[add] Passwort-Änderungs-Funktionalität

This commit is contained in:
roydfalk 2024-05-20 14:07:43 +02:00
parent f1f92d4256
commit 550f3989d3
10 changed files with 312 additions and 4 deletions

View file

@ -48,6 +48,26 @@
"page.register.flaw.password_lacks_number": "das Passwort muss ein Zahl beinhalten", "page.register.flaw.password_lacks_number": "das Passwort muss ein Zahl beinhalten",
"page.register.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten", "page.register.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten",
"page.register.flaw.unhandled_error": "da ist etwas schief gelaufen :/", "page.register.flaw.unhandled_error": "da ist etwas schief gelaufen :/",
"page.register.success": "Danke!" "page.register.success": "Danke!",
"page.password_change_init.title": "Passwort ändern",
"page.password_change_init.info": "Falls dein Mitglieds-Konto zugeordnet werden kann, wird eine E-Mail mit weiteren Anweisungen an deine private Adresse geschickt.",
"page.password_change_init.identifier": "Anmelde-Name oder private E-Mail-Adresse",
"page.password_change_init.submit": "Auslösen",
"page.password_change_init.status.wait": "einen Augenblick …",
"page.password_change_init.status.success": "Erledigt. Schau mal in dein E-Mail-Postfach!",
"page.password_change_init.status.fail": "da ist etwas schief gelaufen :/",
"page.password_change_exec.title": "Passwort ändern",
"page.password_change_exec.form.field.password_value.label": "Passwort",
"page.password_change_exec.form.field.password_confirmation.label": "Passwort wiederholen",
"page.password_change_exec.form.submit": "Ändern",
"page.password_change_exec.flaw.token_invalid": "Erlaubnis verfallen",
"page.password_change_exec.flaw.password_mismatch": "die Passwörter stimmen nicht überein",
"page.password_change_exec.flaw.password_too_short": "das Passwort muss mindestens {{minimum_length}} Zeichen haben",
"page.password_change_exec.flaw.password_too_long": "das Passwort darf höchstens {{maximum_length}} Zeichen haben",
"page.password_change_exec.flaw.password_lacks_letter": "das Passwort muss einen Buchstaben beinhalten",
"page.password_change_exec.flaw.password_lacks_number": "das Passwort muss ein Zahl beinhalten",
"page.password_change_exec.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten",
"page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/",
"page.password_change_exec.status.success": "erledigt"
} }
} }

View file

@ -48,6 +48,26 @@
"page.register.flaw.password_lacks_number": "the password must contain a number", "page.register.flaw.password_lacks_number": "the password must contain a number",
"page.register.flaw.password_lacks_special_character": "the password must contain a special character", "page.register.flaw.password_lacks_special_character": "the password must contain a special character",
"page.register.flaw.unhandled_error": "something went wrong :/", "page.register.flaw.unhandled_error": "something went wrong :/",
"page.register.success": "Thanks!" "page.register.success": "Thanks!",
"page.password_change_init.title": "Change Password",
"page.password_change_init.info": "In case your member account can be found, an e-mail with further instructions will be sent to your private e-mail address.",
"page.password_change_init.identifier": "Login name or private e-mail address",
"page.password_change_init.submit": "Procede",
"page.password_change_init.status.wait": "just a second …",
"page.password_change_init.status.success": "Done. Take a look into your e-mail inbox",
"page.password_change_init.status.fail": "Something went wrong :/",
"page.password_change_exec.title": "Change Password",
"page.password_change_exec.form.field.password_value.label": "password",
"page.password_change_exec.form.field.password_confirmation.label": "confirm password",
"page.password_change_exec.form.submit": "Change",
"page.password_change_exec.flaw.token_invalid": "permission expired",
"page.password_change_exec.flaw.password_mismatch": "die Passwörter stimmen nicht überein",
"page.password_change_exec.flaw.password_too_short": "das Passwort muss mindestens {{minimum_length}} Zeichen haben",
"page.password_change_exec.flaw.password_too_long": "das Passwort darf höchstens {{maximum_length}} Zeichen haben",
"page.password_change_exec.flaw.password_lacks_letter": "das Passwort muss einen Buchstaben beinhalten",
"page.password_change_exec.flaw.password_lacks_number": "das Passwort muss ein Zahl beinhalten",
"page.password_change_exec.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten",
"page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/",
"page.password_change_exec.status.success": "done"
} }
} }

