From 74f79ae0b7c92327a97ef4fa95edc87a3befe75e Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 25 Sep 2025 16:07:41 +0200 Subject: [PATCH] [add] api:user_dav_conf [add] api:user_dav_token [mod] conf:add caldav node --- source/api/actions/user_dav_conf.ts | 152 +++++++++++++++++++++++++++ source/api/actions/user_dav_token.ts | 53 ++++++++++ source/api/functions.ts | 10 +- source/conf.ts | 54 ++++++++++ source/repositories/user.ts | 13 +++ source/services/user.ts | 11 ++ tools/makefile | 2 + 7 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 source/api/actions/user_dav_conf.ts create mode 100644 source/api/actions/user_dav_token.ts diff --git a/source/api/actions/user_dav_conf.ts b/source/api/actions/user_dav_conf.ts new file mode 100644 index 0000000..b568f8b --- /dev/null +++ b/source/api/actions/user_dav_conf.ts @@ -0,0 +1,152 @@ +namespace _zeitbild.api +{ + + /** + */ + export function register_user_dav_conf( + rest_subject : lib_plankton.rest_http.type_rest + ) : void + { + register< + null, + ( + null + | + { + address : string; + username : string; + password : (null | string); + setup_hints : Array< + { + label : string; + link : string; + remark : (null | string); + } + >; + } + ) + >( + rest_subject, + lib_plankton.http.enum_method.get, + "/user_dav_conf", + { + "description": "gibt die CalDAV-Zugangsdaten eines Nutzers aus", + "output_schema": () => ({ + "nullable": true, + "type": "object", + "properties": { + "address": { + "nullable": false, + "type": "string" + }, + "username": { + "nullable": false, + "type": "string" + }, + "password": { + "nullable": true, + "type": "string" + }, + "setup_hints": { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "object", + "properties": { + "label": { + "nullable": false, + "type": "string" + }, + "link": { + "nullable": false, + "type": "string" + }, + "remark": { + "nullable": true, + "type": "string", + "default": null, + }, + }, + "required": [ + "label", + "link", + ], + "additionalProperties": false + }, + "default": [] + }, + }, + "required": [ + "address", + "username", + "password", + "setup_hints", + ], + "additionalProperties": false + }), + "restriction": restriction_logged_in, + "execution": async (stuff) => { + let result : ( + null + | + { + address : string; + username : string; + password : (null | string); + setup_hints : Array< + { + label : string; + link : string; + remark : (null | string); + } + >; + } + ) = null; + const raw : (null | any) = _zeitbild.conf.get()["caldav"]; + if (raw === null) + { + result = null; + } + else + { + const session : {key : string; value : lib_plankton.session.type_session;} = await session_from_stuff(stuff); + const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.identify(session.value.name); + const user_object : _zeitbild.type_user_object = await _zeitbild.service.user.get(user_id); + const arguments_ : Record = Object.fromEntries( + [ + {"key": "username", "value": user_object.name}, + {"key": "password", "value": user_object.dav_token}, + ] + .filter( + entry => (entry.value !== null) + ) + .map( + entry => ([entry.key, entry.value as string]) + ) + ); + result = { + "address": lib_plankton.string.coin(raw["address"], arguments_), + "username": lib_plankton.string.coin(raw["username"], arguments_), + "password": ( + (user_object.dav_token === null) + ? + null + : + lib_plankton.string.coin(raw["password"], arguments_) + ), + "setup_hints": raw["setup_hints"], + }; + } + return Promise.resolve( + { + "status_code": 200, + "data": result, + } + ); + } + } + ); + } + +} diff --git a/source/api/actions/user_dav_token.ts b/source/api/actions/user_dav_token.ts new file mode 100644 index 0000000..3293f5e --- /dev/null +++ b/source/api/actions/user_dav_token.ts @@ -0,0 +1,53 @@ +namespace _zeitbild.api +{ + + /** + */ + export function register_user_dav_token( + rest_subject : lib_plankton.rest_http.type_rest + ) : void + { + register< + // string, + null, + null + >( + rest_subject, + lib_plankton.http.enum_method.patch, + "/user_dav_token", + { + "description": "setzt/überschreibt den DAV-Token eines Nutzers", + /* + "input_schema": () => ({ + "nullable": false, + "type": "string" + }), + */ + "input_schema": () => ({ + "nullable": true, + }), + "output_schema": () => ({ + "nullable": true + }), + "restriction": restriction_logged_in, + "execution": async (stuff) => { + const session : {key : string; value : lib_plankton.session.type_session;} = await session_from_stuff(stuff); + const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.identify(session.value.name); + // TODO: outsource to user service? + const user_object : _zeitbild.type_user_object = await _zeitbild.service.user.get(user_id); + // user_object.dav_token = stuff.input; + user_object.dav_token = lib_plankton.random.generate_string({"length": 12}); + await _zeitbild.service.user.change(user_id, user_object); + return Promise.resolve( + { + "status_code": 200, + "data": null, + } + ); + } + } + ); + } + +} + diff --git a/source/api/functions.ts b/source/api/functions.ts index 0fae129..8ae4442 100644 --- a/source/api/functions.ts +++ b/source/api/functions.ts @@ -31,6 +31,15 @@ namespace _zeitbild.api _zeitbild.api.register_session_end(rest_subject); _zeitbild.api.register_session_oidc(rest_subject); } + // user + { + _zeitbild.api.register_users(rest_subject); + // caldav + { + _zeitbild.api.register_user_dav_conf(rest_subject); + _zeitbild.api.register_user_dav_token(rest_subject); + } + } // calendar { _zeitbild.api.register_calendar_list(rest_subject); @@ -52,7 +61,6 @@ namespace _zeitbild.api } // misc { - _zeitbild.api.register_users(rest_subject); _zeitbild.api.register_events(rest_subject); } diff --git a/source/conf.ts b/source/conf.ts index a95febb..d611d1e 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -299,6 +299,60 @@ namespace _zeitbild.conf "default": { } }, + "caldav": { + "nullable": true, + "type": "object", + "properties": { + "address": { + "nullable": false, + "type": "string" + }, + "username": { + "nullable": false, + "type": "string" + }, + "password": { + "nullable": false, + "type": "string" + }, + "setup_hints": { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "object", + "properties": { + "label": { + "nullable": false, + "type": "string" + }, + "link": { + "nullable": false, + "type": "string" + }, + "remark": { + "nullable": true, + "type": "string", + "default": null + }, + }, + "required": [ + "label", + "link", + ], + "additionalProperties": false + }, + "default": [] + }, + }, + "required": [ + "address", + "username", + "password" + ], + "additionalProperties": false, + "default": null + }, "misc": { "nullable": false, "type": "object", diff --git a/source/repositories/user.ts b/source/repositories/user.ts index 1299250..528ad11 100644 --- a/source/repositories/user.ts +++ b/source/repositories/user.ts @@ -121,6 +121,19 @@ namespace _zeitbild.repository.user } + /** + */ + export async function update( + user_id : _zeitbild.type_user_id, + user_object : _zeitbild.type_user_object + ) : Promise + { + const dispersal : Record = encode(user_object); + await get_store().update(user_id, dispersal); + return Promise.resolve(undefined); + } + + /** */ export async function identify( diff --git a/source/services/user.ts b/source/services/user.ts index a6e5a5f..ec08125 100644 --- a/source/services/user.ts +++ b/source/services/user.ts @@ -47,4 +47,15 @@ namespace _zeitbild.service.user return _zeitbild.repository.user.create(user_object); } + + /** + */ + export function change( + user_id : _zeitbild.type_user_id, + user_object : _zeitbild.type_user_object + ) : Promise + { + return _zeitbild.repository.user.update(user_id, user_object); + } + } diff --git a/tools/makefile b/tools/makefile index 401af4e..b175eba 100644 --- a/tools/makefile +++ b/tools/makefile @@ -65,6 +65,8 @@ ${dir_temp}/zeitbild-unlinked.js: \ ${dir_source}/api/actions/session_oidc.ts \ ${dir_source}/api/actions/session_end.ts \ ${dir_source}/api/actions/users.ts \ + ${dir_source}/api/actions/user_dav_conf.ts \ + ${dir_source}/api/actions/user_dav_token.ts \ ${dir_source}/api/actions/calendar_list.ts \ ${dir_source}/api/actions/calendar_get.ts \ ${dir_source}/api/actions/calendar_add.ts \