decided in favor of dedicated COMPONENT() macro, updates to documentation

This commit is contained in:
udo
2026-04-19 11:34:03 +00:00
parent be514d63d6
commit 2b5586d7df
56 changed files with 926 additions and 401 deletions
+12 -250
View File
@@ -1,49 +1,4 @@
String starter_dirname(String path)
{
if(path == "")
return("");
auto parts = split(path, "/");
if(parts.size() <= 1)
return("");
parts.pop_back();
String result = join(parts, "/");
if(result == "")
return("/");
return(result);
}
String starter_fs_join(String root, String relative)
{
if(relative == "")
return(root);
if(relative[0] == '/')
return(relative);
if(root == "" || root == "/")
return(root + relative);
if(root[root.length() - 1] == '/')
return(root + relative);
return(root + "/" + relative);
}
String starter_safe_name(String raw)
{
String result = "";
for(auto c : raw)
{
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
result.append(1, c);
else
result.append(1, '_');
}
return(result);
}
String starter_json_string(String raw)
{
DTree value;
value = raw;
return(json_encode(value));
}
#load "user.class.h"
String starter_fs_root(Request& context)
{
@@ -66,7 +21,7 @@ String starter_base_url(Request& context)
String base = context.var["starter"]["base_url"].to_string();
if(base == "")
{
base = starter_dirname(starter_script_url(context));
base = dirname(starter_script_url(context));
if(base == "")
base = "/";
if(base[base.length() - 1] != '/')
@@ -77,34 +32,12 @@ String starter_base_url(Request& context)
String starter_fs_path(String relative, Request& context)
{
return(starter_fs_join(starter_fs_root(context), relative));
}
DTree starter_cfg(String path, Request& context)
{
DTree result = context.var["starter"]["config"];
for(auto segment : split(path, "/"))
{
if(segment == "")
continue;
result = result[segment];
}
return(result);
}
String starter_cfg_string(String path, Request& context)
{
return(starter_cfg(path, context).to_string());
return(path_join(starter_fs_root(context), relative));
}
String starter_link(String path, Request& context);
String starter_link(String path, StringMap params, Request& context);
String starter_theme_value(String key, Request& context)
{
return(starter_cfg("theme/" + key, context).to_string());
}
String starter_first_route_segment(Request& context)
{
String query = context.params["QUERY_STRING"];
@@ -251,12 +184,6 @@ DTree starter_default_config()
return(config);
}
void starter_set_status(Request& context, s32 code, String reason)
{
context.response_code = "HTTP/1.1 " + std::to_string(code) + " " + reason;
context.flags.status = code;
}
void starter_register_css(String path, Request& context)
{
context.var["starter"]["assets"]["css"][path] = path;
@@ -321,182 +248,15 @@ String starter_link(String path, StringMap params, Request& context)
return(url);
}
String starter_filebase_root(Request& context)
{
String root = starter_cfg_string("filebase/path", context);
if(root == "")
root = "/tmp/uce-starter-data";
return(root);
}
String starter_hash_id(String raw)
{
raw = to_lower(trim(raw));
return(gen_sha1("uce-starter:" + raw).substr(0, 12));
}
String starter_user_dir(String email, Request& context)
{
String bucket = starter_hash_id(email);
return(starter_filebase_root(context) + "/users/" + bucket.substr(0, 2) + "/" + bucket);
}
String starter_user_file(String email, Request& context)
{
return(starter_user_dir(email, context) + "/account.json");
}
String starter_password_hash(String password, String salt)
{
String hash = "uce-starter:" + password + ":" + salt;
for(s32 i = 0; i < 2048; i++)
hash = gen_sha1(hash + ":" + std::to_string(i));
return(hash);
}
DTree starter_read_json_file(String file_name)
{
DTree result;
if(!file_exists(file_name))
return(result);
String raw = trim(file_get_contents(file_name));
if(raw == "")
return(result);
return(json_decode(raw));
}
bool starter_write_json_file(String file_name, DTree data)
{
mkdir(starter_dirname(file_name));
return(file_put_contents(file_name, json_encode(data)));
}
DTree starter_user_load(String email, Request& context)
{
DTree user = starter_read_json_file(starter_user_file(email, context));
if(user.get_type_name() != "array")
return(DTree());
user["id"] = to_lower(trim(email));
return(user);
}
DTree starter_user_create(String email, String password, Request& context)
{
DTree result;
email = to_lower(trim(email));
password = trim(password);
result["message"] = "";
result["result"].set_bool(false);
if(email == "" || password == "")
{
result["message"] = "email_and_password_required";
return(result);
}
if(email.find("@") == String::npos)
{
result["message"] = "invalid_email";
return(result);
}
DTree existing = starter_user_load(email, context);
if(existing.get_type_name() == "array" && existing["email"].to_string() != "")
{
result["message"] = "user_exists";
return(result);
}
String salt = gen_sha1(std::to_string((u64)time()) + ":" + std::to_string((u64)(microtime() * 1000000.0)) + ":" + make_session_id()).substr(0, 24);
DTree user;
user["email"] = email;
user["salt"] = salt;
user["password_hash"] = starter_password_hash(password, salt);
user["created"] = std::to_string((u64)time());
DTree role;
role = "user";
user["roles"].push(role);
starter_write_json_file(starter_user_file(email, context), user);
user["id"] = email;
result["result"].set_bool(true);
result["id"] = email;
result["profile"] = user;
return(result);
}
DTree starter_user_sign_in(String email, String password, Request& context)
{
DTree result;
result["result"].set_bool(false);
email = to_lower(trim(email));
password = trim(password);
DTree user = starter_user_load(email, context);
if(user.get_type_name() != "array" || user["email"].to_string() == "")
{
result["message"] = "no_such_user";
return(result);
}
if(user["password_hash"].to_string() == "")
{
result["message"] = "no_password_set";
return(result);
}
String expected = starter_password_hash(password, user["salt"].to_string());
if(expected != user["password_hash"].to_string())
{
result["message"] = "invalid_password";
return(result);
}
session_start();
context.session["starter_user_id"] = email;
context.var["starter"]["current_user"] = user;
result["result"].set_bool(true);
result["profile"] = user;
return(result);
}
bool starter_is_signed_in(Request& context)
{
if(context.var["starter"]["current_user"]["email"].to_string() != "")
return(true);
String user_id = context.session["starter_user_id"];
if(user_id == "")
return(false);
DTree user = starter_user_load(user_id, context);
if(user["email"].to_string() == "")
{
context.session.erase("starter_user_id");
return(false);
}
context.var["starter"]["current_user"] = user;
return(true);
}
DTree starter_current_user(Request& context)
{
if(starter_is_signed_in(context))
return(context.var["starter"]["current_user"]);
return(DTree());
}
void starter_user_logout(Request& context)
{
context.session.erase("starter_user_id");
context.var["starter"]["current_user"].clear();
}
void starter_redirect(String path, Request& context)
{
starter_set_status(context, 302, "Found");
context.set_status(302, "Found");
context.header["Location"] = starter_link(path, context);
}
void starter_not_found(String message, Request& context)
{
starter_set_status(context, 404, "Not Found");
context.set_status(404, "Not Found");
context.var["starter"]["error"] = message;
context.var["starter"]["page_title"] = "404 Not Found";
}
@@ -511,7 +271,7 @@ String starter_menu_href(String menu_key, DTree menu_item, Request& context)
String starter_html_class(Request& context)
{
String classes = "no-js";
if(starter_theme_value("mode", context) == "dark")
if(context.cfg.get_by_path("theme/mode").to_string() == "dark")
classes += " dark-theme";
return(classes);
}
@@ -525,7 +285,7 @@ void starter_boot(Request& context)
context.var["starter"]["fs_root"] = get_cwd();
context.var["starter"]["script_url"] = first(context.params["DOCUMENT_URI"], context.params["SCRIPT_NAME"]);
String base_url = starter_dirname(context.var["starter"]["script_url"].to_string());
String base_url = dirname(context.var["starter"]["script_url"].to_string());
if(base_url == "")
base_url = "/";
if(base_url[base_url.length() - 1] != '/')
@@ -541,7 +301,9 @@ void starter_boot(Request& context)
config["theme"][key] = item;
});
config["theme"]["key"] = requested_theme;
context.var["starter"]["config"] = config;
context.cfg = config;
context.var["cfg"].set_reference(&context.cfg);
context.var["starter"]["config"].set_reference(&context.cfg);
context.var["starter"]["route"] = starter_make_route(context);
context.var["starter"]["page_type"] = "html";
context.var["starter"]["page_title"] = first(config["menu"][context.var["starter"]["route"]["l_path"].to_string()]["title"].to_string(), config["site"]["default_page_title"].to_string(), "Home");
@@ -554,9 +316,9 @@ void starter_boot(Request& context)
}
session_start();
starter_is_signed_in(context);
StarterUser(context).is_signed_in();
starter_register_css(starter_theme_value("path", context) + "css/style.css", context);
starter_register_css(context.cfg.get_by_path("theme/path").to_string() + "css/style.css", context);
starter_register_css("themes/common/fontawesome/css/all.min.css", context);
starter_register_js("js/u-query.js", context);
starter_register_js("js/morphdom.js", context);