View file

@ -405,4 +405,71 @@ namespace _espe.backend
); );
} }
/**
*/
export async function member_password_change_initialize(
identifier : string
) : Promise<string>
{
const url_template : string = (
"/"
+
lib_plankton.zoo_page.encode(
{
"name": "password_change_exec",
"parameters": {
"id": "{{id}}",
"token": "{{token}}",
}
}
)
);
return (
abstract_call(
"POST",
"/member/password_change/initialize",
{
"data": {
"identifier": identifier,
"url_template": url_template,
},
}
)
);
}
/**
*/
export async function member_password_change_execute(
id : int,
token : string,
password_new : string
) : Promise<
Array<
{
incident : string;
details : Record<string, any>;
}
>
>
{
return (
abstract_call(
"PATCH",
("/member/password_change/execute/" + id.toFixed(0)),
{
"data": {
"token": token,
"password_new": password_new,
},
"custom_response_handlers": {
409: (output_data_raw) => output_data_raw,
},
}
)
);
}
} }

View file

@ -0,0 +1,115 @@
lib_plankton.zoo_page.register(
"password_change_exec",
(parameters, target_element) => {
function set_state(
state : ("load" | "fill" | "wait" | "done"),
messages : Array<string> = []
) : void
{
target_element.querySelector(".password_change_exec").setAttribute("rel", state);
target_element.querySelector(".password_change_exec-message").textContent = "";
let dom_list = document.createElement("ul");
messages.forEach(
message => {
let dom_message = document.createElement("li");
dom_message.textContent = message;
dom_list.appendChild(dom_message);
}
);
target_element.querySelector(".password_change_exec-message").appendChild(dom_list);
}
const id : int = parseInt(parameters.id);
const token : string = parameters.token;
update_nav({"mode": null});
target_element.appendChild(template_request("password_change_exec"));
target_element.querySelector(".password_change_exec-title").textContent = lib_plankton.translate.get("page.password_change_exec.title");
set_state(
"load",
[
]
);
const form = new lib_plankton.zoo_form.class_form<
{
password_value : string;
password_confirmation : string;
},
{
password_value : string;
password_confirmation : string;
}
>(
x => x,
x => x,
new lib_plankton.zoo_input.class_input_group(
[
{
"name": "password_value",
"input": new lib_plankton.zoo_input.class_input_password(),
"label": lib_plankton.translate.get("page.password_change_exec.form.field.password_value.label"),
},
{
"name": "password_confirmation",
"input": new lib_plankton.zoo_input.class_input_password(),
"label": lib_plankton.translate.get("page.password_change_exec.form.field.password_confirmation.label"),
},
]
),
[
{
"label": lib_plankton.translate.get("page.password_change_exec.form.submit"),
"procedure": async (get_value, get_representation) => {
const value = await get_value();
set_state(
"wait",
[
]
);
let flaws : Array<{incident : string; details : Record<string, any>;}>;
if (! (value.password_value === value.password_confirmation)) {
flaws = [
{"incident": "password_mismatch", "details": {}},
];
}
else {
try {
flaws = await _espe.backend.member_password_change_execute(
id,
token,
value.password_value
);
}
catch (error) {
flaws = [
{"incident": "unhandled_error", "details": {}},
];
}
}
if (flaws.length > 0) {
set_state(
"fill",
flaws.map(
flaw => lib_plankton.string.coin(
lib_plankton.translate.get("page.password_change_exec.flaw." + flaw.incident),
flaw.details
)
)
);
}
else {
set_state(
"done",
[
lib_plankton.translate.get("page.password_change_exec.status.success")
]
);
}
},
}
]
);
form.setup(target_element.querySelector(".password_change_exec-form") as HTMLElement);
}
);

View file

@ -0,0 +1,8 @@
<template id="password_change_exec">
<section class="password_change_exec">
<h2 class="password_change_exec-title"></h2>
<div class="password_change_exec-message"></div>
<div class="password_change_exec-form"></div>
<p class="password_change_exec-status"></p>
</section>
</template>

View file

