From 550f3989d30bd9f72895a7ebcf975f18c7995828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Mon, 20 May 2024 14:07:43 +0200 Subject: [PATCH] =?UTF-8?q?[add]=20Passwort-=C3=84nderungs-Funktionalit?= =?UTF-8?q?=C3=A4t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/data/localization/deu.loc.json | 22 +++- source/data/localization/eng.loc.json | 22 +++- source/logic/backend.ts | 67 ++++++++++ source/pages/password_change_exec/logic.ts | 115 ++++++++++++++++++ .../pages/password_change_exec/structure.html | 8 ++ source/pages/password_change_exec/style.css | 11 ++ source/pages/password_change_init/logic.ts | 55 +++++++++ .../pages/password_change_init/structure.html | 6 + source/pages/password_change_init/style.css | 0 tools/makefile | 10 +- 10 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 source/pages/password_change_exec/logic.ts create mode 100644 source/pages/password_change_exec/structure.html create mode 100644 source/pages/password_change_exec/style.css create mode 100644 source/pages/password_change_init/logic.ts create mode 100644 source/pages/password_change_init/structure.html create mode 100644 source/pages/password_change_init/style.css diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 486bdc2..85f3698 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -48,6 +48,26 @@ "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.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" } } diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 8078795..8ab9e8e 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -48,6 +48,26 @@ "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.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" } } diff --git a/source/logic/backend.ts b/source/logic/backend.ts index 65cddb6..aec1a13 100644 --- a/source/logic/backend.ts +++ b/source/logic/backend.ts @@ -405,4 +405,71 @@ namespace _espe.backend ); } + + /** + */ + export async function member_password_change_initialize( + identifier : string + ) : Promise + { + 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; + } + > + > + { + 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, + }, + } + ) + ); + } + } diff --git a/source/pages/password_change_exec/logic.ts b/source/pages/password_change_exec/logic.ts new file mode 100644 index 0000000..c15d0d7 --- /dev/null +++ b/source/pages/password_change_exec/logic.ts @@ -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 = [] + ) : 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;}>; + 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); + } +); diff --git a/source/pages/password_change_exec/structure.html b/source/pages/password_change_exec/structure.html new file mode 100644 index 0000000..e56298d --- /dev/null +++ b/source/pages/password_change_exec/structure.html @@ -0,0 +1,8 @@ + diff --git a/source/pages/password_change_exec/style.css b/source/pages/password_change_exec/style.css new file mode 100644 index 0000000..b62f01c --- /dev/null +++ b/source/pages/password_change_exec/style.css @@ -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;} diff --git a/source/pages/password_change_init/logic.ts b/source/pages/password_change_init/logic.ts new file mode 100644 index 0000000..535934a --- /dev/null +++ b/source/pages/password_change_init/logic.ts @@ -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); + } +); diff --git a/source/pages/password_change_init/structure.html b/source/pages/password_change_init/structure.html new file mode 100644 index 0000000..4709a10 --- /dev/null +++ b/source/pages/password_change_init/structure.html @@ -0,0 +1,6 @@ + diff --git a/source/pages/password_change_init/style.css b/source/pages/password_change_init/style.css new file mode 100644 index 0000000..e69de29 diff --git a/tools/makefile b/tools/makefile index 3cf9c1b..3f11ab9 100644 --- a/tools/makefile +++ b/tools/makefile @@ -29,6 +29,8 @@ ${dir_temp}/logic-unlinked.js: \ ${dir_source}/pages/list/logic.ts \ ${dir_source}/pages/view/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 @ ${cmd_log} "logic | compile …" @ ${cmd_mkdir} $(dir $@) @@ -48,7 +50,9 @@ ${dir_build}/style.css: \ ${dir_source}/pages/create/style.css \ ${dir_source}/pages/list/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_mkdir} $(dir $@) @ ${cmd_cat} $^ > $@ @@ -61,7 +65,9 @@ ${dir_build}/index.html: \ ${dir_source}/pages/create/structure.html \ ${dir_source}/pages/list/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_mkdir} $(dir $@) @ tools/make-index $^ > $@