namespace _zeitbild.service.calendar { /** */ export function add( calendar_object : _zeitbild.type_calendar_object ) : Promise<_zeitbild.type_calendar_id> { return _zeitbild.repository.calendar.create(calendar_object); } /** */ export async function list( search_term : (null | string) ) : Promise< Array< { id : _zeitbild.type_calendar_id; preview : { name : string; } } > > { return ( _zeitbild.repository.calendar.list(search_term) .then( x => x.map( (y : any) => ({ "id": y.key, "preview": y.preview, }) ) ) ); } /** */ export function overview( user_id : _zeitbild.type_user_id ) : Promise< Array< { id : _zeitbild.type_calendar_id; name : string; access_level : _zeitbild.enum_access_level; } > > { return _zeitbild.repository.calendar.overview(user_id); } /** */ export async function get( calendar_id : _zeitbild.type_calendar_id ) : Promise<_zeitbild.type_calendar_object> { return _zeitbild.repository.calendar.read(calendar_id); } /** * checks if a user has a sufficient access level */ function wrap_check_access_level( calendar_object : _zeitbild.type_calendar_object, user_id : _zeitbild.type_user_id, threshold : _zeitbild.enum_access_level, success_handler : ( (access_level : _zeitbild.enum_access_level) => Promise ) ) : Promise { const access_level : _zeitbild.enum_access_level = calendar_object.access.attributed.get( user_id, lib_plankton.pod.make_filled<_zeitbild.enum_access_level>( calendar_object.access.default_level ) ); if (! _zeitbild.value_object.access_level.order(threshold, access_level)) { return Promise.reject( new Error( lib_plankton.string.coin( "insufficient access level; at least required: {{threshold}}, actual: {{actual}}", { "threshold": _zeitbild.value_object.access_level.to_string(threshold), "actual": _zeitbild.value_object.access_level.to_string(access_level), } ) ) ); } else { return success_handler(access_level); } } /** */ export async function event_get( calendar_id : _zeitbild.type_calendar_id, local_resource_event_id : _zeitbild.type_local_resource_event_id, user_id : _zeitbild.type_user_id ) : Promise<_zeitbild.type_event_object> { const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read( calendar_id ); return wrap_check_access_level<_zeitbild.type_event_object>( calendar_object, user_id, _zeitbild.enum_access_level.view, async () => { const event_object : _zeitbild.type_event_object = await _zeitbild.service.resource.event_get( calendar_object.resource_id, local_resource_event_id ); return Promise.resolve<_zeitbild.type_event_object>(event_object); } ); } /** */ export async function event_add( calendar_id : _zeitbild.type_calendar_id, event_object : _zeitbild.type_event_object, user_id : _zeitbild.type_user_id ) : Promise { const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read( calendar_id ); return wrap_check_access_level( calendar_object, user_id, _zeitbild.enum_access_level.edit, async () => { /*const event_id : _zeitbild.type_local_resource_event_id = */await _zeitbild.service.resource.event_add( calendar_object.resource_id, event_object ); return Promise.resolve(undefined); } ); } /** */ export async function event_change( calendar_id : _zeitbild.type_calendar_id, local_resource_event_id : _zeitbild.type_local_resource_event_id, event_object : _zeitbild.type_event_object, user_id : _zeitbild.type_user_id ) : Promise { const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read( calendar_id ); return wrap_check_access_level( calendar_object, user_id, _zeitbild.enum_access_level.edit, async () => { await _zeitbild.service.resource.event_change( calendar_object.resource_id, local_resource_event_id, event_object ); return Promise.resolve(undefined); } ); } /** */ export async function event_remove( calendar_id : _zeitbild.type_calendar_id, local_resource_event_id : _zeitbild.type_local_resource_event_id, user_id : _zeitbild.type_user_id ) : Promise { const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read( calendar_id ); return wrap_check_access_level( calendar_object, user_id, _zeitbild.enum_access_level.edit, async () => { await _zeitbild.service.resource.event_remove( calendar_object.resource_id, local_resource_event_id ); return Promise.resolve(undefined); } ); } /** */ async function get_events( calendar_id : _zeitbild.type_calendar_id, from_pit : lib_plankton.pit.type_pit, to_pit : lib_plankton.pit.type_pit, user_id : _zeitbild.type_user_id ) : Promise< Array< { id : (null | _zeitbild.type_local_resource_event_id); object : _zeitbild.type_event_object; } > > { const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(calendar_id); return wrap_check_access_level>( calendar_object, user_id, _zeitbild.enum_access_level.view, async () => { const resource_object : _zeitbild.type_resource_object = await _zeitbild.repository.resource.read(calendar_object.resource_id); switch (resource_object.kind) { case "local": { return ( Promise.all( resource_object.data.event_ids .map( (event_id) => ( _zeitbild.repository.resource.local_resource_event_read( calendar_object.resource_id, event_id ) .then( (event_object) => Promise.resolve( { "id": event_id, "object": event_object, } ) ) ) ) ) .then( (event_entries) => Promise.resolve( event_entries .filter( (event_entry : {id : (null | _zeitbild.type_local_resource_event_id); object : _zeitbild.type_event_object;}) => lib_plankton.pit.is_between( lib_plankton.pit.from_datetime(event_entry.object.begin), from_pit, to_pit ) ) ) ) ); break; } case "caldav": { // TODO readonly const url : lib_plankton.url.type_url = lib_plankton.url.decode( resource_object.data.url ); const http_request : lib_plankton.http.type_request = { "version": "HTTP/2", "scheme": ((url.scheme === "https") ? "https" : "http"), "host": url.host, "path": (url.path ?? "/"), "query": url.query, "method": lib_plankton.http.enum_method.get, "headers": {}, "body": null, }; // TODO: cache? const http_response : lib_plankton.http.type_response = await lib_plankton.http.call( http_request, { } ); const vcalendar : lib_plankton.ical.type_vcalendar = lib_plankton.ical.ics_decode( http_response.body.toString(), { } ); return Promise.resolve( vcalendar.vevents .map( (vevent : lib_plankton.ical.type_vevent) => ( (vevent.dtstart !== undefined) ? { "name": ( (vevent.summary !== undefined) ? vevent.summary : "???" ), "begin": _zeitbild.helpers.ical_dt_to_own_datetime(vevent.dtstart), "end": ( (vevent.dtend !== undefined) ? _zeitbild.helpers.ical_dt_to_own_datetime(vevent.dtend) : null ), "location": ( (vevent.location !== undefined) ? vevent.location : null ), "description": ( (vevent.description !== undefined) ? vevent.description : null ), } : null ) ) .filter( (event) => (event !== null) ) .map( (event) => ({ "id": null, "object": event, }) ) .filter( (event_entry) => lib_plankton.pit.is_between( lib_plankton.pit.from_datetime(event_entry.object.begin), from_pit, to_pit ) ) ); break; } default: { return Promise.reject( new Error("invalid resource kind: " + resource_object["kind"]) ); break; } } } ); } /** * @todo check access level */ export async function gather_events( calendar_ids_wanted : (null | Array<_zeitbild.type_calendar_id>), from_pit : lib_plankton.pit.type_pit, to_pit : lib_plankton.pit.type_pit, user_id : _zeitbild.type_user_id ) : Promise< Array< { calendar_id : _zeitbild.type_calendar_id; calendar_name : string; event_id : (null | _zeitbild.type_local_resource_event_id); event_object : _zeitbild.type_event_object; } > > { const calendar_ids_allowed : Array<_zeitbild.type_calendar_id> = ( (await overview(user_id)) .map((x : any) => x.id) ); // use set intersection 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) ) ) ) ); calendar_ids.sort(); return ( Promise.all( calendar_ids .map( async (calendar_id) => { const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read( calendar_id ); const events : Array< { id : (null | _zeitbild.type_local_resource_event_id); object : _zeitbild.type_event_object; } > = await get_events( calendar_id, from_pit, to_pit, user_id ); return Promise.resolve( events .map( (event_entry) => ({ "calendar_id": calendar_id, "calendar_name": calendar_object.name, "event_id": event_entry.id, "event_object": event_entry.object, }) ) ); } ) ) .then( (sub_results) => sub_results.reduce( (x, y) => x.concat(y), [] ) ) ); } }