@ -0,0 +1,11 @@
.password_change_exec:not([rel]) .password_change_exec-message {display: none;}
.password_change_exec:not([rel]) .password_change_exec-form {display: none;}
.password_change_exec[rel="fill"] .password_change_exec-message {}
.password_change_exec[rel="fill"] .password_change_exec-form {}
.password_change_exec[rel="wait"] .password_change_exec-message {}
.password_change_exec[rel="wait"] .password_change_exec-form {display: none;}
.password_change_exec[rel="done"] .password_change_exec-message {}
.password_change_exec[rel="done"] .password_change_exec-form {display: none;}

View file

@ -0,0 +1,55 @@
lib_plankton.zoo_page.register(
"password_change_init",
(parameters, target_element) => {
target_element.appendChild(template_request("password_change_init"));
target_element.querySelector(".password_change_init-title").textContent = lib_plankton.translate.get("page.password_change_init.title");
target_element.querySelector(".password_change_init-info").textContent = lib_plankton.translate.get("page.password_change_init.info");
update_nav({"mode": null});
const form = new lib_plankton.zoo_form.class_form<
{
identifier : string;
},
{
identifier : string;
}
>(
x => x,
x => x,
new lib_plankton.zoo_input.class_input_group(
[
{
"name": "identifier",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("page.password_change_init.identifier"),
},
]
),
[
{
"label": lib_plankton.translate.get("page.password_change_init.submit"),
"procedure": async (get_value, get_representation) => {
target_element.querySelector(".password_change_init-stat").textContent = lib_plankton.translate.get("page.password_change_init.status.wait");
const value = await get_value();
(
_espe.backend.member_password_change_initialize(value.identifier)
.then(
() => {
target_element.querySelector(".password_change_init-stat").textContent = lib_plankton.translate.get("page.password_change_init.status.success");
}
)
.catch(
(error) => {
target_element.querySelector(".password_change_init-stat").textContent = lib_plankton.translate.get("page.password_change_init.status.fail");
}
)
);
},
}
]
);
form.setup(target_element.querySelector(".password_change_init-form") as HTMLElement);
}
);

View file

@ -0,0 +1,6 @@
<template id="password_change_init">
<h2 class="password_change_init-title"></h2>
<p class="password_change_init-info"></p>
<div class="password_change_init-form"></div>
<p class="password_change_init-stat"></p>
</template>

View file

@ -29,6 +29,8 @@ ${dir_temp}/logic-unlinked.js: \
${dir_source}/pages/list/logic.ts \ ${dir_source}/pages/list/logic.ts \
${dir_source}/pages/view/logic.ts \ ${dir_source}/pages/view/logic.ts \
${dir_source}/pages/register/logic.ts \ ${dir_source}/pages/register/logic.ts \
${dir_source}/pages/password_change_init/logic.ts \
${dir_source}/pages/password_change_exec/logic.ts \
${dir_source}/logic/main.ts ${dir_source}/logic/main.ts
@ ${cmd_log} "logic | compile …" @ ${cmd_log} "logic | compile …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)
@ -48,7 +50,9 @@ ${dir_build}/style.css: \
${dir_source}/pages/create/style.css \ ${dir_source}/pages/create/style.css \
${dir_source}/pages/list/style.css \ ${dir_source}/pages/list/style.css \
${dir_source}/pages/view/style.css \ ${dir_source}/pages/view/style.css \
${dir_source}/pages/register/style.css ${dir_source}/pages/register/style.css \
${dir_source}/pages/password_change_init/style.css \
${dir_source}/pages/password_change_exec/style.css
@ ${cmd_log} "style …" @ ${cmd_log} "style …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)
@ ${cmd_cat} $^ > $@ @ ${cmd_cat} $^ > $@
@ -61,7 +65,9 @@ ${dir_build}/index.html: \
${dir_source}/pages/create/structure.html \ ${dir_source}/pages/create/structure.html \
${dir_source}/pages/list/structure.html \ ${dir_source}/pages/list/structure.html \
${dir_source}/pages/view/structure.html \ ${dir_source}/pages/view/structure.html \
${dir_source}/pages/register/structure.html ${dir_source}/pages/register/structure.html \
${dir_source}/pages/password_change_init/structure.html \
${dir_source}/pages/password_change_exec/structure.html
@ ${cmd_log} "structure …" @ ${cmd_log} "structure …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)
@ tools/make-index $^ > $@ @ tools/make-index $^ > $@