add: ability to mask your account when creating a question

This commit is contained in:
trisua 2025-07-01 14:50:19 -04:00
parent 973373426a
commit 0634819278
11 changed files with 125 additions and 79 deletions

View file

@ -43,6 +43,7 @@ version = "1.0.0"
"general:label.could_not_find_post" = "Could not find original post..." "general:label.could_not_find_post" = "Could not find original post..."
"general:label.timeline_end" = "That's a wrap!" "general:label.timeline_end" = "That's a wrap!"
"general:label.loading" = "Working on it!" "general:label.loading" = "Working on it!"
"general:label.send_anonymously" = "Send anonymously"
"general:label.supporter_motivation" = "Become a supporter!" "general:label.supporter_motivation" = "Become a supporter!"
"general:action.become_supporter" = "Become supporter" "general:action.become_supporter" = "Become supporter"

View file

@ -627,7 +627,7 @@
(text "{%- endif %} {%- endmacro %} {% macro question(question, owner, show_community=true, secondary=false, profile=false) -%}") (text "{%- endif %} {%- endmacro %} {% macro question(question, owner, show_community=true, secondary=false, profile=false) -%}")
(div (div
("class" "card question {% if secondary -%}secondary{%- endif %} flex gap-2") ("class" "card question {% if secondary -%}secondary{%- endif %} flex gap-2")
(text "{% if owner.id == 0 -%}") (text "{% if owner.id == 0 or question.context.mask_owner -%}")
(span (span
(text "{% if profile and profile.settings.anonymous_avatar_url -%}") (text "{% if profile and profile.settings.anonymous_avatar_url -%}")
(img (img
@ -636,7 +636,7 @@
("class" "avatar shadow") ("class" "avatar shadow")
("loading" "lazy") ("loading" "lazy")
("style" "--size: 52px")) ("style" "--size: 52px"))
(text "{% else %} {{ self::avatar(username=owner.username, selector_type=\"username\", size=\"52px\") }} {%- endif %}")) (text "{% else %} {{ self::avatar(username=\"anonymous\", selector_type=\"username\", size=\"52px\") }} {%- endif %}"))
(text "{% else %}") (text "{% else %}")
(a (a
("href" "/@{{ owner.username }}") ("href" "/@{{ owner.username }}")
@ -648,7 +648,7 @@
("class" "flex items-center gap-2 flex-wrap") ("class" "flex items-center gap-2 flex-wrap")
(span (span
("class" "name") ("class" "name")
(text "{% if owner.id == 0 -%} {% if profile and profile.settings.anonymous_username -%}") (text "{% if owner.id == 0 or question.context.mask_owner -%} {% if profile and profile.settings.anonymous_username -%}")
(span (span
("class" "flex items-center gap-2") ("class" "flex items-center gap-2")
(b (b
@ -696,7 +696,7 @@
(text "{{ self::post_media(upload_ids=question.drawings) }}") (text "{{ self::post_media(upload_ids=question.drawings) }}")
; anonymous user ip thing ; anonymous user ip thing
; this is only shown if the post author is anonymous AND we are a helper ; this is only shown if the post author is anonymous AND we are a helper
(text "{% if is_helper and owner.id == 0 %}") (text "{% if is_helper and (owner.id == 0 or question.context.mask_owner) -%}")
(details (details
("class" "card tiny lowered w-full") ("class" "card tiny lowered w-full")
(summary (summary
@ -705,12 +705,22 @@
(span (text "View IP"))) (span (text "View IP")))
(pre (code (text "{{ question.ip }}")))) (pre (code (text "{{ question.ip }}"))))
(text "{% endif %}")
(text "{% if question.context.mask_owner -%}")
(details
("class" "card tiny lowered w-full")
(summary
("class" "w-full flex gap-2 flex-wrap items-center")
(icon (text "venetian-mask"))
(span (text "Unmask")))
(text "{{ self::full_username(user=owner) }}"))
(text "{%- endif %} {%- endif %}")
; ... ; ...
(div (div
("class" "flex gap-2 items-center justify-between")))) ("class" "flex gap-2 items-center justify-between"))))
(text "{%- endmacro %} {% macro create_question_form(receiver=\"0\", community=\"\", header=\"\", is_global=false, drawing_enabled=false) -%}") (text "{%- endmacro %} {% macro create_question_form(receiver=\"0\", community=\"\", header=\"\", is_global=false, drawing_enabled=false, allow_anonymous=false) -%}")
(div (div
("class" "card-nest") ("class" "card-nest")
(div (div
@ -742,50 +752,66 @@
("minlength" "2") ("minlength" "2")
("maxlength" "4096"))) ("maxlength" "4096")))
(div (div
("class" "flex gap-2") ("class" "flex w-full justify-between gap-2 flex-collapse")
(button (div
("class" "primary") ("class" "flex gap-2")
(text "{{ text \"communities:action.create\" }}")) (button
("class" "primary")
(text "{{ text \"communities:action.create\" }}"))
(text "{% if drawing_enabled -%}") (text "{% if drawing_enabled -%}")
(button (button
("class" "lowered") ("class" "lowered")
("ui_ident" "add_drawing") ("ui_ident" "add_drawing")
("onclick" "attach_drawing()") ("onclick" "attach_drawing()")
("type" "button") ("type" "button")
(text "{{ text \"communities:action.draw\" }}")) (text "{{ text \"communities:action.draw\" }}"))
(button (button
("class" "lowered red hidden") ("class" "lowered red hidden")
("ui_ident" "remove_drawing") ("ui_ident" "remove_drawing")
("onclick" "remove_drawing()") ("onclick" "remove_drawing()")
("type" "button") ("type" "button")
(text "{{ text \"communities:action.remove_drawing\" }}")) (text "{{ text \"communities:action.remove_drawing\" }}"))
(script (script
(text "globalThis.attach_drawing = async () => { (text "globalThis.attach_drawing = async () => {
globalThis.gerald = await trigger(\"carp::new\", [document.querySelector(\"[ui_ident=carp_canvas_field]\")]); globalThis.gerald = await trigger(\"carp::new\", [document.querySelector(\"[ui_ident=carp_canvas_field]\")]);
globalThis.gerald.create_canvas(); globalThis.gerald.create_canvas();
document.querySelector(\"[ui_ident=add_drawing]\").classList.add(\"hidden\"); document.querySelector(\"[ui_ident=add_drawing]\").classList.add(\"hidden\");
document.querySelector(\"[ui_ident=remove_drawing]\").classList.remove(\"hidden\"); document.querySelector(\"[ui_ident=remove_drawing]\").classList.remove(\"hidden\");
}
globalThis.remove_drawing = async () => {
if (
!(await trigger(\"atto::confirm\", [
\"Are you sure you would like to do this?\",
]))
) {
return;
} }
document.querySelector(\"[ui_ident=carp_canvas_field]\").innerHTML = \"\"; globalThis.remove_drawing = async () => {
globalThis.gerald = null; if (
!(await trigger(\"atto::confirm\", [
\"Are you sure you would like to do this?\",
]))
) {
return;
}
document.querySelector(\"[ui_ident=add_drawing]\").classList.remove(\"hidden\"); document.querySelector(\"[ui_ident=carp_canvas_field]\").innerHTML = \"\";
document.querySelector(\"[ui_ident=remove_drawing]\").classList.add(\"hidden\"); globalThis.gerald = null;
}"))
document.querySelector(\"[ui_ident=add_drawing]\").classList.remove(\"hidden\");
document.querySelector(\"[ui_ident=remove_drawing]\").classList.add(\"hidden\");
}"))
(text "{%- endif %}"))
(text "{% if not is_global and allow_anonymous -%}")
(div
("class" "flex gap-2 items-center")
(input
("type" "checkbox")
("name" "mask_owner")
("id" "mask_owner")
("class" "w-content"))
(label
("for" "mask_owner")
(b (str (text "general:label.send_anonymously")))))
(text "{%- endif %}")))) (text "{%- endif %}"))))
(script (script
@ -811,6 +837,7 @@
receiver: \"{{ receiver }}\", receiver: \"{{ receiver }}\",
community: \"{{ community }}\", community: \"{{ community }}\",
is_global: \"{{ is_global }}\" == \"true\", is_global: \"{{ is_global }}\" == \"true\",
mask_owner: (e.target.mask_owner || { checked:false }).checked
}), }),
); );
@ -1136,12 +1163,12 @@
(str (text "general:link.reference"))) (str (text "general:link.reference")))
(button (button
("onclick" "trigger('me::achievement', ['OpenTos']); Turbo.visit('{{ config.policies.terms_of_service }}')") ("onclick" "trigger('me::achievement_link', ['OpenTos', '{{ config.policies.terms_of_service }}'])")
(icon (text "heart-handshake")) (icon (text "heart-handshake"))
(text "Terms of service")) (text "Terms of service"))
(button (button
("onclick" "trigger('me::achievement', ['OpenPrivacyPolicy']); Turbo.visit('{{ config.policies.privacy }}')") ("onclick" "trigger('me::achievement_link', ['OpenPrivacyPolicy', '{{ config.policies.privacy }}'])")
(icon (text "cookie")) (icon (text "cookie"))
(text "Privacy policy")) (text "Privacy policy"))
(b ("class" "title") (str (text "general:label.account"))) (b ("class" "title") (str (text "general:label.account")))

View file

@ -1,7 +1,7 @@
(text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}") (text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}")
(div (div
("style" "display: contents") ("style" "display: contents")
(text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings) }}")) (text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings, allow_anonymous=profile.settings.allow_anonymous_questions) }}"))
(text "{%- endif %} {{ macros::profile_nav(selected=\"media\") }}") (text "{%- endif %} {{ macros::profile_nav(selected=\"media\") }}")
(div (div

View file

@ -1,7 +1,7 @@
(text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}") (text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}")
(div (div
("style" "display: contents") ("style" "display: contents")
(text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings) }}")) (text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings, allow_anonymous=profile.settings.allow_anonymous_questions) }}"))
(text "{%- endif %} {{ macros::profile_nav(selected=\"outbox\") }}") (text "{%- endif %} {{ macros::profile_nav(selected=\"outbox\") }}")
(div (div

View file

@ -1,7 +1,7 @@
(text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}") (text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}")
(div (div
("style" "display: contents") ("style" "display: contents")
(text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings) }}")) (text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings, allow_anonymous=profile.settings.allow_anonymous_questions) }}"))
(text "{%- endif %} {% if not tag and pinned|length != 0 -%}") (text "{%- endif %} {% if not tag and pinned|length != 0 -%}")
(div (div

View file

@ -1,7 +1,7 @@
(text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}") (text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}")
(div (div
("style" "display: contents") ("style" "display: contents")
(text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings) }}")) (text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings, allow_anonymous=profile.settings.allow_anonymous_questions) }}"))
(text "{%- endif %} {{ macros::profile_nav(selected=\"replies\") }}") (text "{%- endif %} {{ macros::profile_nav(selected=\"replies\") }}")
(div (div

View file

@ -917,18 +917,18 @@ media_theme_pref();
if (option.input_element_type === "checkbox") { if (option.input_element_type === "checkbox") {
into_element.innerHTML += `<div class="card flex items-center gap-2"> into_element.innerHTML += `<div class="card flex items-center gap-2">
<input <input
type="checkbox" type="checkbox"
onchange="window.set_setting_field${id_key}('${option.key}', event.target.checked)" onchange="window.set_setting_field${id_key}('${option.key}', event.target.checked)"
placeholder="${option.key}" placeholder="${option.key}"
name="${option.key}" name="${option.key}"
id="${option.key}" id="${option.key}"
${option.value === "true" ? "checked" : ""} ${option.value === "true" ? "checked" : ""}
class="w-content" class="w-content"
/> />
<label for="${option.key}"><b>${option.label.replaceAll("_", " ")}</b></label> <label for="${option.key}"><b>${option.label.replaceAll("_", " ")}</b></label>
</div>`; </div>`;
return; return;
} }

View file

@ -342,25 +342,34 @@
}, },
); );
self.define("achievement", async (_, name) => { self.define("achievement", (_, name) => {
fetch("/api/v1/auth/user/me/achievement", { return new Promise((resolve) => {
method: "POST", fetch("/api/v1/auth/user/me/achievement", {
headers: { method: "POST",
"Content-Type": "application/json", headers: {
}, "Content-Type": "application/json",
body: JSON.stringify({ },
name, body: JSON.stringify({
}), name,
}) }),
.then((res) => res.json()) })
.then((res) => { .then((res) => res.json())
if (!res.ok) { .then((res) => {
trigger("atto::toast", [ if (!res.ok) {
res.ok ? "success" : "error", trigger("atto::toast", [
res.message, res.ok ? "success" : "error",
]); res.message,
} ]);
}); }
resolve();
});
});
});
self.define("achievement_link", async (_, name, href) => {
await self.achievement(name);
Turbo.visit(href);
}); });
self.define("report", (_, asset, asset_type) => { self.define("report", (_, asset, asset_type) => {

View file

@ -92,6 +92,10 @@ pub async fn create_request(
} }
} }
if req.mask_owner && !req.is_global {
props.context.mask_owner = true;
}
match data match data
.create_question(props, drawings.iter().map(|x| x.to_vec()).collect()) .create_question(props, drawings.iter().map(|x| x.to_vec()).collect())
.await .await

View file

@ -790,6 +790,8 @@ pub struct CreateQuestion {
pub receiver: String, pub receiver: String,
#[serde(default)] #[serde(default)]
pub community: String, pub community: String,
#[serde(default)]
pub mask_owner: bool,
} }
#[derive(Deserialize)] #[derive(Deserialize)]

View file

@ -381,6 +381,9 @@ impl Question {
pub struct QuestionContext { pub struct QuestionContext {
#[serde(default)] #[serde(default)]
pub is_nsfw: bool, pub is_nsfw: bool,
/// If the owner is shown as anonymous in the UI.
#[serde(default)]
pub mask_owner: bool,
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]