From 2eed983131323d1c241a1768fa0e7fb604c8138e Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 23 Oct 2025 13:18:25 +0200 Subject: [PATCH] [task-416] [mod] oidc group handling [mod] calendar overview query handling (PostgreSQL specific) --- source/api/actions/session_oidc.ts | 132 ++++++++++-------- source/auth.ts | 1 + source/repositories/calendar.ts | 57 ++++++-- source/repositories/sql/calendar_overview.sql | 12 +- 4 files changed, 127 insertions(+), 75 deletions(-) diff --git a/source/api/actions/session_oidc.ts b/source/api/actions/session_oidc.ts index a5c59f1..fee9dda 100644 --- a/source/api/actions/session_oidc.ts +++ b/source/api/actions/session_oidc.ts @@ -123,67 +123,87 @@ namespace _zeitbild.api } else { - try - { - // groups - const group_ids : Array<_zeitbild.type_group_id> = await Promise.all<_zeitbild.type_group_id>( - (data.userinfo.groups ?? []) - .map( - async (group_name_raw) => { - const group_name : string = get_group_name(group_name_raw); - let group_id : (null | _zeitbild.type_group_id) = await (() => { - try + // groups + const group_ids : Array<_zeitbild.type_group_id> = await Promise.all<_zeitbild.type_group_id>( + (data.userinfo.groups ?? []) + .map( + async (group_name_raw) => { + const group_name : string = get_group_name(group_name_raw); + const group_id_raw : (null | _zeitbild.type_group_id) = await ( + _zeitbild.repository.group.identify(group_name) + .catch(() => Promise.resolve(null)) + ); + if (group_id_raw === null) + { + const group_id : _zeitbild.type_group_id = await _zeitbild.service.group.add( { - return _zeitbild.repository.group.identify(group_name); + "name": group_name, + "label": get_group_label(group_name_raw), } - catch (error) - { - return Promise.resolve(null); - } - }) (); - if (group_id === null) - { - group_id = await _zeitbild.service.group.add( - { - "name": group_name, - "label": get_group_label(group_name_raw), - } - ); - return group_id; - } - else - { - await _zeitbild.service.group.change( - group_id, - { - "name": group_name, - "label": get_group_label(group_name_raw), - } - ); - return group_id; - } + ); + return group_id; + } + else + { + const group_id : _zeitbild.type_group_id = group_id_raw; + await _zeitbild.service.group.change( + group_id, + { + "name": group_name, + "label": get_group_label(group_name_raw), + } + ); + return group_id; } - ) - ); - await _zeitbild.service.user.add( - { - "name": data.userinfo.name, - "groups": group_ids, - "email_address": data.userinfo.email, - "dav_token": null, } + ) + ); + + const user_id : _zeitbild.type_user_id = await (async () => { + const user_object : _zeitbild.type_user_object = { + "name": (data.userinfo.name as string), + "groups": group_ids, + "email_address": data.userinfo.email, + "dav_token": null, + }; + const user_id_raw : (null | _zeitbild.type_user_id) = await ( + _zeitbild.service.user.identify(data.userinfo.name as string) + .catch(() => Promise.resolve(null)) ); - lib_plankton.log.info( - "user_provisioned", - { - "name": data.userinfo.name, - } - ); - } - catch (error) - { - // do nothing - } + if (user_id_raw === null) + { + // provision + const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.add( + user_object + ); + lib_plankton.log.info( + "user_provisioned", + { + "id": user_id, + "name": user_object.name, + } + ); + return user_id; + } + else + { + const user_id : _zeitbild.type_user_id = user_id_raw; + // update + await _zeitbild.service.user.change( + user_id, + user_object + ); + lib_plankton.log.info( + "user_updated", + { + "id": user_id, + "name": user_object.name, + } + ); + return user_id; + } + }) (); + const session_key : string = await lib_plankton.session.begin( data.userinfo.name, { diff --git a/source/auth.ts b/source/auth.ts index 8e5ffd9..cfd094b 100644 --- a/source/auth.ts +++ b/source/auth.ts @@ -100,6 +100,7 @@ namespace _zeitbild.auth "openid", "profile", "email", + "groups", ], "label": _zeitbild.conf.get().authentication.data.label, } diff --git a/source/repositories/calendar.ts b/source/repositories/calendar.ts index db66714..03e54e3 100644 --- a/source/repositories/calendar.ts +++ b/source/repositories/calendar.ts @@ -639,31 +639,62 @@ namespace _zeitbild.repository.calendar (x : Array>) => x.map( (row : Record) => ({ "id": row["id"], - "name": row["name"], - "hue": (row["hue"] / hue_scaling), + "name": lib_plankton.call.convey( + row["name"], + [ + // JSON.parse, + (x : Array) => x[0], + ] + ), + "hue": lib_plankton.call.convey( + row["hue"], + [ + // JSON.parse, + (x : Array) => x[0], + (x : int) => (x / hue_scaling), + ] + ), /** * @todo use _zeitbild.access_level_determine */ "access_level": _zeitbild.access_level_determine_raw( - row["access_public"], + lib_plankton.call.convey( + row["access_public"], + [ + // JSON.parse, + (x : Array) => x[0], + ] + ), ( (user_id === null) ? null : { - "default": decode_access_level(row["access_level_default"]), - "group": ( - lib_plankton.call.null_prop>( - row["access_level_attributed_group"], - x => x.split(",").map(parseInt).map(decode_access_level) - ) - ?? - [] + "default": lib_plankton.call.convey( + row["access_level_default"], + [ + // JSON.parse, + (x : Array) => x[0], + decode_access_level, + ] ), - "user": lib_plankton.call.null_prop( + "group": lib_plankton.call.convey( + row["access_level_attributed_group"], + [ + // JSON.parse, + (x : Array<(null | int)>) => x.filter(y => (y !== null)), + (x : Array) => x.map(decode_access_level), + ] + ), + "user": lib_plankton.call.convey( row["access_level_attributed_user"], - decode_access_level + [ + // JSON.parse, + (x : Array<(null | int)>) => x.filter(y => (y !== null)), + (x : Array) => x.map(decode_access_level), + (x : Array<_zeitbild.enum_access_level>) => ((x.length > 0) ? x[0] : null), + ] ), } ) diff --git a/source/repositories/sql/calendar_overview.sql b/source/repositories/sql/calendar_overview.sql index 8290e9a..70a55b6 100644 --- a/source/repositories/sql/calendar_overview.sql +++ b/source/repositories/sql/calendar_overview.sql @@ -1,11 +1,11 @@ SELECT x.id AS id, - MAX(x.name) AS name, - MAX(x.hue) AS hue, - MAX(x.access_public) AS access_public, - MAX(x.access_level_default) AS access_level_default, - GROUP_CONCAT(y1.level, ',') AS access_level_attributed_group, - GROUP_CONCAT(y2.level, ',') AS access_level_attributed_user + JSON_AGG(x.name) AS name, + JSON_AGG(x.hue) AS hue, + JSON_AGG(x.access_public) AS access_public, + JSON_AGG(x.access_level_default) AS access_level_default, + JSON_AGG(y1.level) AS access_level_attributed_group, + JSON_AGG(y2.level) AS access_level_attributed_user FROM calendars AS x LEFT OUTER JOIN calendar_access_attributed_group AS y1 ON ((x.id = y1.calendar_id) AND (y1.group_id IN (SELECT group_id FROM user_groups WHERE (user_id = $user_id))))