From 9eab32d5731ffda221f8eaff2ef3f538a8c952b9 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Fri, 6 Dec 2024 15:52:22 +0100 Subject: [PATCH] [task-192] [int ] --- lib/plankton/plankton.d.ts | 60 +++-- lib/plankton/plankton.js | 35 +++ source/api/actions/caldav_get.ts | 10 +- source/services/caldav.ts | 430 +++++++++++++++---------------- 4 files changed, 301 insertions(+), 234 deletions(-) diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 42b9f20..b821fba 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -524,25 +524,25 @@ declare namespace lib_plankton.call { * @param {Object} args * @author fenris */ - function args2list(args: any): Array; + export function args2list(args: any): Array; /** * just the empty function; useful for some callbacks etc. * * @author fenris */ - function nothing(): void; + export function nothing(): void; /** * just the identity; useful for some callbacks etc.; defined as function instead of const for using type parameters * * @author fenris */ - function id(x: type_value): type_value; + export function id(x: type_value): type_value; /** * just the identity; useful for some callbacks etc. * * @author fenris */ - function const_(x: type_value): ((y: any) => type_value); + export function const_(x: type_value): ((y: any) => type_value); /** * composes two functions (i.e. returns a function that return the result of the successive execution of both input-functions) * @@ -550,7 +550,7 @@ declare namespace lib_plankton.call { * @param {function} function_g * @author fenris */ - function compose(function_f: ((type_x: any) => type_y), function_g: ((type_y: any) => type_z)): ((value: type_x) => type_z); + export function compose(function_f: ((type_x: any) => type_y), function_g: ((type_y: any) => type_z)): ((value: type_x) => type_z); /** * transforms a function with sequential input to a function with leveled input; example: add(2,3) = curryfy(add)(2)(3) * @@ -558,27 +558,46 @@ declare namespace lib_plankton.call { * @return {function} the currified version of the in put function * @author fenris */ - function curryfy(f: Function): Function; + export function curryfy(f: Function): Function; /** * @author fenris */ - function convey(value: any, functions: Array): any; + export function convey(value: any, functions: Array): any; + /** + */ + class class_value_wrapper { + /** + */ + private value; + /** + */ + constructor(value: type_value); + /** + */ + convey(function_: ((value: type_value) => type_value_result)): class_value_wrapper; + /** + */ + cull(): type_value; + } + /** + */ + export function wrap(value: type_value): class_value_wrapper; /** * @author fenris */ - function timeout(procedure: (() => void), delay_in_seconds: float): int; + export function timeout(procedure: (() => void), delay_in_seconds: float): int; /** * Promise version of "setTimeout" * * @author fenris */ - function defer(seconds: float, action: (() => type_result)): Promise; + export function defer(seconds: float, action: (() => type_result)): Promise; /** * a definition for a value being "defined" * * @author neuc */ - function is_def(obj: type_value, options?: { + export function is_def(obj: type_value, options?: { null_is_valid?: boolean; }): boolean; /** @@ -586,7 +605,7 @@ declare namespace lib_plankton.call { * * @author neuc */ - function def_val(value: any, default_value: any, options?: { + export function def_val(value: any, default_value: any, options?: { type?: (null | string); null_is_valid?: boolean; }): any; @@ -597,7 +616,7 @@ declare namespace lib_plankton.call { * @return {function} * @author fenris */ - function attribute(name: string): ((object: type_object) => type_attribute); + export function attribute(name: string): ((object: type_object) => type_attribute); /** * provides a method of a class as a regular function; useful for processing lists of objects * @@ -605,32 +624,33 @@ declare namespace lib_plankton.call { * @return {function} * @author fenris */ - function method(name: string): ((object: type_object) => type_output); + export function method(name: string): ((object: type_object) => type_output); /** * @author fenris */ - type type_coproduct = { + export type type_coproduct = { kind: string; data?: any; }; /** * @author fenris */ - function distinguish(coproduct: type_coproduct, handlers: Record type_output)>, options?: { + export function distinguish(coproduct: type_coproduct, handlers: Record type_output)>, options?: { fallback?: (null | ((coproduct?: type_coproduct) => type_output)); }): type_output; /** */ - function try_catch_wrap(get_value: (() => type_value)): { + export function try_catch_wrap(get_value: (() => type_value)): { value: (null | type_value); error: (null | any); }; /** */ - function try_catch_wrap_async(get_value: (() => Promise)): Promise<{ + export function try_catch_wrap_async(get_value: (() => Promise)): Promise<{ value: (null | type_value); error: (null | any); }>; + export {}; } declare namespace lib_plankton.email { /** @@ -3792,6 +3812,12 @@ declare namespace lib_plankton.webdav { } | { kind: "privileges"; data: Array; + } | { + kind: "component_set"; + data: { + name: string; + items: Array; + }; }); /** * @see http://www.webdav.org/specs/rfc2518.html#ELEMENT_prop diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 865d6e3..312e5f4 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -1298,6 +1298,31 @@ var lib_plankton; return result; } call.convey = convey; + /** + */ + class class_value_wrapper { + /** + */ + constructor(value) { + this.value = value; + } + /** + */ + convey(function_) { + return (new class_value_wrapper(function_(this.value))); + } + /** + */ + cull() { + return this.value; + } + } + /** + */ + function wrap(value) { + return (new class_value_wrapper(value)); + } + call.wrap = wrap; /** * @author fenris */ @@ -13479,6 +13504,16 @@ var lib_plankton; } }, ]), + "component_set": ({ "name": name, "items": items }) => (items.map(item => ({ + "kind": "complex", + "data": { + "tag": "C:comp", + "attributes": { + "name": item + }, + "children": [] + } + }))), }) } }; diff --git a/source/api/actions/caldav_get.ts b/source/api/actions/caldav_get.ts index 28c35aa..24ba886 100644 --- a/source/api/actions/caldav_get.ts +++ b/source/api/actions/caldav_get.ts @@ -185,13 +185,21 @@ namespace _zeitbild.api "value": { "kind": "primitive", "data": lib_plankton.ical.ics_encode( + /* { "version": "2.0", "prodid": "zeitbild", "vevents": [], "method": "publish", } - ), + */ + _zeitbild.helpers.ical_vcalendar_from_own_event_list( + data + .map( + entry => entry.event_object + ) + ) + ) } }, ], diff --git a/source/services/caldav.ts b/source/services/caldav.ts index 208ce1f..f74d29a 100644 --- a/source/services/caldav.ts +++ b/source/services/caldav.ts @@ -2,6 +2,162 @@ namespace _zeitbild.service.caldav { + /** + */ + function get_answers( + ) : Record< + string, + (stuff : any) => lib_plankton.webdav.type_data_prop_value + > + { + return { + // RFC2518 + + /** + * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.2 + */ + "displayname": (stuff) => ({ + "kind": "primitive", + "data": stuff["name"] + }), + /** + * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.4 + */ + /* + "getcontentlength": { + "kind": "none", + "data": null + }, + */ + /** + * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.5 + */ + "getcontenttype": (stuff) => ({ + "kind": "primitive", + "data": stuff["content_type"] + }), + /** + * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.7 + */ + /* + "getlastmodified": { + "kind": "none", + "data": null + }, + */ + /** + * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.9 + */ + "resourcetype": (stuff) => ({ + "kind": "resourcetype", + "data": { + "kind": "collection", + "type": "calendar", + } + }), + + // RFCP3744 + + /** + * @see https://datatracker.ietf.org/doc/html/rfc3744#section-4.2 + */ + "principal-url": (stuff) => ({ + "kind": "href", + "data": "/caldav" + }), + /** + * @see https://datatracker.ietf.org/doc/html/rfc3744#section-5.1 + */ + "owner": (stuff) => ({ + "kind": "primitive", + "data": "" + }), + /** + * @see https://datatracker.ietf.org/doc/html/rfc3744#section-5.4 + */ + "current-user-privilege-set": (stuff) => ({ + "kind": "privileges", + "data": [ + "read" + ] + }), + + // RFC4791 + + /** + * @see https://datatracker.ietf.org/doc/html/rfc4791#section-5.2.3 + */ + "supported-calendar-component-set": (stuff) => ({ + "kind": "component_set", + "data": { + "name": "C:supported-calendar-component-set", + "items": [ + "VCALENDAR" + ] + } + }), + /** + * @see https://datatracker.ietf.org/doc/html/rfc4791#section-6.2.1 + */ + "calendar-home-set": (stuff) => ({ + "kind": "href", + "data": "/caldav/project" + }), + + // RFC4918 + + /** + * @see https://datatracker.ietf.org/doc/html/rfc4918#section-15.6 + */ + "getetag": (stuff) => ({ + "kind": "primitive", + "data": "" + }), + + // RFC5397 + + /** + * @see https://datatracker.ietf.org/doc/html/rfc5397#section-3 + */ + "current-user-principal": (stuff) => ({ + "kind": "href", + "data": "/caldav" + }), + + // RFC6638 + + /** + * @see https://datatracker.ietf.org/doc/html/rfc6638#section-2.4.1 + */ + "calendar-user-address-set": (stuff) => ({ + "kind": "primitive", + "data": "" + }), + + // unknown + + /* + "calendar-color": { + "kind": "none", + "data": null + }, + "executable": { + "kind": "none", + "data": null + }, + "checked-in": { + "kind": "none", + "data": null + }, + "checked-out": { + "kind": "none", + "data": null + }, + */ + }; + } + + /** * @todo use pod for output * @todo get api paths in props from config @@ -76,149 +232,8 @@ namespace _zeitbild.service.caldav else { const answers : Record< string, - lib_plankton.webdav.type_data_prop_value - > = { - // RFC2518 - - /** - * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.2 - */ - "displayname": { - "kind": "primitive", - "data": "projects" - }, - /** - * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.4 - */ - /* - "getcontentlength": { - "kind": "none", - "data": null - }, - */ - /** - * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.5 - */ - /* - "getcontenttype": { - "kind": "none", - "data": null - }, - */ - /** - * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.7 - */ - /* - "getlastmodified": { - "kind": "none", - "data": null - }, - */ - /** - * @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.9 - */ - "resourcetype": { - "kind": "resourcetype", - "data": { - "kind": "collection", - "type": "calendar", - } - }, - - // RFCP3744 - - /** - * @see https://datatracker.ietf.org/doc/html/rfc3744#section-4.2 - */ - "principal-url": { - "kind": "href", - "data": "/caldav" - }, - /** - * @see https://datatracker.ietf.org/doc/html/rfc3744#section-5.1 - */ - "owner": { - "kind": "primitive", - "data": "" - }, - /** - * @see https://datatracker.ietf.org/doc/html/rfc3744#section-5.4 - */ - "current-user-privilege-set": { - "kind": "privileges", - "data": [ - "read" - ] - }, - - // RFC4791 - - /** - * @see https://datatracker.ietf.org/doc/html/rfc4791#section-5.2.3 - */ - "supported-calendar-component-set": { - "kind": "primitive", - "data": "VEVENT" - }, - /** - * @see https://datatracker.ietf.org/doc/html/rfc4791#section-6.2.1 - */ - "calendar-home-set": { - "kind": "href", - "data": "/caldav/project" - }, - - // RFC4918 - - /** - * @see https://datatracker.ietf.org/doc/html/rfc4918#section-15.6 - */ - "getetag": { - "kind": "primitive", - "data": "" - }, - - // RFC5397 - - /** - * @see https://datatracker.ietf.org/doc/html/rfc5397#section-3 - */ - "current-user-principal": { - "kind": "href", - "data": "/caldav" - }, - - // RFC6638 - - /** - * @see https://datatracker.ietf.org/doc/html/rfc6638#section-2.4.1 - */ - "calendar-user-address-set": { - "kind": "primitive", - "data": "" - }, - - // unknown - - /* - "calendar-color": { - "kind": "none", - "data": null - }, - "executable": { - "kind": "none", - "data": null - }, - "checked-in": { - "kind": "none", - "data": null - }, - "checked-out": { - "kind": "none", - "data": null - }, - */ - }; + (stuff : any) => lib_plankton.webdav.type_data_prop_value + > = get_answers(); return { "kind": "root", "data": { @@ -253,7 +268,7 @@ namespace _zeitbild.service.caldav return { "name": prop, "value": ( - answers[prop_normalized] + answers[prop_normalized]({"name": "projects", "content_type": "text/xml"}) ?? { "kind": "none", @@ -306,7 +321,7 @@ namespace _zeitbild.service.caldav "prop": [ { "name": prop, - "value": answers[prop_normalized], + "value": answers[prop_normalized]({"name": "projects", "content_type": "text/xml"}), }, ], "status": (http_protocol + " 200 OK"), @@ -339,20 +354,8 @@ namespace _zeitbild.service.caldav { const answers : Record< string, - ((stuff : any) => lib_plankton.webdav.type_data_prop_value) - > = { - "displayname": (stuff) => ({ - "kind": "primitive", - "data": stuff["name"] - }), - "resourcetype": () => ({ - "kind": "resourcetype", - "data": { - "kind": "collection", - "type": "calendar", - } - }), - }; + (stuff : any) => lib_plankton.webdav.type_data_prop_value + > = get_answers(); /** * @todo remove */ @@ -431,67 +434,62 @@ namespace _zeitbild.service.caldav } ), "body": { - /* - "propstats": [ - { - "prop": [ - { - "name": "D:displayname", - "value": { - "kind": "primitive", - "data": entry.name, - }, - }, - { - "name": "D:resourcetype", - "value": { - "kind": "resourcetype", - "data": { - "kind": "collection", - "type": "calendar", - } - } - }, - ], - "status": "HTTP/1.1 200 OK", - "description": null, - } - ], - */ - "propstats": props.map( - prop => { - const prop_parts : Array = prop.toLowerCase().split(":"); - const prop_normalized : string = ((prop_parts.length <= 1) ? prop_parts[0] : prop_parts.slice(1).join(":")); - return ( - (! (prop_normalized in answers)) - ? - { - "prop": [ + "propstats": ( + lib_plankton.call.wrap>(props) + .convey>( + (props_raw) => props_raw.map( + (prop_raw) => { + const prop_parts : Array = prop_raw.toLowerCase().split(":"); + const prop_normalized : string = ((prop_parts.length <= 1) ? prop_parts[0] : prop_parts.slice(1).join(":")); + return ( + (prop_normalized in answers) + ? { - "name": prop, - "value": { - "kind": "none", - "data": null + "found": true, + "prop": { + "name": prop_raw, + "value": answers[prop_normalized]({"name": entry.name, "content_type": "text/calendar"}), } - }, - ], - "status": "HTTP/1.1 200 OK", - "description": null, - } - : - { - "prop": [ + } + : { - "name": prop, - "value": answers[prop_normalized](entry), - }, - ], - "status": "HTTP/1.1 404 Not Found", - "description": null, + "found": false, + "prop": { + "name": prop_raw, + "value": {"kind": "none", "data": null} + } + } + ); } - ); - } - ) + ) + ) + .convey>>( + (props_transformed) => lib_plankton.list.group( + props_transformed, + (x, y) => (x.found === y.found) + ) + ) + .convey>( + (props_grouped) => props_grouped.map( + group => ( + group[0].found + ? + { + "prop": group.map(member => member.prop), + "status": "HTTP/1.1 200 OK", + "description": null, + } + : + { + "prop": group.map(member => member.prop), + "status": "HTTP/1.1 404 Not Found", + "description": null, + } + ) + ) + ) + .cull() + ), }, "description": null, })