(text "{% extends \"auth/base.html\" %} {% block head %}") (title (text "Register")) (text "{% endblock %} {% block title %}Register{% endblock %} {% block content %}") (script ("src" "https://challenges.cloudflare.com/turnstile/v0/api.js") ("defer" "")) (form ("class" "w-full flex flex-col gap-4") ("onsubmit" "register(event)") (div ("class" "flex flex-col gap-1") (label ("for" "username") (b (text "Username"))) (input ("type" "text") ("placeholder" "username") ("required" "") ("name" "username") ("id" "username"))) (div ("class" "flex flex-col gap-1") (label ("for" "password") (b (text "Password"))) (input ("type" "password") ("placeholder" "password") ("required" "") ("name" "password") ("id" "password"))) (text "{% if config.security.enable_invite_codes -%}") (div ("class" "flex flex-col gap-1") (label ("for" "invite_code") (b (text "Invite code"))) (input ("type" "text") ("placeholder" "invite code") ("required" "") ("name" "invite_code") ("id" "invite_code"))) (text "{%- endif %}") (hr) (div ("class" "card-nest w-full") (div ("class" "card small flex items-center gap-2") (text "{{ icon \"scroll-text\" }}") (b (text "Policies"))) (div ("class" "card secondary flex flex-col gap-2") (span (text "By continuing, you agree to the following policies:")) (ul (li (a ("href" "{{ config.policies.terms_of_service }}") (text "Terms of service"))) (li (a ("href" "{{ config.policies.privacy }}") (text "Privacy policy")))) (div ("class" "flex items-center gap-2") (input ("type" "checkbox") ("name" "policy_consent") ("id" "policy_consent") ("class" "w-content") ("required" "")) (label ("for" "policy_consent") (text "I agree"))))) (div ("class" "cf-turnstile") ("data-sitekey" "{{ config.turnstile.site_key }}")) (hr) (button (text "Submit"))) (script (text "async function register(e) { e.preventDefault(); await trigger(\"atto::debounce\", [\"users::create\"]); fetch(\"/api/v1/auth/register\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", }, body: JSON.stringify({ username: e.target.username.value, password: e.target.password.value, policy_consent: e.target.policy_consent.checked, captcha_response: e.target.querySelector( \"[name=cf-turnstile-response]\", ).value, invite_code: (e.target.invite_code || { value: \"\" }).value, }), }) .then((res) => res.json()) .then((res) => { trigger(\"atto::toast\", [ res.ok ? \"success\" : \"error\", res.message, ]); if (res.ok) { // update tokens const new_tokens = ns(\"me\").LOGIN_ACCOUNT_TOKENS; new_tokens[e.target.username.value] = res.message; trigger(\"me::set_login_account_tokens\", [new_tokens]); // redirect setTimeout(() => { window.location.href = \"/\"; }, 150); } }); }")) (text "{% endblock %} {% block footer %}") (span ("class" "small w-full text-center") (text "Or, ") (a ("href" "/auth/login") (text "login"))) (text "{% endblock %}")