From 6360b41e9aea9a65ea6b48ea47697264401e21a0 Mon Sep 17 00:00:00 2001 From: Alfie King Date: Thu, 21 Aug 2025 23:23:14 +0100 Subject: [PATCH] fkin finally --- include/errors.hpp | 15 ++++ include/templating.hpp | 11 ++- src/errors.cpp | 13 +++ src/main.cpp | 3 +- src/templating.cpp | 68 ++++++++++++++- static/css/404.css | 155 --------------------------------- static/css/cap.css | 20 ----- templates/bases/base.html | 1 - templates/bases/directory.html | 2 +- templates/errors/404.html | 78 ++--------------- 10 files changed, 112 insertions(+), 254 deletions(-) create mode 100644 include/errors.hpp create mode 100644 src/errors.cpp delete mode 100644 static/css/404.css delete mode 100644 static/css/cap.css diff --git a/include/errors.hpp b/include/errors.hpp new file mode 100644 index 0000000..2111619 --- /dev/null +++ b/include/errors.hpp @@ -0,0 +1,15 @@ +#ifndef ERRORS_HPP +#define ERRORS_HPP + +#include +#include "templating.hpp" + +extern Templating templating; + +struct CustomErrorHandler { + struct context {}; + void before_handle(crow::request& req, crow::response& res, context&) {} + void after_handle(crow::request& req, crow::response& res, context&); +}; + +#endif \ No newline at end of file diff --git a/include/templating.hpp b/include/templating.hpp index 344a620..fabbe12 100644 --- a/include/templating.hpp +++ b/include/templating.hpp @@ -7,12 +7,19 @@ class Templating { public: - Templating(const std::string& template_dir) : inja_env{template_dir} {} + explicit Templating(const std::string& template_dir); + crow::response render_template(const std::string& template_name, const inja::json& data); crow::response render_template(const std::string& template_name); + std::string render_template_string(const std::string& template_name, const inja::json& data); + std::string render_template_string(const std::string& template_name); + private: inja::Environment inja_env; + std::string template_dir; // absolute path to templates + + std::string preprocess_template(const std::string& template_name); }; -#endif \ No newline at end of file +#endif diff --git a/src/errors.cpp b/src/errors.cpp new file mode 100644 index 0000000..70baa62 --- /dev/null +++ b/src/errors.cpp @@ -0,0 +1,13 @@ +#include "errors.hpp" + + +std::string render_404_template(const crow::request& req) { + return templating.render_template_string("errors/404.html", {{"requested_url", req.url}}); +} + +void CustomErrorHandler::after_handle(crow::request& req, crow::response& res, context&) { + if (res.code == 404 && res.body.empty()) { + res.set_header("Content-Type", "text/html"); + res.body = render_404_template(req); + } +} diff --git a/src/main.cpp b/src/main.cpp index 247400f..12b7277 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #define CROW_STATIC_DIRECTORY "../static" #include "templating.hpp" +#include "errors.hpp" #include @@ -7,7 +8,7 @@ Templating templating{"../templates"}; int main() { - crow::SimpleApp app; + crow::App app; CROW_ROUTE(app, "/")([]() { return templating.render_template("index.html"); diff --git a/src/templating.cpp b/src/templating.cpp index 80c2011..0eb8bf6 100644 --- a/src/templating.cpp +++ b/src/templating.cpp @@ -1,16 +1,76 @@ #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 { - inja::Template template_obj = inja_env.parse_template(template_name); - std::string rendered = inja_env.render(template_obj, data); + 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 inja::RenderError& e) { + } 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{}); -} \ No newline at end of file +} + +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{}); +} diff --git a/static/css/404.css b/static/css/404.css deleted file mode 100644 index 0816d0a..0000000 --- a/static/css/404.css +++ /dev/null @@ -1,155 +0,0 @@ -#snakeContainer { - padding: 15px; -} - -canvas#snakeCanvas { - box-sizing: border-box; - border: 2px solid var(--secondary-background-color); - border-radius: 10px; - width: 100%; -} - -form { - display: flex; - flex-direction: column; - width: min-content; - gap: 1rem; - padding: 15px; -} - -form input[type="text"] { - padding: 10px; - box-sizing: border-box; - border: 1px solid var(--secondary-background-color); - border-radius: 6px; - background-color: var(--secondary-background-color-but-slightly-transparent); - color: var(--text-color); -} - -form button[type="submit"] { - padding: 10px; - box-sizing: border-box; - border: 1px solid var(--secondary-background-color); - border-radius: 6px; - background-color: var(--secondary-background-color-but-slightly-transparent); - color: var(--text-color); - font-weight: bold; - cursor: pointer; -} - -.flex-row { - display: flex; - flex-direction: row; - gap: 1rem; -} - -.min-width { - width: min-content; -} - -.max-width { - width: 100%; -} - -#snakeLeaderboardSection { - display: flex; - flex-direction: column; - align-items: center; - padding: 0; - max-height: 272px ; -} - -#snakeLeaderboard { - display: flex; - flex-direction: column; - list-style: none; - padding: 0; - margin: 0; - width: 100%; - overflow-y: scroll; -} - -#snakeLeaderboard li { - padding: 5px 20px; - background-color: var(--secondary-background-color-but-slightly-transparent); - color: var(--text-color); - font-size: 1rem; - display: flex; - justify-content: space-between; - align-items: center; -} - -#snakeLeaderboard li:nth-child(even) { - background-color: var(--secondary-background-color); -} - -dialog { - width: 90%; - max-width: 500px; - padding: 20px; - background-color: var(--background-color); - color: var(--text-color); - border: 2px solid var(--secondary-background-color); - border-radius: 8px; -} - -dialog button { - padding: 10px; - width: 100%; - box-sizing: border-box; - border: 2px solid var(--secondary-background-color); - border-radius: 6px; - background-color: var(--secondary-background-color-but-slightly-transparent); - color: var(--text-color); - font-weight: bold; - cursor: pointer; - margin-top: 10px; -} - -dialog h2 { - margin: 0; - font-size: 1.5rem; -} - -dialog p { - margin: 0; - font-size: 1rem; -} - -@media screen and (max-width: 850px) { - .flex-row { - flex-direction: column; - } - - form { - align-items: center; - width: 100%; - } - - .min-width { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - } -} - -@media screen and (max-width: 650px) { - .mobileOnly { - display: flex; - } - - .pcOnly { - display: none; - } -} - -@media screen and (min-width: 651px) { - .mobileOnly { - display: none !important; - } - - .pcOnly { - display: flex; - } -} \ No newline at end of file diff --git a/static/css/cap.css b/static/css/cap.css deleted file mode 100644 index eb614a2..0000000 --- a/static/css/cap.css +++ /dev/null @@ -1,20 +0,0 @@ -cap-widget { - --cap-background: var(--secondary-background-color-but-slightly-transparent); - --cap-border-color: var(--secondary-background-color); - --cap-border-radius: 14px; - --cap-widget-width: 230px; - --cap-widget-padding: 14px; - --cap-gap: 15px; - --cap-color: var(--text-color); - --cap-checkbox-size: 25px; - --cap-checkbox-border: 1px solid var(--secondary-background-color); - --cap-checkbox-border-radius: 6px; - --cap-checkbox-background: none; - --cap-checkbox-margin: 2px; - --cap-font: "Space Mono", "serif"; - --cap-spinner-color: var(--primary-color); - --cap-spinner-background-color: var(--secondary-background-color-but-slightly-transparent); - --cap-spinner-thickness: 5px; - --cap-credits-font-size: 12px; - --cap-opacity-hover: 0.8; -} \ No newline at end of file diff --git a/templates/bases/base.html b/templates/bases/base.html index 1a00a45..fd17f84 100644 --- a/templates/bases/base.html +++ b/templates/bases/base.html @@ -37,7 +37,6 @@
  • YouTube
  • Tumblr
  • Reddit
  • -
  • 404 >:3
  • diff --git a/templates/bases/directory.html b/templates/bases/directory.html index 714ebec..36391ec 100644 --- a/templates/bases/directory.html +++ b/templates/bases/directory.html @@ -1,4 +1,4 @@ -{% extends "bases/base.html" %} +{% extends "base.html" %} {% block title %}/{{ directory }} - Alfie's basement{% endblock %} {% block description %}server backend survivor{% endblock %} diff --git a/templates/errors/404.html b/templates/errors/404.html index 0413b88..d1938db 100644 --- a/templates/errors/404.html +++ b/templates/errors/404.html @@ -3,80 +3,18 @@ {% block title %}404 - Not Found{% endblock %} {% block description %}The page you are looking for does not exist.{% endblock %} -{% block head %} - - -{% endblock %} - {% block content %}

    404

    - It seems like the thing you are looking for is not here :[ + Hey so you know that thing you were looking for? Yeah, it doesn't exist. :P

    - - while you're here, why not play some snake? - - - You can't play snake on mobile, sorry :( - + So why not try going back to the homepage?

    -
    - -
    -
    -
    -

    Submit score

    -
    - - - - - -
    -
    -
    -

    Leaderboard

    -
      - {% for score in scores %} -
    • - {{ score.position }} - {{ score.name }} - {{ score.score }} -
    • - {% endfor %} -
    -
    -
    -
    -

    Leaderboard

    -
      - {% for score in scores %} -
    • - {{ score.position }} - {{ score.name }} - {{ score.score }} -
    • - {% endfor %} -
    -
    -{% if error %} - -

    Error

    -

    {{ error }}

    - -
    - -{% endif %} -{% endblock %} - -{% block scripts %} - - -{% endblock %} \ No newline at end of file +
    +

    The actual error for the 2 ppl who care

    +

    + 404: {{ requested_url }} not found :3 +

    +
    \ No newline at end of file