From 439f046b1d98057516b82ba607464a7a75e93095 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Mon, 13 Oct 2025 10:48:47 +0200 Subject: [PATCH] [mod] Beispiel-Daten mit relativen Datums-Angaben --- misc/data-example.json | 88 +++++++++-- source/main.ts | 166 +------------------- source/sample.ts | 336 +++++++++++++++++++++++++++++++++++++++++ source/types.ts | 3 + tools/makefile | 1 + 5 files changed, 418 insertions(+), 176 deletions(-) create mode 100644 source/sample.ts diff --git a/misc/data-example.json b/misc/data-example.json index e564273..79a3f1e 100644 --- a/misc/data-example.json +++ b/misc/data-example.json @@ -27,6 +27,7 @@ "id": 1, "name": "LV Lampukistan", "access": { + "public": true, "default_level": "view", "attributed": [ { @@ -47,12 +48,20 @@ "name": "Aufstand: Mieten", "begin": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 14}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [-1]}, + {"action": "shift_day", "args": [6]} + ], "time": {"hour": 12, "minute": 0, "second": 0} }, "end": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 14}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [-1]}, + {"action": "shift_day", "args": [6]} + ], "time": {"hour": 15, "minute": 0, "second": 0} }, "location": "Porada Ninfu, Haupt-Markt", @@ -62,12 +71,20 @@ "name": "Aufstand: Waffen", "begin": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 21}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [0]}, + {"action": "shift_day", "args": [6]} + ], "time": {"hour": 12, "minute": 0, "second": 0} }, "end": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 21}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [0]}, + {"action": "shift_day", "args": [6]} + ], "time": {"hour": 15, "minute": 0, "second": 0} }, "location": "Tandreell, Stoiber-Platz", @@ -77,12 +94,20 @@ "name": "Aufstand: Essen", "begin": { "timezone_shift": 2, - "date": {"year": 2025, "month": 10, "day": 28}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [1]}, + {"action": "shift_day", "args": [6]} + ], "time": {"hour": 12, "minute": 0, "second": 0} }, "end": { "timezone_shift": 2, - "date": {"year": 2025, "month": 10, "day": 28}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [1]}, + {"action": "shift_day", "args": [6]} + ], "time": {"hour": 15, "minute": 0, "second": 0} }, "location": "Kawanda, Nord-Bahnhof", @@ -96,6 +121,7 @@ "id": 2, "name": "KV Zepettel-Region", "access": { + "public": false, "default_level": "view", "attributed": [ { @@ -116,12 +142,20 @@ "name": "Feier: Bier", "begin": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 18}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [0]}, + {"action": "shift_day", "args": [3]} + ], "time": {"hour": 18, "minute": 0, "second": 0} }, "end": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 18}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [0]}, + {"action": "shift_day", "args": [3]} + ], "time": {"hour": 23, "minute": 0, "second": 0} }, "location": "Rudschadinedschad, Schlamm-Park", @@ -131,12 +165,20 @@ "name": "Feier: Schnapps", "begin": { "timezone_shift": 2, - "date": {"year": 2025, "month": 10, "day": 1}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [2]}, + {"action": "shift_day", "args": [2]} + ], "time": {"hour": 18, "minute": 0, "second": 0} }, "end": { "timezone_shift": 2, - "date": {"year": 2025, "month": 10, "day": 1}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [2]}, + {"action": "shift_day", "args": [2]} + ], "time": {"hour": 23, "minute": 0, "second": 0} }, "location": "Kawanda, Ratten-Platz", @@ -150,6 +192,7 @@ "id": 3, "name": "OV Kawanda", "access": { + "public": false, "default_level": "view", "attributed": [ { @@ -166,12 +209,20 @@ "name": "Aufräumen: Flaschen", "begin": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 24}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [1]}, + {"action": "shift_day", "args": [2]} + ], "time": {"hour": 15, "minute": 0, "second": 0} }, "end": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 24}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [1]}, + {"action": "shift_day", "args": [2]} + ], "time": {"hour": 17, "minute": 0, "second": 0} }, "location": "Kawanda, Penner-Allee", @@ -185,6 +236,7 @@ "id": 4, "name": "KV Zepettel-Region | intern", "access": { + "public": false, "default_level": "none", "attributed": [ { @@ -205,12 +257,20 @@ "name": "Infostand", "begin": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 16}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [0]}, + {"action": "shift_day", "args": [1]} + ], "time": {"hour": 10, "minute": 0, "second": 0} }, "end": { "timezone_shift": 2, - "date": {"year": 2025, "month": 9, "day": 16}, + "date_relative": [ + {"action": "trunc_week", "args": []}, + {"action": "shift_week", "args": [0]}, + {"action": "shift_day", "args": [1]} + ], "time": {"hour": 14, "minute": 0, "second": 0} }, "location": "Rudschadinedschad, Schabracken-Markt", diff --git a/source/main.ts b/source/main.ts index e4705a1..b588706 100644 --- a/source/main.ts +++ b/source/main.ts @@ -19,164 +19,6 @@ along with »zeitbild«. If not, see . -/** - */ -type type_data = { - users : Array< - { - id : int; - name : string; - email_address : string; - dav_token : (null | string); - password : string; - } - >; - calendars : Array< - { - id : int; - name : string; - access : { - public ?: boolean; - default_level : ("none" | "view" | "edit" | "admin"); - attributed : Array< - { - user_id : int; - level : ("none" | "view" | "edit" | "admin"); - } - >; - }; - resource : ( - { - kind : "local"; - data : { - events : Array< - _zeitbild.type_event_object - > - }; - } - | - { - kind : "ics_feed"; - data : { - url : string; - from_fucked_up_wordpress ?: boolean; - }; - } - ); - } - >; -}; - - -/** - */ -async function data_init( - data : type_data -) : Promise -{ - let track : { - user : Record< - int, - _zeitbild.type_user_id - >; - calendar : Record< - int, - _zeitbild.type_user_id - >; - } = { - "user": {}, - "calendar": {}, - }; - for await (const user_raw of data.users) - { - const user_object : _zeitbild.type_user_object = { - "name": user_raw.name, - "email_address": user_raw.email_address, - "dav_token": user_raw.dav_token, - }; - const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.add( - user_object - ); - await _zeitbild.service.auth_internal.set( - user_raw.name, - user_raw.password - ); - track.user[user_raw.id] = user_id; - } - for await (const calendar_raw of data.calendars) - { - let resource_object : _zeitbild.type_resource_object; - let resource_id : _zeitbild.type_resource_id; - switch (calendar_raw.resource.kind) - { - case "local": - { - resource_object = { - "kind": "local", - "data": { - "event_ids": [], - } - }; - resource_id = await _zeitbild.service.resource.add( - resource_object - ); - /*const event_ids : Array<_zeitbild.type_local_resource_event_id> = */await Promise.all( - calendar_raw.resource.data.events - .map( - (event_raw : _zeitbild.type_event_object) => _zeitbild.service.resource.event_add(resource_id, event_raw) - ) - ); - break; - } - case "ics_feed": - { - resource_object = { - "kind": "ics_feed", - "data": { - "url": calendar_raw.resource.data.url, - "from_fucked_up_wordpress": (calendar_raw.resource.data.from_fucked_up_wordpress ?? false), - } - }; - resource_id = await _zeitbild.service.resource.add( - resource_object - ); - break; - } - } - const calendar_object : _zeitbild.type_calendar_object = - { - "name": calendar_raw.name, - "access": { - "public": (calendar_raw.access.public ?? false), - "default_level": _zeitbild.value_object.access_level.from_string(calendar_raw.access.default_level), - "attributed": lib_plankton.map.hashmap.implementation_map( - lib_plankton.map.hashmap.make( - x => x.toFixed(0), - { - "pairs": ( - calendar_raw.access.attributed - .map( - (entry) => ({ - "key": track.user[entry.user_id], - "value": _zeitbild.value_object.access_level.from_string(entry.level), - }) - ) - ), - } - ) - ), - }, - "resource_id": resource_id, - }; - const calendar_id : _zeitbild.type_calendar_id = await _zeitbild.service.calendar.add( - calendar_object - ); - track.calendar[calendar_raw.id] = calendar_id; - } - return Promise.resolve(undefined); -} - - /** */ async function main( @@ -227,8 +69,8 @@ async function main( "description": "conf-expose" }, { - "name": "fill", - "description": "fill" + "name": "sample", + "description": "sample" }, { "name": "help", @@ -417,9 +259,9 @@ async function main( ); break; } - case "fill": + case "sample": { - await data_init( + await _zeitbild.sample.init( lib_plankton.json.decode( await lib_plankton.file.read(args.data_path) ) diff --git a/source/sample.ts b/source/sample.ts new file mode 100644 index 0000000..8002e8c --- /dev/null +++ b/source/sample.ts @@ -0,0 +1,336 @@ +/* +This file is part of »zeitbild«. + +Copyright 2025 'kcf' + +»zeitbild« is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +»zeitbild« 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »zeitbild«. If not, see . + */ + + +namespace _zeitbild.sample +{ + + /** + */ + type type_date_absolute = { + year : int; + month : int; + day : int; + }; + + + /** + */ + type type_date_relative = Array< + { + action : "trunc_week"; + args : [int]; + } + | + { + action : "shift_week"; + args : [int]; + } + | + { + action : "shift_day"; + args : [int]; + } + >; + + + /** + */ + type type_ywd = { + year : int; + week : int; + day : int; + }; + + + /** + */ + type type_time = { + hour : int; + minute : int; + second : int; + }; + + + /** + */ + type type_datetime = ( + { + timezone_shift : int; + time : (null | type_time); + } + & + ( + { + date_absolute : type_date_absolute; + } + | + { + date_relative : type_date_relative; + } + ) + ); + + + /** + */ + type type_data = { + users : Array< + { + id : int; + name : string; + email_address : string; + dav_token : (null | string); + password : string; + } + >; + calendars : Array< + { + id : int; + name : string; + access : { + public ?: boolean; + default_level : ("none" | "view" | "edit" | "admin"); + attributed : Array< + { + user_id : int; + level : ("none" | "view" | "edit" | "admin"); + } + >; + }; + resource : ( + { + kind : "local"; + data : { + events : Array< + { + /** + * @todo rename to "title" + */ + name : string; + begin : type_datetime; + end : ( + null + | + type_datetime + ); + location : ( + null + | + string + ); + link : ( + null + | + string + ); + description : ( + null + | + string + ); + } + > + }; + } + | + { + kind : "ics_feed"; + data : { + url : string; + from_fucked_up_wordpress ?: boolean; + }; + } + ); + } + >; + }; + + + /** + */ + function decode_datetime( + datetime : type_datetime + ) : lib_plankton.pit.type_datetime + { + if ("date_relative" in datetime) + { + return { + "timezone_shift": datetime.timezone_shift, + "date": lib_plankton.call.convey( + lib_plankton.pit.now(), + ( + datetime.date_relative.map<(x : any) => any>( + entry => { + switch (entry.action) + { + // default: {throw (new Error("unhandled action: " + entry.action));} + case "trunc_week": {return (x => lib_plankton.pit.trunc_week(x));} + case "shift_week": {return (x => lib_plankton.pit.shift_week(x, entry.args[0]));} + case "shift_day": {return (x => lib_plankton.pit.shift_day(x, entry.args[0]));} + } + } + ) + .concat( + [ + lib_plankton.pit.to_datetime, + x => x.date, + ] + ) + ) + ), + "time": datetime.time, + }; + } + else + { + return { + "timezone_shift": datetime.timezone_shift, + "date": datetime.date_absolute, + "time": datetime.time, + }; + } + } + + + /** + */ + export async function init( + data : type_data + ) : Promise + { + let track : { + user : Record< + int, + _zeitbild.type_user_id + >; + calendar : Record< + int, + _zeitbild.type_user_id + >; + } = { + "user": {}, + "calendar": {}, + }; + for await (const user_raw of data.users) + { + const user_object : _zeitbild.type_user_object = { + "name": user_raw.name, + "email_address": user_raw.email_address, + "dav_token": user_raw.dav_token, + }; + const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.add( + user_object + ); + await _zeitbild.service.auth_internal.set( + user_raw.name, + user_raw.password + ); + track.user[user_raw.id] = user_id; + } + for await (const calendar_raw of data.calendars) + { + let resource_object : _zeitbild.type_resource_object; + let resource_id : _zeitbild.type_resource_id; + switch (calendar_raw.resource.kind) + { + case "local": + { + resource_object = { + "kind": "local", + "data": { + "event_ids": [], + } + }; + resource_id = await _zeitbild.service.resource.add( + resource_object + ); + /*const event_ids : Array<_zeitbild.type_local_resource_event_id> = */await Promise.all( + calendar_raw.resource.data.events + .map( + (event_raw) => { + const event : _zeitbild.type_event_object = { + "name": event_raw.name, + "begin": decode_datetime(event_raw.begin), + "end": ( + (event_raw.end === null) + ? + null + : + decode_datetime(event_raw.end) + ), + "location": event_raw.location, + "link": event_raw.link, + "description": event_raw.description, + }; + return _zeitbild.service.resource.event_add(resource_id, event); + } + ) + ); + break; + } + case "ics_feed": + { + resource_object = { + "kind": "ics_feed", + "data": { + "url": calendar_raw.resource.data.url, + "from_fucked_up_wordpress": (calendar_raw.resource.data.from_fucked_up_wordpress ?? false), + } + }; + resource_id = await _zeitbild.service.resource.add( + resource_object + ); + break; + } + } + const calendar_object : _zeitbild.type_calendar_object = + { + "name": calendar_raw.name, + "access": { + "public": (calendar_raw.access.public ?? false), + "default_level": _zeitbild.value_object.access_level.from_string(calendar_raw.access.default_level), + "attributed": lib_plankton.map.hashmap.implementation_map( + lib_plankton.map.hashmap.make( + x => x.toFixed(0), + { + "pairs": ( + calendar_raw.access.attributed + .map( + (entry) => ({ + "key": track.user[entry.user_id], + "value": _zeitbild.value_object.access_level.from_string(entry.level), + }) + ) + ), + } + ) + ), + }, + "resource_id": resource_id, + }; + const calendar_id : _zeitbild.type_calendar_id = await _zeitbild.service.calendar.add( + calendar_object + ); + track.calendar[calendar_raw.id] = calendar_id; + } + return Promise.resolve(undefined); + } + +} diff --git a/source/types.ts b/source/types.ts index 023f787..d1f1b84 100644 --- a/source/types.ts +++ b/source/types.ts @@ -58,6 +58,9 @@ namespace _zeitbild /** */ export type type_event_object = { + /** + * @todo rename to "title" + */ name : string; begin : lib_plankton.pit.type_datetime; end : ( diff --git a/tools/makefile b/tools/makefile index ce88995..9866701 100644 --- a/tools/makefile +++ b/tools/makefile @@ -80,6 +80,7 @@ ${dir_temp}/zeitbild-unlinked.js: \ ${dir_source}/api/actions/events.ts \ ${dir_source}/api/actions/export_ics.ts \ ${dir_source}/api/functions.ts \ + ${dir_source}/sample.ts \ ${dir_source}/main.ts @ ${cmd_log} "compile …" @ ${cmd_mkdir} $(dir $@)