Files
retoor 3c4334cec9 feat: implement MoloApp plans 01-15 with integration
Full C++23 framework tree: runtime, observability, security,
data, app, realtime, supervisor, clients, CLI, example plus
enterprise tenancy, audit, operability, governance,
supplychain. Postgres via docker compose for tests.
2026-10-23 18:20:04 +02:00

132 lines
4.8 KiB
C++

#include "App.hpp"
#include "../fw/Negotiate.hpp"
#include "../fw/Router.hpp"
#include "../fw/StaticFiles.hpp"
#include "../fw/Templates.hpp"
#include "../fw/Validate.hpp"
namespace molo::example::app {
namespace {
fw::Model contact_model() {
return fw::Model(
{{"name", fw::FieldType::String, true, 1, 80, 0, 0, false, ""},
{"email", fw::FieldType::Email, true, 3, 120, 0, 0, false, ""},
{"message", fw::FieldType::String, true, 1, 2000, 0, 0, false, ""}});
}
fw::Model user_model() {
fw::Field age{"age", fw::FieldType::Integer, true, 0, 0, 0, 150, true, ""};
return fw::Model(
{{"username", fw::FieldType::String, true, 3, 40, 0, 0, false, ""},
{"email", fw::FieldType::Email, true, 3, 120, 0, 0, false, ""},
age});
}
} // namespace
void register_formats_demo(fw::Router& router, Services& services) {
fw::Environment* env = services.templates.get();
std::map<std::string, std::string> embedded = services.embedded;
std::string static_root = services.static_root;
router.get("/templates/page", "template-page", [env](fw::Request req) {
(void)req;
fw::TemplateCtx ctx;
ctx["title"] = std::string("Templates");
ctx["heading"] = std::string("Template demo");
ctx["author"] = std::string("ada");
ctx["snippet"] = std::string("<b>bold</b>");
fw::TemplateList items;
items.push_back({{"name", "extends"}, {"kind", "inheritance"}});
items.push_back({{"name", "include"}, {"kind", "partial"}});
items.push_back({{"name", "for"}, {"kind", "loop"}});
ctx["items"] = items;
return fw::Response(200, env->render("page.html", ctx),
"text/html; charset=utf-8");
});
router.get("/formats/data", "formats", [](fw::Request req) {
std::vector<std::string> offers = {"application/json", "application/xml",
"text/html", "text/plain"};
std::string pick =
fw::negotiate(req.headers.get("Accept"), offers);
if (pick == "application/json")
return fw::Response(
200, "{\"format\":\"json\",\"value\":42}", "application/json");
if (pick == "application/xml")
return fw::Response(200, "<data><value>42</value></data>",
"application/xml");
if (pick == "text/html")
return fw::Response(200, "<p>value: 42</p>",
"text/html; charset=utf-8");
return fw::Response(200, "value: 42", "text/plain; charset=utf-8");
});
router.get("/forms/contact", "contact-get", [env](fw::Request req) {
(void)req;
fw::TemplateCtx ctx;
ctx["title"] = std::string("Contact");
ctx["posted"] = std::string("");
ctx["name"] = std::string("");
ctx["email"] = std::string("");
ctx["message"] = std::string("");
return fw::Response(200, env->render("contact.html", ctx),
"text/html; charset=utf-8");
});
router.post("/forms/contact", "contact-post", [env](fw::Request req) {
fw::Form form(contact_model());
fw::TemplateCtx ctx;
ctx["title"] = std::string("Contact");
try {
auto clean = form.bind(req);
ctx["posted"] = std::string("true");
ctx["name"] = clean["name"];
ctx["email"] = clean["email"];
ctx["message"] = clean["message"];
} catch (const fw::ValidationError& e) {
ctx["posted"] = std::string("");
auto input = fw::parse_form(req.body);
ctx["name"] = input.count("name") ? input["name"] : "";
ctx["email"] = input.count("email") ? input["email"] : "";
ctx["message"] = input.count("message") ? input["message"] : "";
ctx["error"] = e.to_json();
return fw::Response(422, env->render("contact.html", ctx),
"text/html; charset=utf-8");
}
return fw::Response(200, env->render("contact.html", ctx),
"text/html; charset=utf-8");
});
router.post("/validate/user", "validate-user", [](fw::Request req) {
fw::Model model = user_model();
auto input = fw::parse_json_object_flat(req.body);
if (input.empty()) input = fw::parse_form(req.body);
try {
auto clean = model.validate(input);
return fw::JsonResponse(
"{\"ok\":true,\"username\":\"" +
fw::json_escape(clean["username"]) + "\"}",
200);
} catch (const fw::ValidationError& e) {
return fw::JsonResponse(e.to_json(), 422);
}
});
router.get("/static/{name}", "static", [static_root](fw::Request req) {
return fw::serve_disk_file(static_root, req.param_or("name", ""));
});
router.get("/embedded/{name}", "embedded", [embedded](fw::Request req) {
return fw::serve_embedded(embedded, req.param_or("name", ""));
});
router.get("/redirect/here", "redirect", [](fw::Request req) {
bool permanent = req.query_or("mode", "temp") == "perm";
return fw::Response(fw::RedirectResponse("/health", permanent));
});
}
} // namespace molo::example::app