From 085d255ae75975b0175871e1dd6786321957cc7b Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Sun, 5 Oct 2025 23:24:47 +0200 Subject: [PATCH] =?UTF-8?q?[add]=20api:invitation=5Fdelete=20[mod]=20Front?= =?UTF-8?q?end-URL-Templates=20nun=20in=20Konfiguration=20statt=20als=20Pa?= =?UTF-8?q?rameter=20von=20au=C3=9Fen=20(conf=205=20->=206)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- misc/conf-example.json | 2 + source/api/actions/invitation_create.ts | 35 ++++++---- source/api/actions/invitation_delete.ts | 69 +++++++++++++++++++ source/api/functions.ts | 1 + source/conf.ts | 90 ++++++++++++++++++++----- source/helpers.ts | 2 +- source/services/invitation.ts | 37 +++++++--- tools/makefile | 1 + 8 files changed, 196 insertions(+), 41 deletions(-) create mode 100644 source/api/actions/invitation_delete.ts diff --git a/misc/conf-example.json b/misc/conf-example.json index c4f1802..024becb 100644 --- a/misc/conf-example.json +++ b/misc/conf-example.json @@ -56,6 +56,8 @@ }, "connections": { "frontend_url_base": "http://localhost:8888", + "frontend_path_template_invitation_handle": "/#invitation_handle,key={{key}}", + "frontend_path_template_password_change": "/#password_change_exec,id={{id}},key={{key}}", "login_url": "https://login.example.org" } }, diff --git a/source/api/actions/invitation_create.ts b/source/api/actions/invitation_create.ts index b681700..3324a7a 100644 --- a/source/api/actions/invitation_create.ts +++ b/source/api/actions/invitation_create.ts @@ -35,7 +35,6 @@ namespace _espe.api groups_value : Array; expiry : (null | int); }; - notification_target_url_template ?: (null | string); send_immediatly : boolean; }, ( @@ -44,6 +43,7 @@ namespace _espe.api { id : _espe.type.member_id; key : string; + url : (null | string); } ) >( @@ -117,11 +117,6 @@ namespace _espe.api "expiry", ] }, - "notification_target_url_template": { - "type": "string", - "nullable": true, - "description": "Platz-Halter: key" - }, "send_immediatly": { "nullable": false, "type": "boolean", @@ -145,20 +140,31 @@ namespace _espe.api "type": "string", "nullable": false, }, + "url": { + "type": "string", + "nullable": true, + }, }, "additionalProperties": false, "required": [ "id", "key", + "url", ] }), "restriction": () => restriction_logged_in, "execution": () => async ({"input": input}) => { - if (input === null) { + if (input === null) + { return Promise.reject(new Error("impossible")); } - else { - const invitation_info : {id : _espe.type.invitation_id; key : _espe.type.invitation_key;} = await _espe.service.invitation.create( + else + { + const invitation_info : { + id : _espe.type.invitation_id; + key : _espe.type.invitation_key; + url : (null | string); + } = await _espe.service.invitation.create( { "name_changeable": input.data.name_changeable, "name_value": input.data.name_value, @@ -171,14 +177,15 @@ namespace _espe.api }, { "expiry": input.data.expiry, - "notification_target_url_template": input.notification_target_url_template, "send_immediatly": input.send_immediatly, } ); - return Promise.resolve({ - "status_code": 201, - "data": invitation_info - }); + return Promise.resolve( + { + "status_code": 201, + "data": invitation_info + } + ); } } } diff --git a/source/api/actions/invitation_delete.ts b/source/api/actions/invitation_delete.ts new file mode 100644 index 0000000..9c6ef2f --- /dev/null +++ b/source/api/actions/invitation_delete.ts @@ -0,0 +1,69 @@ +/* +Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend +Copyright (C) 2024 Christian Fraß + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see +. + */ + +namespace _espe.api +{ + + /** + */ + export function register_invitation_delete( + rest_subject : lib_plankton.rest_http.type_rest + ) : void + { + lib_plankton.rest_http.register< + int, + null + >( + rest_subject, + lib_plankton.http.enum_method.delete, + _espe.api.full_path("/invitation/delete"), + { + /** + * @todo translation + */ + "description": () => "löscht eine Einladung", + "input_schema": () => ({ + "nullable": false, + "type": "integer", + }), + "output_schema": () => ({ + "nullable": true, + }), + "restriction": () => restriction_logged_in, + "execution": () => async (stuff) => { + if (stuff.input === null) + { + return Promise.reject(new Error("impossible")); + } + else + { + const invitation_id : _espe.type.invitation_id = stuff.input; + await _espe.service.invitation.remove( + invitation_id + ); + return Promise.resolve( + { + "status_code": 200, + "data": null + } + ); + } + } + } + ); + } + +} + diff --git a/source/api/functions.ts b/source/api/functions.ts index d030510..e48f2a9 100644 --- a/source/api/functions.ts +++ b/source/api/functions.ts @@ -67,6 +67,7 @@ namespace _espe.api _espe.api.register_invitation_list(rest_subject); _espe.api.register_invitation_read(rest_subject); _espe.api.register_invitation_create(rest_subject); + _espe.api.register_invitation_delete(rest_subject); _espe.api.register_invitation_examine(rest_subject); _espe.api.register_invitation_accept(rest_subject); } diff --git a/source/conf.ts b/source/conf.ts index 004e4f5..feb8677 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -161,6 +161,8 @@ namespace _espe.conf }; connections : { frontend_url_base : (null | string); + frontend_path_template_invitation_handle : (null | string); + frontend_path_template_password_change : (null | string); login_url : (null | string); }; }; @@ -208,7 +210,7 @@ namespace _espe.conf conf_raw : any ) : void { - const version : int = (conf_raw["version"] ?? 5); + const version : int = (conf_raw["version"] ?? 6); _data = { "general": ( ((node_general) => ({ @@ -219,7 +221,8 @@ namespace _espe.conf "log": ( (() => { switch (version) { - case 1: { + case 1: + { return [ { "kind": "stdout", @@ -233,7 +236,9 @@ namespace _espe.conf case 2: case 3: case 4: - case 5: { + case 5: + case 6: + { const node_log = ( conf_raw["log"] ?? @@ -270,12 +275,15 @@ namespace _espe.conf switch (version) { case 1: case 2: - case 3: { + case 3: + { return "::"; break; } case 4: - case 5: { + case 5: + case 6: + { return (node_server["host"] ?? "::"); break } @@ -290,7 +298,8 @@ namespace _espe.conf const kind : string = (node_database["kind"] ?? "sqlite"); const node_database_data_raw = (node_database["data"] ?? {}); switch (kind) { - case "sqlite": { + case "sqlite": + { return { "kind": kind, "data": { @@ -299,14 +308,16 @@ namespace _espe.conf }; break; } - case "postgresql": { + case "postgresql": + { return { "kind": kind, "data": node_database_data_raw, }; break; } - default: { + default: + { throw (new Error("unhandled")); break; } @@ -318,7 +329,8 @@ namespace _espe.conf const kind : string = (node_email_sending["kind"] ?? "console"); const data_raw = (node_email_sending["data"] ?? {}); switch (kind) { - case "regular": { + case "regular": + { return { "kind": kind, "data": { @@ -328,7 +340,8 @@ namespace _espe.conf }; break; } - case "redirect": { + case "redirect": + { return { "kind": kind, "data": { @@ -339,7 +352,8 @@ namespace _espe.conf }; break; } - case "console": { + case "console": + { return { "kind": kind, "data": { @@ -347,7 +361,8 @@ namespace _espe.conf }; break; } - case "drop": { + case "drop": + { return { "kind": kind, "data": { @@ -355,7 +370,8 @@ namespace _espe.conf }; break; } - default: { + default: + { throw (new Error("unhandled")); break; } @@ -400,6 +416,44 @@ namespace _espe.conf "connections": ( ((node_settings_connections) => ({ "frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null), + "frontend_path_template_password_change": (() => { + switch (version) + { + case 1: + case 2: + case 3: + case 4: + case 5: + { + return null; + break; + } + case 6: + { + return (node_settings_connections["frontend_path_template_password_change"] ?? null); + break; + } + } + }) (), + "frontend_path_template_invitation_handle": (() => { + switch (version) + { + case 1: + case 2: + case 3: + case 4: + case 5: + { + return null; + break; + } + case 6: + { + return (node_settings_connections["frontend_path_template_invitation_handle"] ?? null); + break; + } + } + }) (), "login_url": (node_settings_connections["login_url"] ?? null), })) (node_settings["connections"] ?? {}) ), @@ -408,7 +462,8 @@ namespace _espe.conf "outputs": (() => { switch (version) { case 1: - case 2: { + case 2: + { const node_output = (conf_raw["output"] ?? {}); return ( ("authelia" in node_output) @@ -427,12 +482,15 @@ namespace _espe.conf ); break; } - case 3: { + case 3: + { return (conf_raw["outputs"] ?? []); break; } case 4: - case 5: { + case 5: + case 6: + { const node_outputs = (conf_raw["outputs"] ?? []); return node_outputs.map( (output_description : {kind : string; data : any;}) => { diff --git a/source/helpers.ts b/source/helpers.ts index 28947d2..ab9e26b 100644 --- a/source/helpers.ts +++ b/source/helpers.ts @@ -259,7 +259,7 @@ namespace _espe.helpers } else { return lib_plankton.string.coin( - "{{base}}/{{rest}}", + "{{base}}{{rest}}", { "base": frontend_url_base, "rest": lib_plankton.string.coin(template, arguments_), diff --git a/source/services/invitation.ts b/source/services/invitation.ts index 652dbbb..07b97d4 100644 --- a/source/services/invitation.ts +++ b/source/services/invitation.ts @@ -78,11 +78,9 @@ namespace _espe.service.invitation }, { "expiry": expiry = -1, - "notification_target_url_template": notification_target_url_template = null, "send_immediatly": send_immediatly = true, } : { expiry ?: (null | int); - notification_target_url_template ?: (null | string); send_immediatly ?: boolean; } = { } @@ -90,6 +88,7 @@ namespace _espe.service.invitation { id : _espe.type.invitation_id; key : _espe.type.invitation_key; + url : (null | string); } > { @@ -129,6 +128,19 @@ namespace _espe.service.invitation "groups_value": groups_value, }; const invitation_id : _espe.type.invitation_id = await _espe.repository.invitation.create(invitation_object); + const frontend_path_template_invitation_handle : (null | string) = _espe.conf.get().settings.connections.frontend_path_template_invitation_handle; + const url : (null | string) = ( + (frontend_path_template_invitation_handle === null) + ? + null + : + _espe.helpers.frontend_url_get( + frontend_path_template_invitation_handle, + { + "key": invitation_key, + } + ) + ); // send link { if (! send_immediatly) @@ -145,7 +157,7 @@ namespace _espe.service.invitation (email_address_value !== "") ) && - (notification_target_url_template !== null) + (url !== null) ) ) { @@ -154,19 +166,13 @@ namespace _espe.service.invitation { "details": { "provided_address": email_address_value, - "notification_target_url_template": notification_target_url_template, + "url": url, }, } ); } else { - const url : (null | string) = _espe.helpers.frontend_url_get( - notification_target_url_template, - { - "key": invitation_key, - } - ); try { await _espe.helpers.email_send( @@ -205,10 +211,21 @@ namespace _espe.service.invitation return { "id": invitation_id, "key": invitation_key, + "url": url, }; } + /** + */ + export function remove( + id : _espe.type.invitation_id + ) : Promise + { + return _espe.repository.invitation.delete_(id); + } + + /** */ export function get_by_id( diff --git a/tools/makefile b/tools/makefile index a621835..c669da1 100644 --- a/tools/makefile +++ b/tools/makefile @@ -74,6 +74,7 @@ ${dir_temp}/espe-core.js ${dir_temp}/espe-core.d.ts: \ ${dir_source}/api/actions/invitation_list.ts \ ${dir_source}/api/actions/invitation_read.ts \ ${dir_source}/api/actions/invitation_create.ts \ + ${dir_source}/api/actions/invitation_delete.ts \ ${dir_source}/api/actions/invitation_examine.ts \ ${dir_source}/api/actions/invitation_accept.ts \ ${dir_source}/api/functions.ts \