#include "templating.hpp" #include #include #include #include Templating::Templating(const std::string& template_dir) : inja_env(std::filesystem::canonical(template_dir).string()), template_dir(std::filesystem::canonical(template_dir).string()) { inja_env.set_search_included_templates_in_files(true); } std::string Templating::preprocess_template(const std::string& template_name) { namespace fs = std::filesystem; fs::path abs_template_dir = fs::path(template_dir); fs::path abs_template_file = fs::canonical(abs_template_dir / template_name); std::ifstream file(abs_template_file); if (!file.is_open()) { throw std::runtime_error("Failed to open template file: " + abs_template_file.string()); } std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); std::regex extends_regex(R"(\{\%\s*extends\s*(['"])(.+?)\1\s*\%\})"); std::smatch match; if (std::regex_search(content, match, extends_regex)) { std::string quote = match[1].str(); std::string original_path = match[2].str(); if (original_path.find("/") == std::string::npos && !original_path.empty() && original_path.front() != '/') { fs::path abs_extended_template = fs::canonical(abs_template_dir / original_path); fs::path rel_path = fs::relative(abs_extended_template, abs_template_file.parent_path()); std::string new_path = rel_path.generic_string(); content = std::regex_replace(content, extends_regex, "{% extends " + quote + new_path + quote + " %}"); } } return content; } crow::response Templating::render_template(const std::string& template_name, const inja::json& data) { try { std::string preprocessed = preprocess_template(template_name); inja::Template tpl = inja_env.parse(preprocessed); std::string rendered = inja_env.render(tpl, data); return crow::response(rendered); } catch (const std::exception& e) { return crow::response(500, e.what()); } } crow::response Templating::render_template(const std::string& template_name) { return render_template(template_name, inja::json{}); } std::string Templating::render_template_string(const std::string& template_name, const inja::json& data) { std::string preprocessed = preprocess_template(template_name); inja::Template tpl = inja_env.parse(preprocessed); return inja_env.render(tpl, data); } std::string Templating::render_template_string(const std::string& template_name) { return render_template_string(template_name, inja::json{}); }