From 7c7bb3f66a928713d5348a0b797c2d3f585dc87f Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 12 Sep 2024 20:42:06 +0200 Subject: [PATCH] [mod] --- source/api/actions/calendar_list.ts | 41 +- source/api/actions/events.ts | 130 +++--- source/backend.ts | 6 - source/main.ts | 2 +- source/repositories/calendar.ts | 12 +- source/services/calendar.ts | 29 +- source/view.ts | 696 ---------------------------- 7 files changed, 114 insertions(+), 802 deletions(-) delete mode 100644 source/backend.ts delete mode 100644 source/view.ts diff --git a/source/api/actions/calendar_list.ts b/source/api/actions/calendar_list.ts index 14bdd83..5e12c9d 100644 --- a/source/api/actions/calendar_list.ts +++ b/source/api/actions/calendar_list.ts @@ -13,17 +13,17 @@ namespace _zeitbild.api Array< { id : _zeitbild.type.calendar_id; - preview : { - name : string; - }; + name : string; + public : boolean; + role : (null | _zeitbild.type.role); } > >( rest_subject, lib_plankton.http.enum_method.get, - "/calendar/list", + "/calendars", { - "description": "listet alle Kalender auf", + "description": "listet alle verfügbaren Kalender auf", "query_parameters": [ ], "output_schema": () => ({ @@ -37,29 +37,30 @@ namespace _zeitbild.api "type": "number", "nullable": false, }, - "preview": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "nullable": false, - }, - }, - "required": [ - "name", - ] - } + "name": { + "type": "string", + "nullable": false, + }, + "public": { + "type": "boolean", + "nullable": false, + }, + "role": { + "type": "string", + "nullable": true, + }, }, "required": [ "id", - "preview", + "name", + "public", + "role", ], } }), "restriction": restriction_none, // TODO "execution": () => ( - _zeitbild.service.calendar.list(null) + _zeitbild.service.calendar.overview(2) // TODO: user_id .then( data => Promise.resolve({ "status_code": 200, diff --git a/source/api/actions/events.ts b/source/api/actions/events.ts index f12311d..f84dd08 100644 --- a/source/api/actions/events.ts +++ b/source/api/actions/events.ts @@ -21,44 +21,33 @@ namespace _zeitbild.api Array< { calendar_id : int; + calendar_name : string; event : _zeitbild.type.event_object; } > >( rest_subject, - lib_plankton.http.enum_method.post, + lib_plankton.http.enum_method.get, "/events", { "description": "stellt Veranstaltungen aus verschiedenen Kalendern zusammen", "query_parameters": [ - ], - "input_schema": () => ({ - "type": "object", - "nullable": false, - "additionalProperties": false, - "properties": { - "from": { - "type": "number", - "nullable": false, - }, - "to": { - "type": "number", - "nullable": false, - }, - "calendar_id": { - "type": "array", - "nullable": false, - "items": { - "type": "number", - "nullable": false - } - } + { + "name": "from", + "required": true, + "description": "UNIX timestamp", }, - "required": [ - "from", - "to", - ] - }), + { + "name": "to", + "required": true, + "description": "UNIX timestamp", + }, + { + "name": "calendar_ids", + "required": false, + "description": "comma separated", + }, + ], "output_schema": () => ({ "type": "array", "items": { @@ -105,50 +94,59 @@ namespace _zeitbild.api } }, "required": [ - "calendar_id", + "calendar_ids", + "calendar_name", "event", ], } }), "restriction": restriction_none, // TODO - "execution": (stuff) => { - if (stuff.input === null) { - return Promise.resolve({ - "status_code": 400, - "data": null, - }); - } - else { - return ( - ( - (stuff.input.calendar_ids !== null) - ? - Promise.resolve(stuff.input.calendar_ids) - : - ( - _zeitbild.service.calendar.overview(0) // TODO: user_id - .then( - (x : any) => x.map((y : any) => y.id) - ) - ) + "execution": async (stuff) => { + const from : _zeitbild.helpers.type_pit = parseInt(stuff.query_parameters["from"]); + const to : _zeitbild.helpers.type_pit = parseInt(stuff.query_parameters["to"]); + const calendar_ids_wanted : Array<_zeitbild.type.calendar_id> = ( + ( + ("calendar_ids" in stuff.query_parameters) + && + (stuff.query_parameters["calendar_ids"] !== null) + ) + ? + lib_plankton.call.convey( + stuff.query_parameters["calendar_ids"], + [ + (x : string) => x.split(","), + (x : Array) => x.map(parseInt), + (x : Array) => x.filter(y => (! isNaN(y))) + ] + ) + : + null + ); + const calendar_ids_allowed : Array<_zeitbild.type.calendar_id> = ( + (await _zeitbild.service.calendar.overview(0)) // TODO: user_id + .map((x : any) => x.id) + ); + const calendar_ids : Array<_zeitbild.type.calendar_id> = ( + (calendar_ids_wanted === null) + ? + calendar_ids_allowed + : + ( + calendar_ids_wanted + .filter( + (calendar_id) => calendar_ids_allowed.includes(calendar_id) ) - .then( - (calendar_ids : Array<_zeitbild.type.calendar_id>) => _zeitbild.service.calendar.gather_events( - calendar_ids, - // @ts-ignore - stuff.input.from, - // @ts-ignore - stuff.input.to - ) - ) - .then( - (data : any) => Promise.resolve({ - "status_code": 200, - "data": data, - }) - ) - ); - } + ) + ); + const data = await _zeitbild.service.calendar.gather_events( + calendar_ids, + from, + to + ); + return Promise.resolve({ + "status_code": 200, + "data": data, + }); } } ); diff --git a/source/backend.ts b/source/backend.ts deleted file mode 100644 index 332a099..0000000 --- a/source/backend.ts +++ /dev/null @@ -1,6 +0,0 @@ - -/** - */ -namespace _zeitbild.frontend.resources.backend -{ -} diff --git a/source/main.ts b/source/main.ts index f61b221..ad2ff7e 100644 --- a/source/main.ts +++ b/source/main.ts @@ -8,7 +8,7 @@ async function main( // init1 lib_plankton.log.conf_push( [ - lib_plankton.log.channel_make({"kind": "stdout", "data": {"threshold": "debug"}}), + lib_plankton.log.channel_make({"kind": "stdout", "data": {"threshold": "info"}}), ] ); diff --git a/source/repositories/calendar.ts b/source/repositories/calendar.ts index 84b94a3..af7561e 100644 --- a/source/repositories/calendar.ts +++ b/source/repositories/calendar.ts @@ -277,6 +277,7 @@ namespace _zeitbild.repository.calendar /** + * @todo sort for role, public and id */ export function overview( user_id : _zeitbild.type.user_id @@ -306,12 +307,21 @@ namespace _zeitbild.repository.calendar (row) => ({ "id": row["id"], "name": row["name"], - "public": row["public"], + "public": (row["public"] === 1), "role": row["role"], }) ) ) ) + /* + .then( + (entries) => Promise.resolve( + entries.toSorted( + (x, y) => (x + ) + ) + ) + */ ) } } diff --git a/source/services/calendar.ts b/source/services/calendar.ts index a787c4e..8dc9256 100644 --- a/source/services/calendar.ts +++ b/source/services/calendar.ts @@ -179,16 +179,16 @@ namespace _zeitbild.service.calendar /** - * @todo user id */ export async function gather_events( calendar_ids : Array<_zeitbild.type.calendar_id>, from_pit : _zeitbild.helpers.type_pit, - to_pit : _zeitbild.helpers.type_pit, + to_pit : _zeitbild.helpers.type_pit ) : Promise< Array< { calendar_id : _zeitbild.type.calendar_id; + calendar_name : string; event : _zeitbild.type.event_object; } > @@ -198,21 +198,26 @@ namespace _zeitbild.service.calendar Promise.all( calendar_ids .map( - (calendar_id) => get_events( - calendar_id, - from_pit, - to_pit - ) - .then( - (events) => Promise.resolve( - events.map( + async (calendar_id) => { + const calendar_object : _zeitbild.type.calendar_object = await _zeitbild.repository.calendar.read( + calendar_id + ); + const events : Array<_zeitbild.type.event_object> = await get_events( + calendar_id, + from_pit, + to_pit + ); + return Promise.resolve( + events + .map( (event) => ({ "calendar_id": calendar_id, + "calendar_name": calendar_object.name, "event": event, }) ) - ) - ) + ); + } ) ) .then( diff --git a/source/view.ts b/source/view.ts deleted file mode 100644 index 48db65c..0000000 --- a/source/view.ts +++ /dev/null @@ -1,696 +0,0 @@ - -/** - */ -namespace _zeitbild.frontend.view -{ - - /** - */ - function event_generate_tooltip( - calendar_name : string, - event : type_event - ) : string - { - return ( - lib_plankton.string.coin( - "[{{calendar_name}}] {{event_name}}\n", - { - "calendar_name": calendar_name, - "event_name": event.name, - } - ) - + - "--\n" - + - ( - (event.begin.time !== null) - ? - lib_plankton.string.coin( - "{{label}}: {{value}}\n", - { - "label": "Anfang", // TODO: translate - "value": lib_plankton.string.coin( - "{{hour}}:{{minute}}", - { - "hour": event.begin.time.hour.toFixed(0).padStart(2, "0"), - "minute": event.begin.time.minute.toFixed(0).padStart(2, "0"), - } - ), // TODO: outsource - } - ) - : - "" - ) - + - ( - (event.end !== null) - ? - lib_plankton.string.coin( - "{{label}}: {{value}}\n", - { - "label": "Ende", // TODO: translate - "value": ( - [ - ( - ( - (event.end.date.year !== event.begin.date.year) - || - (event.end.date.month !== event.begin.date.month) - || - (event.end.date.day !== event.begin.date.day) - ) - ? - lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": event.end.date.year.toFixed(0).padStart(4, "0"), - "month": event.end.date.month.toFixed(0).padStart(2, "0"), - "day": event.end.date.day.toFixed(0).padStart(2, "0"), - } - ) - : - null - ), - ( - (event.end.time !== null) - ? - lib_plankton.string.coin( - "{{hour}}:{{minute}}", - { - "hour": event.end.time.hour.toFixed(0).padStart(2, "0"), - "minute": event.end.time.minute.toFixed(0).padStart(2, "0"), - } - ) - : - null - ), - ] - .filter(x => (x !== null)) - .join(",") - ), - } - ) - : - "" - ) - + - ( - (event.location !== null) - ? - ( - lib_plankton.string.coin( - "{{label}}: {{value}}\n", - { - "label": "Ort", // TODO - "value": event.location, - } - ) - ) - : - "" - ) - + - ( - (event.description !== null) - ? - ( - "--\n" - + - lib_plankton.string.coin( - "{{description}}\n", - { - "description": event.description, - } - ) - ) - : - "" - ) - ); - } - - - /** - * @todo kein "while" - */ - async function calendar_view_table_data( - calendar_ids : Array, - options : { - from ?: { - year : int; - week : int; - }, - to ?: { - year : int; - week : int; - }, - timezone_shift ?: int; - } = {} - ) : Promise< - { - sources : lib_plankton.structures.type_hashmap< - type_calendar_id, - { - name : string; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : _zeitbild.frontend.helpers.type_pit; - entries : Array< - { - calendar_id : type_calendar_id; - event : type_event; - } - >; - today : boolean; - } - >; - } - > - } - > - { - const now_pit : _zeitbild.frontend.helpers.type_pit = _zeitbild.frontend.helpers.pit_now(); - options = Object.assign( - { - "from": lib_plankton.call.convey( - now_pit, - [ - (x : _zeitbild.frontend.helpers.type_pit) => _zeitbild.frontend.helpers.pit_shift_week(x, -1), - _zeitbild.frontend.helpers.pit_to_date_object, - (x : Date) => ({ - "year": x.getFullYear(), - "week": _zeitbild.frontend.helpers.date_object_get_week_of_year(x), - }) - ] - ), - "to": lib_plankton.call.convey( - now_pit, - [ - (x : _zeitbild.frontend.helpers.type_pit) => _zeitbild.frontend.helpers.pit_shift_week(x, +4), - _zeitbild.frontend.helpers.pit_to_date_object, - (x : Date) => ({ - "year": x.getFullYear(), - "week": _zeitbild.frontend.helpers.date_object_get_week_of_year(x), - }) - ] - ), - "timezone_shift": 0, - }, - options - ); - /* - const calendar_object : type_calendar_object = calendar_read( - data, - calendar_id - ); - */ - const from_pit : _zeitbild.frontend.helpers.type_pit = _zeitbild.frontend.helpers.pit_from_year_and_week( - (options.from as {year : int; week : int}).year, - (options.from as {year : int; week : int}).week, - { - "timezone_shift": (options.timezone_shift as int), - } - ); - const to_pit : _zeitbild.frontend.helpers.type_pit = _zeitbild.frontend.helpers.pit_from_year_and_week( - (options.to as {year : int; week : int}).year, - (options.to as {year : int; week : int}).week, - { - "timezone_shift": (options.timezone_shift as int), - } - ); - - // prepare - const entries : Array< - { - calendar_id : type_calendar_id; - calendar_name : string; - event : type_event; - } - > = await _zeitbild.frontend.resources.backend.calendar_gather_events( - calendar_ids, - from_pit, - to_pit - ); - let result : { - sources : lib_plankton.structures.type_hashmap< - type_calendar_id, - { - name : string; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : _zeitbild.frontend.helpers.type_pit; - entries : Array< - { - calendar_id : type_calendar_id; - event : type_event; - } - >; - today : boolean; - } - >; - } - >; - } = { - "sources": lib_plankton.structures.hashmap_construct( - x => x.toFixed(0), - ( - entries - .map( - (entry) => ( - { - "key": entry.calendar_id, - "value": { - "name": entry.calendar_name, - } - } - ) - ) - ) - ), - "rows": [], - }; - let row : Array< - { - pit : _zeitbild.frontend.helpers.type_pit; - entries : Array< - { - calendar_id : type_calendar_id; - event : type_event; - } - >; - today : boolean; - } - > = []; - let day : int = 0; - while (true) { - const pit_current : _zeitbild.frontend.helpers.type_pit = _zeitbild.frontend.helpers.pit_shift_day( - from_pit, - day - ); - if ( - _zeitbild.frontend.helpers.pit_is_before( - pit_current, - to_pit - ) - ) { - day += 1; - row.push( - { - "pit": pit_current, - "entries": [], - "today": false, // TODO - } - ); - if (day % 7 === 0) { - result.rows.push( - { - "week": ( - (options.from as {year : int; week : int}).week - + - Math.floor(day / 7) - - - 1 // TODO - ), - "data": row - } - ); - row = []; - } - else { - // do nothing - } - } - else { - break; - } - } - - // fill - { - // events - ( - entries - .forEach( - (entry) => { - const distance_seconds : int = ( - _zeitbild.frontend.helpers.pit_from_datetime(entry.event.begin) - - - from_pit - ); - const distance_days : int = (distance_seconds / (60 * 60 * 24)); - - const week : int = Math.floor(Math.floor(distance_days) / 7); - const day : int = (Math.floor(distance_days) % 7); - - if ((week >= 0) && (week < result.rows.length)) { - result.rows[week].data[day].entries.push(entry); - } - else { - // do nothing - } - } - ) - ); - // today - { - const distance_seconds : int = ( - now_pit - - - from_pit - ); - const distance_days : int = (distance_seconds / (60 * 60 * 24)); - - const week : int = Math.floor(Math.floor(distance_days) / 7); - const day : int = (Math.floor(distance_days) % 7); - - if ((week >= 0) && (week < result.rows.length)) { - result.rows[week].data[day].today = true; - } - else { - // do nothing - } - } - } - - return Promise.resolve(result); - } - - - /** - */ - export async function calendar_view_table_html( - calendar_ids : Array, - options : { - from ?: { - year : int; - week : int; - }; - to ?: { - year : int; - week : int; - }; - timezone_shift ?: int; - } = {} - ) : Promise - { - const stuff : { - sources : lib_plankton.structures.type_hashmap< - type_calendar_id, - { - name : string; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : _zeitbild.frontend.helpers.type_pit; - entries : Array< - { - calendar_id : type_calendar_id; - event : type_event; - } - >; - today : boolean; - } - >; - } - >; - } = await calendar_view_table_data( - calendar_ids, - options - ); - const sources : lib_plankton.structures.type_hashmap< - type_calendar_id, - { - name : string; - color : lib_plankton.color.type_color; - } - > = lib_plankton.structures.hashmap_construct( - (x => x.toFixed(0)), - lib_plankton.structures.hashmap_dump( - stuff.sources - ) - .map( - (pair) => ({ - "key": pair.key, - "value": { - "name": pair.value.name, - "color": lib_plankton.color.give_generic( - (pair.key - 1), - { - "saturation": 0.375, - "value": 0.375, - } - ), - } - }) - ) - ); - return _zeitbild.frontend.helpers.template_coin( - "tableview", - { - "sources": ( - await _zeitbild.frontend.helpers.promise_row( - lib_plankton.structures.hashmap_dump(sources) - .map( - ({"key": calendar_id, "value": data}) => async () => _zeitbild.frontend.helpers.template_coin( - "tableview-sources-entry", - { - "name": data.name, - "color": lib_plankton.color.output_hex(data.color), - "rel": calendar_id.toFixed(0), - } - ) - ) - ) - ).join(""), - "rows": ( - await _zeitbild.frontend.helpers.promise_row( - stuff.rows - .map( - (row) => async () => _zeitbild.frontend.helpers.template_coin( - "tableview-row", - { - "week": row.week.toFixed(0).padStart(2, "0"), - "cells": ( - await _zeitbild.frontend.helpers.promise_row( - row.data - .map( - (cell) => async () => _zeitbild.frontend.helpers.template_coin( - "tableview-cell", - { - "extra_classes": ( - [""] - .concat(cell.today ? ["calendar-cell-today"] : []) - .join(" ") - ), - "title": lib_plankton.call.convey( - cell.pit, - [ - _zeitbild.frontend.helpers.pit_to_datetime, - (x : _zeitbild.frontend.helpers.type_datetime) => lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ), - ] - ), - "day": lib_plankton.call.convey( - cell.pit, - [ - _zeitbild.frontend.helpers.pit_to_datetime, - (x : _zeitbild.frontend.helpers.type_datetime) => lib_plankton.string.coin( - "{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ), - ] - ), - "entries": ( - await _zeitbild.frontend.helpers.promise_row( - cell.entries - .map( - (entry) => () => _zeitbild.frontend.helpers.template_coin( - "tableview-cell-entry", - { - "color": lib_plankton.color.output_hex( - lib_plankton.structures.hashmap_get( - sources, - entry.calendar_id - ).color - ), - "title": event_generate_tooltip( - lib_plankton.structures.hashmap_get( - sources, - entry.calendar_id - ).name, - entry.event - ), - "name": entry.event.name, - } - ) - ) - ) - ).join(""), - } - ) - ) - ) - ).join(""), - } - ) - ) - ) - ).join(""), - } - ); - } - - - /** - */ - async function calendar_view_list_data( - calendar_ids : Array, - options : { - from ?: _zeitbild.frontend.helpers.type_pit; - to ?: _zeitbild.frontend.helpers.type_pit; - timezone_shift ?: int; - } = {} - ) : Promise< - Array< - { - calendar_id : type_calendar_id; - event : type_event; - } - > - > - { - const now_pit : _zeitbild.frontend.helpers.type_pit = _zeitbild.frontend.helpers.pit_now(); - options = Object.assign( - { - "from": lib_plankton.call.convey( - now_pit, - [ - (x : _zeitbild.frontend.helpers.type_pit) => _zeitbild.frontend.helpers.pit_shift_day(x, -1), - ] - ), - "to": lib_plankton.call.convey( - now_pit, - [ - (x : _zeitbild.frontend.helpers.type_pit) => _zeitbild.frontend.helpers.pit_shift_week(x, +4), - ] - ), - "timezone_shift": 0, - }, - options - ); - - const entries : Array< - { - calendar_id : type_calendar_id; - event : type_event; - } - > = await _zeitbild.frontend.resources.backend.calendar_gather_events( - calendar_ids, - (options.from as _zeitbild.frontend.helpers.type_pit), - (options.to as _zeitbild.frontend.helpers.type_pit) - ); - // TODO: optimize - entries.sort( - (entry_1, entry_2) => ( - _zeitbild.frontend.helpers.pit_from_datetime(entry_1.event.begin) - - - _zeitbild.frontend.helpers.pit_from_datetime(entry_2.event.begin) - ) - ); - - return Promise.resolve(entries); - } - - - /** - */ - export async function calendar_view_list_html( - calendar_ids : Array, - options : { - from ?: _zeitbild.frontend.helpers.type_pit; - to ?: _zeitbild.frontend.helpers.type_pit; - timezone_shift ?: int; - } = {} - ) : Promise - { - const stuff : Array< - { - calendar_id : type_calendar_id; - event : type_event; - } - > = await calendar_view_list_data( - calendar_ids, - options - ); - return Promise.resolve( - new lib_plankton.xml.class_node_complex( - "div", - { - "class": "list", - }, - [ - new lib_plankton.xml.class_node_complex( - "style", - {}, - [ - new lib_plankton.xml.class_node_text( - "html {background-color: #111; color: #FFF; font-family: sans-serif;}\n" - + - "table {width: 100%; border-collapse: collapse;}\n" - ) - ] - ), - new lib_plankton.xml.class_node_complex( - "ul", - { - "class": "list-events", - }, - ( - stuff - .map( - (entry) => ( - new lib_plankton.xml.class_node_complex( - "li", - { - "class": "list-event_entry", - }, - [ - new lib_plankton.xml.class_node_text( - JSON.stringify(entry) - ), - ] - ) - ) - ) - ) - ), - ] - ).compile() - ); - } - -}