Compare commits

...

36 commits

Author SHA1 Message Date
fenris 9c91365f98 Merge branch 'main' into task-192 2025-09-25 17:03:36 +02:00
fenris 193a21277f Merge branch 'main' into task-192 2025-09-25 17:00:07 +02:00
fenris 8264936f21 Revert "[mod] data-example"
This reverts commit 8a9d552760.
2025-09-25 16:58:48 +02:00
fenris 8a9d552760 [mod] data-example 2025-09-25 16:56:08 +02:00
fenris 47319b9e10 [task-192] [res] 2025-09-25 16:54:20 +02:00
fenris 4b75e06057 [task-192] [res] 2025-09-25 16:49:14 +02:00
fenris a7a90e8ab8 Merge branch 'main' into task-192 2025-09-25 16:21:38 +02:00
fenris e46be87a99 [task-192] [upd] node 2025-09-25 16:19:30 +02:00
fenris 58791676e5 [task-192] [upd] node 2025-09-25 16:18:08 +02:00
fenris 74f79ae0b7 [add] api:user_dav_conf [add] api:user_dav_token [mod] conf:add caldav node 2025-09-25 16:07:41 +02:00
fenris a716cf6852 [mod] data-example 2025-09-25 16:06:45 +02:00
fenris e549d7b088 [mod] conf-example 2025-09-25 16:05:59 +02:00
fenris 31194c8c41 [mod] tools:update-plankton [upd] plankton 2025-09-25 16:05:30 +02:00
fenris 4e9f7f634d [mov] conf/example.json -> misc/conf-example.json 2025-09-25 12:16:03 +02:00
fenris bbfc07478f [task-192] [mod] DAV-Zeug entfernt 2025-09-22 01:16:54 +02:00
fenris 5afc562b18 [task-192] [int] 2025-09-09 21:19:59 +00:00
fenris 6309422429 [task-192] [upd] plankton 2025-09-09 21:18:33 +00:00
fenris 2683d49bba [task-192] [mod] data:example 2025-09-09 21:18:21 +00:00
fenris 1df1fa3ac9 [task-192] [fix] api:user_from_web_auth 2025-09-04 09:54:40 +00:00
fenris 5ab91664ed [task-192] caldav-API-Aktionen entfernen 2025-09-04 09:54:28 +00:00
fenris fc228fb274 [task-192] add log stuff 2025-09-04 09:53:18 +00:00
fenris 6ad47e1943 [task-192] [int] 2025-09-04 07:46:49 +00:00
fenris 00f416a126 [int] 2025-08-29 10:52:37 +00:00
fenris 64652af779 [res] 2024-12-09 21:40:07 +01:00
fenris 9eab32d573 [task-192] [int
]
2024-12-06 15:52:22 +01:00
fenris 2cb46cd485 [task-192] [int] 2024-12-01 15:21:20 +01:00
fenris 6f1437b55a [mod] api:caldav_get 2024-11-29 08:44:05 +01:00
fenris 8ddba38bd5 [task-192] [int] geht zum Teil 2024-11-28 23:08:24 +01:00
fenris c5d52a7df5 [mod] data:example 2024-11-28 23:07:50 +01:00
fenris b86e1b62e2 [upd] plankton 2024-11-28 23:06:57 +01:00
fenris ef879bb81b [upd] node:xml2js 2024-11-28 23:06:38 +01:00
fenris 54e27f2ad9 [int] 2024-11-14 19:57:13 +01:00
fenris b5b5dde9e3 [res] 2024-11-10 17:20:41 +01:00
fenris 5de4728901 Merge remote-tracking branch 'origin/main' into task-192 2024-11-10 17:19:58 +01:00
fenris 9d1fd0b55f [int] 2024-10-30 07:20:13 +01:00
fenris 1127130b00 [task-192] [add] api:action:export_caldav 2024-10-27 19:01:33 +01:00
19 changed files with 766 additions and 138 deletions

View file

@ -1,20 +0,0 @@
{
"version": 1,
"log": [
{
"kind": "stdout",
"data": {
"threshold": "info"
}
}
],
"session_management": {
"in_memory": false,
"lifetime": 3600
},
"authentication": {
"kind": "internal",
"data": {
}
}
}

View file

@ -4,18 +4,21 @@
"id": 1,
"name": "alice",
"email_address": "alice@example.org",
"dav_token": null,
"password": "alice"
},
{
"id": 2,
"name": "bob",
"email_address": "bob@example.org",
"dav_token": "bob_dav",
"password": "bob"
},
{
"id": 3,
"name": "charlie",
"email_address": "charlie@example.org",
"dav_token": null,
"password": "charlie"
}
],

58
misc/conf-example.json Normal file
View file

@ -0,0 +1,58 @@
{
"version": 1,
"log": [
{
"kind": "stdout",
"data": {
"threshold": "info",
"format": "jsonl_structured"
}
}
],
"session_management": {
"in_memory": false,
"lifetime": 3600
},
"authentication": {
"kind": "internal",
"data": {
}
},
"database": {
"kind": "sqlite",
"data": {
"path": "../zeitbild.sqlite"
}
},
"caldav": {
"address": "http://localhost:8000/calendars/-/lampukistan",
"username": "lampukistan-{{username}}",
"password": "{{password}}",
"setup_hints": [
{
"label": "Android",
"link": "https://www.android-user.de/caldavcarddav-kalender-und-adressbuecher-ohne-google-synchronisieren/",
"remark": null
},
{
"label": "iOS",
"link": "https://all-inkl.com/wichtig/anleitungen/programme/e-mail/caldav-kalenderfunktion/ios-mail_460.html",
"remark": "eigentlich für Server 'all-inkl.com' — Zugangsdaten müssen entsprechend geändert werden"
},
{
"label": "Thunderbird",
"link": "https://www.uni-bielefeld.de/einrichtungen/bits/services/kuz/e-mail-und-kalender/anleitung/kalender-konfiguration-unter-thunderbird/",
"remark": "eigentlich für Server 'uni-bielefeld.de' — Zugangsdaten müssen entsprechend geändert werden"
},
{
"label": "Evolution",
"link": "https://help.gnome.org/users/evolution/stable/calendar-caldav.html.de"
},
{
"label": "MS Outlook",
"link": "https://www.united-domains.de/help/faq-article/wie-synchronisiere-ich-meinen-kalender-caldav-mit-ms-outlook/",
"remark": null
}
]
}
}

View file

@ -29,10 +29,9 @@ namespace _zeitbild.api
}
|
{
kind : "caldav";
kind : "ics_feed";
data : {
url : string;
read_only : boolean;
from_fucked_up_wordpress : boolean;
};
}
@ -75,12 +74,11 @@ namespace _zeitbild.api
};
break;
}
case "caldav": {
case "ics_feed": {
resource_object = {
"kind": "caldav",
"kind": "ics_feed",
"data": {
"url": stuff.input.resource.data.url,
"read_only": stuff.input.resource.data.read_only,
"from_fucked_up_wordpress": stuff.input.resource.data.from_fucked_up_wordpress,
}
};

View file

@ -0,0 +1,127 @@
namespace _zeitbild.api
{
/**
*/
export function register_export_ics(
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
register<
null,
(
lib_plankton.ical.type_vcalendar
|
string
)
>(
rest_subject,
lib_plankton.http.enum_method.get,
"/export/ics",
{
"description": "trägt Veranstaltungen aus verschiedenen Kalendern zusammen im ics-Format",
"query_parameters": () => ([
{
"name": "from",
"required": false,
"description": "UNIX timestamp",
},
{
"name": "to",
"required": false,
"description": "UNIX timestamp",
},
{
"name": "calendar_ids",
"required": false,
"description": "comma separated",
},
]),
"output_schema": () => ({
"nullable": false,
"type": "string",
}),
"response_body_mimetype": "text/calendar",
"response_body_encode": (output) => Buffer.from(
(typeof(output) === "string")
?
output
:
lib_plankton.ical.ics_encode(output)
),
"restriction": restriction_web_auth,
"execution": async (stuff) => {
const user : {id : _zeitbild.type_user_id; object : _zeitbild.type_user_object;} = await _zeitbild.api.user_from_web_auth(stuff);
const from : lib_plankton.pit.type_pit = (
("from" in stuff.query_parameters)
?
parseInt(stuff.query_parameters["from"])
:
lib_plankton.pit.shift_week(
lib_plankton.pit.now(),
-2
)
);
const to : lib_plankton.pit.type_pit = (
("to" in stuff.query_parameters)
?
parseInt(stuff.query_parameters["to"])
:
lib_plankton.pit.shift_week(
lib_plankton.pit.now(),
+6
)
);
const calendar_ids_wanted : (null | 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<string>) => x.map(parseInt),
(x : Array<int>) => x.filter(y => (! isNaN(y)))
]
)
:
null
);
return (
_zeitbild.service.calendar.gather_events(
calendar_ids_wanted,
from,
to,
user.id
)
.then(
(events_extended) => Promise.resolve(
{
"status_code": 200,
"data": _zeitbild.helpers.icalendar_vcalendar_from_own_event_list(
events_extended
)
}
)
)
.catch(
(reason) => Promise.resolve(
{
"status_code": 403,
"data": String(reason),
}
)
)
);
}
}
);
}
}

View file

@ -74,6 +74,7 @@ namespace _zeitbild.api
{
"name": data.userinfo.name,
"email_address": data.userinfo.email,
"dav_token": null,
}
);
lib_plankton.log.info(

View file

@ -0,0 +1,152 @@
namespace _zeitbild.api
{
/**
*/
export function register_user_dav_conf(
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
register<
null,
(
null
|
{
address : string;
username : string;
password : (null | string);
setup_hints : Array<
{
label : string;
link : string;
remark : (null | string);
}
>;
}
)
>(
rest_subject,
lib_plankton.http.enum_method.get,
"/user_dav_conf",
{
"description": "gibt die CalDAV-Zugangsdaten eines Nutzers aus",
"output_schema": () => ({
"nullable": true,
"type": "object",
"properties": {
"address": {
"nullable": false,
"type": "string"
},
"username": {
"nullable": false,
"type": "string"
},
"password": {
"nullable": true,
"type": "string"
},
"setup_hints": {
"nullable": false,
"type": "array",
"items": {
"nullable": false,
"type": "object",
"properties": {
"label": {
"nullable": false,
"type": "string"
},
"link": {
"nullable": false,
"type": "string"
},
"remark": {
"nullable": true,
"type": "string",
"default": null,
},
},
"required": [
"label",
"link",
],
"additionalProperties": false
},
"default": []
},
},
"required": [
"address",
"username",
"password",
"setup_hints",
],
"additionalProperties": false
}),
"restriction": restriction_logged_in,
"execution": async (stuff) => {
let result : (
null
|
{
address : string;
username : string;
password : (null | string);
setup_hints : Array<
{
label : string;
link : string;
remark : (null | string);
}
>;
}
) = null;
const raw : (null | any) = _zeitbild.conf.get()["caldav"];
if (raw === null)
{
result = null;
}
else
{
const session : {key : string; value : lib_plankton.session.type_session;} = await session_from_stuff(stuff);
const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.identify(session.value.name);
const user_object : _zeitbild.type_user_object = await _zeitbild.service.user.get(user_id);
const arguments_ : Record<string, string> = Object.fromEntries(
[
{"key": "username", "value": user_object.name},
{"key": "password", "value": user_object.dav_token},
]
.filter(
entry => (entry.value !== null)
)
.map(
entry => ([entry.key, entry.value as string])
)
);
result = {
"address": lib_plankton.string.coin(raw["address"], arguments_),
"username": lib_plankton.string.coin(raw["username"], arguments_),
"password": (
(user_object.dav_token === null)
?
null
:
lib_plankton.string.coin(raw["password"], arguments_)
),
"setup_hints": raw["setup_hints"],
};
}
return Promise.resolve(
{
"status_code": 200,
"data": result,
}
);
}
}
);
}
}

View file

@ -0,0 +1,53 @@
namespace _zeitbild.api
{
/**
*/
export function register_user_dav_token(
rest_subject : lib_plankton.rest_http.type_rest
) : void
{
register<
// string,
null,
null
>(
rest_subject,
lib_plankton.http.enum_method.patch,
"/user_dav_token",
{
"description": "setzt/überschreibt den DAV-Token eines Nutzers",
/*
"input_schema": () => ({
"nullable": false,
"type": "string"
}),
*/
"input_schema": () => ({
"nullable": true,
}),
"output_schema": () => ({
"nullable": true
}),
"restriction": restriction_logged_in,
"execution": async (stuff) => {
const session : {key : string; value : lib_plankton.session.type_session;} = await session_from_stuff(stuff);
const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.identify(session.value.name);
// TODO: outsource to user service?
const user_object : _zeitbild.type_user_object = await _zeitbild.service.user.get(user_id);
// user_object.dav_token = stuff.input;
user_object.dav_token = lib_plankton.random.generate_string({"length": 12});
await _zeitbild.service.user.change(user_id, user_object);
return Promise.resolve(
{
"status_code": 200,
"data": null,
}
);
}
}
);
}
}

View file

@ -31,6 +31,15 @@ namespace _zeitbild.api
_zeitbild.api.register_session_end(rest_subject);
_zeitbild.api.register_session_oidc(rest_subject);
}
// user
{
_zeitbild.api.register_users(rest_subject);
// caldav
{
_zeitbild.api.register_user_dav_conf(rest_subject);
_zeitbild.api.register_user_dav_token(rest_subject);
}
}
// calendar
{
_zeitbild.api.register_calendar_list(rest_subject);
@ -46,13 +55,15 @@ namespace _zeitbild.api
_zeitbild.api.register_calendar_event_remove(rest_subject);
}
}
// export
{
_zeitbild.api.register_export_ics(rest_subject);
}
// misc
{
_zeitbild.api.register_users(rest_subject);
_zeitbild.api.register_events(rest_subject);
}
return rest_subject;
}

View file

@ -282,8 +282,96 @@ namespace _zeitbild.conf
"data": {
}
}
},
"external_resources": {
"nullable": false,
"type": "object",
"properties": {
"lifetime": {
"nullable": false,
"type": "integer",
"default": 14400
}
},
"additionalProperties": false,
"required": [
],
"default": {
}
},
"caldav": {
"nullable": true,
"type": "object",
"properties": {
"address": {
"nullable": false,
"type": "string"
},
"username": {
"nullable": false,
"type": "string"
},
"password": {
"nullable": false,
"type": "string"
},
"setup_hints": {
"nullable": false,
"type": "array",
"items": {
"nullable": false,
"type": "object",
"properties": {
"label": {
"nullable": false,
"type": "string"
},
"link": {
"nullable": false,
"type": "string"
},
"remark": {
"nullable": true,
"type": "string",
"default": null
},
},
"required": [
"label",
"link",
],
"additionalProperties": false
},
"default": []
},
},
"required": [
"address",
"username",
"password"
],
"additionalProperties": false,
"default": null
},
"misc": {
"nullable": false,
"type": "object",
"properties": {
/**
* @todo make mandatory
*/
"auth_salt": {
"nullable": false,
"type": "string",
"default": "unsafe_auth_salt"
}
},
"required": [
],
"additionalProperties": false,
"default": {}
},
},
"required": [
"version"
],

View file

@ -7,7 +7,7 @@ namespace _zeitbild.helpers
/**
* @todo timezone
*/
function ical_datetime_to_own_datetime(
function icalendar_datetime_to_own_datetime(
ical_datetime : lib_plankton.ical.type_datetime
) : lib_plankton.pit.type_datetime
{
@ -36,7 +36,7 @@ namespace _zeitbild.helpers
/**
* @todo timezone
*/
export function ical_dt_to_own_datetime(
export function icalendar_dt_to_own_datetime(
ical_dt: lib_plankton.ical.type_dt
) : lib_plankton.pit.type_datetime
{
@ -58,6 +58,125 @@ namespace _zeitbild.helpers
}
/**
* @todo timezone
*/
export function icalendar_dt_from_own_datetime(
datetime : lib_plankton.pit.type_datetime
) : lib_plankton.ical.type_dt
{
return {
"tzid": "Europe/Berlin",
"value": {
"date": {
"year": datetime.date.year,
"month": datetime.date.month,
"day": datetime.date.day,
},
"time": (
(datetime.time === null)
?
null
:
{
"utc": true,
"hour": datetime.time.hour,
"minute": datetime.time.minute,
"second": datetime.time.second,
}
)
},
};
}
/**
*/
export function icalendar_vevent_from_own_event(
event_extended : _zeitbild.type_event_extended,
index : int,
{
"stamp": stamp = "adhoc",
}
:
{
stamp ?: string;
}
=
{
}
) : lib_plankton.ical.type_vevent
{
return {
"uid": lib_plankton.string.coin(
"zeitbild_{{stamp}}_{{id}}",
{
"stamp": stamp,
// "id": event_extended.event_id.toFixed(0),
"id": index.toFixed(0),
}
),
"dtstamp": icalendar_dt_from_own_datetime(event_extended.event_object.begin).value,
"dtstart": icalendar_dt_from_own_datetime(event_extended.event_object.begin),
"dtend": (
(event_extended.event_object.end === null)
?
undefined
:
icalendar_dt_from_own_datetime(event_extended.event_object.end)
),
"location": (event_extended.event_object.location ?? undefined),
"summary": event_extended.event_object.name,
"url": (event_extended.event_object.link ?? undefined),
"description": (event_extended.event_object.description ?? undefined),
/**
* @todo transform name
*/
"categories": [event_extended.calendar_name],
};
}
/**
* @todo assign better uids
*/
export function icalendar_vcalendar_from_own_event_list(
events_extended : Array<_zeitbild.type_event_extended>
) : lib_plankton.ical.type_vcalendar
{
const pit_now : lib_plankton.pit.type_pit = lib_plankton.pit.now();
const datetime_now : lib_plankton.pit.type_datetime = lib_plankton.pit.to_datetime(pit_now);
const stamp : string = lib_plankton.string.coin(
"{{year}}{{month}}{{day}}",
{
"year": datetime_now.date.year.toFixed(0).padStart(4, "0"),
"month": datetime_now.date.month.toFixed(0).padStart(2, "0"),
"day": datetime_now.date.day.toFixed(0).padStart(2, "0"),
}
);
return {
"version": "2.0",
"prodid": "",
"vevents": (
events_extended
.map<lib_plankton.ical.type_vevent>(
(event_extended, index) => icalendar_vevent_from_own_event(
event_extended,
index,
{
"stamp": stamp,
}
)
)
),
"method": "PUBLISH",
"vtimezone": {
"tzid": "Europe/Berlin",
},
};
}
/**
*/
export async function template_coin(

View file

@ -8,6 +8,7 @@ type type_data = {
id : int;
name : string;
email_address : string;
dav_token : (null | string);
password : string;
}
>;
@ -36,10 +37,9 @@ type type_data = {
}
|
{
kind : "caldav";
kind : "ics_feed";
data : {
url : string;
read_only : boolean;
from_fucked_up_wordpress ?: boolean;
};
}
@ -73,6 +73,7 @@ async function data_init(
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
@ -108,13 +109,12 @@ async function data_init(
);
break;
}
case "caldav":
case "ics_feed":
{
resource_object = {
"kind": "caldav",
"kind": "ics_feed",
"data": {
"url": calendar_raw.resource.data.url,
"read_only": calendar_raw.resource.data.read_only,
"from_fucked_up_wordpress": (calendar_raw.resource.data.from_fucked_up_wordpress ?? false),
}
};
@ -384,7 +384,6 @@ async function main(
case "api-doc": {
lib_plankton.log.set_main_logger([]);
const rest_subject : lib_plankton.rest_http.type_rest = _zeitbild.api.make();
lib_plankton.log.conf_pop();
process.stdout.write(
JSON.stringify(
lib_plankton.rest_http.to_oas(rest_subject),
@ -480,6 +479,7 @@ async function main(
)
.catch(
(error) => {
// console.error(error);
process.stderr.write(String(error) + "\n");
}
)

View file

@ -42,7 +42,7 @@ namespace _zeitbild.repository.resource
/**
*/
var _caldav_resource_store : (
var _ics_feed_resource_store : (
null
|
lib_plankton.storage.type_store<
@ -126,7 +126,7 @@ namespace _zeitbild.repository.resource
/**
*/
function get_caldav_resource_store(
function get_ics_feed_resource_store(
) : lib_plankton.storage.type_store<
int,
Record<string, any>,
@ -135,11 +135,11 @@ namespace _zeitbild.repository.resource
Record<string, any>
>
{
if (_caldav_resource_store === null) {
_caldav_resource_store = lib_plankton.storage.sql_table_autokey_store(
if (_ics_feed_resource_store === null) {
_ics_feed_resource_store = lib_plankton.storage.sql_table_autokey_store(
{
"database_implementation": _zeitbild.database.get_implementation(),
"table_name": "caldav_resources",
"table_name": "ics_feed_resources",
"key_name": "id",
}
);
@ -147,7 +147,7 @@ namespace _zeitbild.repository.resource
else {
// do nothing
}
return _caldav_resource_store;
return _ics_feed_resource_store;
}
@ -358,15 +358,14 @@ namespace _zeitbild.repository.resource
}
);
}
case "caldav": {
const dataset_extra_caldav : Record<string, any> = await get_caldav_resource_store().read(dataset_core.sub_id);
case "ics_feed": {
const dataset_extra_ics_feed : Record<string, any> = await get_ics_feed_resource_store().read(dataset_core.sub_id);
return Promise.resolve<_zeitbild.type_resource_object>(
{
"kind": "caldav",
"kind": "ics_feed",
"data": {
"url": dataset_extra_caldav["url"],
"read_only": dataset_extra_caldav["read_only"],
"from_fucked_up_wordpress": dataset_extra_caldav["from_fucked_up_wordpress"],
"url": dataset_extra_ics_feed["url"],
"from_fucked_up_wordpress": dataset_extra_ics_feed["from_fucked_up_wordpress"],
}
}
);
@ -405,18 +404,17 @@ namespace _zeitbild.repository.resource
return Promise.resolve<_zeitbild.type_resource_id>(resource_id);
break;
}
case "caldav": {
const caldav_resource_id : int = await get_caldav_resource_store().create(
case "ics_feed": {
const ics_feed_resource_id : int = await get_ics_feed_resource_store().create(
{
"url": resource_object.data.url,
"read_only": resource_object.data.read_only,
"from_fucked_up_wordpress": resource_object.data.from_fucked_up_wordpress,
}
);
const resource_id : _zeitbild.type_resource_id = await get_resource_core_store().create(
{
"kind": "caldav",
"sub_id": caldav_resource_id,
"kind": "ics_feed",
"sub_id": ics_feed_resource_id,
}
);
await lib_plankton.cache.clear(_zeitbild.cache_regular);
@ -491,12 +489,12 @@ namespace _zeitbild.repository.resource
*/
break;
}
case "caldav": {
await get_caldav_resource_store().update(
case "ics_feed": {
await get_ics_feed_resource_store().update(
dataset_core["sub_id"],
{
"url": resource_object.data.url,
"read_only": resource_object.data.read_only,
"from_fucked_up_wordpress": resource_object.data.from_fucked_up_wordpress,
}
);
await lib_plankton.cache.clear(_zeitbild.cache_regular);

View file

@ -53,6 +53,7 @@ namespace _zeitbild.repository.user
return {
"name": user_object.name,
"email_address": user_object.email_address,
"dav_token": user_object.dav_token,
};
}
@ -66,6 +67,7 @@ namespace _zeitbild.repository.user
return {
"name": row["name"],
"email_address": row["email_address"],
"dav_token": row["dav_token"],
};
}
@ -119,6 +121,19 @@ namespace _zeitbild.repository.user
}
/**
*/
export async function update(
user_id : _zeitbild.type_user_id,
user_object : _zeitbild.type_user_object
) : Promise<void>
{
const dispersal : Record<string, any> = encode(user_object);
await get_store().update(user_id, dispersal);
return Promise.resolve<void>(undefined);
}
/**
*/
export async function identify(

View file

@ -327,8 +327,13 @@ namespace _zeitbild.service.calendar
);
break;
}
case "caldav": {
case "ics_feed": {
// TODO readonly
const vcalendar : lib_plankton.ical.type_vcalendar = await lib_plankton.cache.get<lib_plankton.ical.type_vcalendar>(
_zeitbild.cache_external_resources,
resource_object.data.url,
_zeitbild.conf.get().external_resources.lifetime,
async () => {
const url : lib_plankton.url.type_url = lib_plankton.url.decode(
resource_object.data.url
);
@ -342,13 +347,18 @@ namespace _zeitbild.service.calendar
"headers": {},
"body": null,
};
// TODO: cache?
const http_response : lib_plankton.http.type_response = await lib_plankton.http.call(
http_request,
{
}
);
const ics_raw : string = http_response.body.toString();
const ics_raw : string = (
(http_response.body === null)
?
""
:
http_response.body.toString()
);
const vcalendar_list : Array<lib_plankton.ical.type_vcalendar> = lib_plankton.ical.ics_decode_multi(
ics_raw,
{
@ -362,6 +372,9 @@ namespace _zeitbild.service.calendar
"prodid": vcalendar_list[0].prodid,
"vevents": vcalendar_list.map(x => x.vevents).reduce((x, y) => x.concat(y), []),
};
return Promise.resolve<lib_plankton.ical.type_vcalendar>(vcalendar);
}
);
return Promise.resolve(
vcalendar.vevents
.map(
@ -376,11 +389,11 @@ namespace _zeitbild.service.calendar
:
"???"
),
"begin": _zeitbild.helpers.ical_dt_to_own_datetime(vevent.dtstart),
"begin": _zeitbild.helpers.icalendar_dt_to_own_datetime(vevent.dtstart),
"end": (
(vevent.dtend !== undefined)
?
_zeitbild.helpers.ical_dt_to_own_datetime(vevent.dtend)
_zeitbild.helpers.icalendar_dt_to_own_datetime(vevent.dtend)
:
null
),
@ -441,19 +454,6 @@ namespace _zeitbild.service.calendar
}
/**
*/
type type_gather_events_result = Array<
{
calendar_id : _zeitbild.type_calendar_id;
calendar_name : string;
access_level : _zeitbild.enum_access_level;
event_id : (null | _zeitbild.type_local_resource_event_id);
event_object : _zeitbild.type_event_object;
}
>;
/**
*/
export async function gather_events(
@ -461,7 +461,7 @@ namespace _zeitbild.service.calendar
from_pit : lib_plankton.pit.type_pit,
to_pit : lib_plankton.pit.type_pit,
user_id : (null | _zeitbild.type_user_id)
) : Promise<type_gather_events_result>
) : Promise<Array<_zeitbild.type_event_extended>>
{
const calendar_ids_allowed : Array<_zeitbild.type_calendar_id> = (
(await overview(user_id))
@ -483,8 +483,8 @@ namespace _zeitbild.service.calendar
)
);
calendar_ids.sort();
return lib_plankton.cache.get_complex<any, type_gather_events_result>(
_zeitbild.cache,
return lib_plankton.cache.get_complex<any, Array<_zeitbild.type_event_extended>>(
_zeitbild.cache_regular,
"gather_events",
{
"user_id": user_id,
@ -492,6 +492,10 @@ namespace _zeitbild.service.calendar
"to_pit": to_pit,
"calendar_ids": calendar_ids,
},
/**
* @todo expire?
*/
null,
() => (
Promise.all(
calendar_ids

View file

@ -31,7 +31,7 @@ namespace _zeitbild.service.resource
return Promise.resolve<_zeitbild.type_event_object>(event_object);
break;
}
case "caldav": {
case "ics_feed": {
// TODO
return Promise.reject(new Error("not implemented"));
break;
@ -63,14 +63,8 @@ namespace _zeitbild.service.resource
return Promise.resolve<_zeitbild.type_local_resource_event_id>(local_resource_event_id);
break;
}
case "caldav": {
if (resource_object.data.read_only) {
return Promise.reject(new Error("can not add event to read only caldav resource"));
}
else {
// TODO
return Promise.reject(new Error("not implemented"));
}
case "ics_feed": {
return Promise.reject(new Error("unavailable"));
break;
}
default: {
@ -102,14 +96,8 @@ namespace _zeitbild.service.resource
return Promise.resolve<void>(undefined);
break;
}
case "caldav": {
if (resource_object.data.read_only) {
return Promise.reject(new Error("can not change event of read only caldav resource"));
}
else {
// TODO
return Promise.reject(new Error("not implemented"));
}
case "ics_feed": {
return Promise.reject(new Error("unavailable"));
break;
}
default: {
@ -139,14 +127,8 @@ namespace _zeitbild.service.resource
return Promise.resolve<void>(undefined);
break;
}
case "caldav": {
if (resource_object.data.read_only) {
return Promise.reject(new Error("can not delete event from read only caldav resource"));
}
else {
// TODO
return Promise.reject(new Error("not implemented"));
}
case "ics_feed": {
return Promise.reject(new Error("unavailable"));
break;
}
default: {

View file

@ -28,6 +28,16 @@ namespace _zeitbild.service.user
}
/**
*/
export function get(
user_id : _zeitbild.type_user_id
) : Promise<_zeitbild.type_user_object>
{
return _zeitbild.repository.user.read(user_id);
}
/**
*/
export function add(
@ -37,4 +47,15 @@ namespace _zeitbild.service.user
return _zeitbild.repository.user.create(user_object);
}
/**
*/
export function change(
user_id : _zeitbild.type_user_id,
user_object : _zeitbild.type_user_object
) : Promise<void>
{
return _zeitbild.repository.user.update(user_id, user_object);
}
}

View file

@ -28,6 +28,11 @@ namespace _zeitbild
|
string
);
dav_token : (
null
|
string
);
};
@ -82,10 +87,9 @@ namespace _zeitbild
}
|
{
kind : "caldav";
kind : "ics_feed";
data : {
url : string;
read_only : boolean;
from_fucked_up_wordpress : boolean;
};
}
@ -112,4 +116,15 @@ namespace _zeitbild
resource_id : type_resource_id;
};
/**
*/
export type type_event_extended = {
calendar_id : type_calendar_id;
calendar_name : string;
access_level : enum_access_level;
event_id : (null | type_local_resource_event_id);
event_object : type_event_object;
};
}

View file

@ -65,6 +65,8 @@ ${dir_temp}/zeitbild-unlinked.js: \
${dir_source}/api/actions/session_oidc.ts \
${dir_source}/api/actions/session_end.ts \
${dir_source}/api/actions/users.ts \
${dir_source}/api/actions/user_dav_conf.ts \
${dir_source}/api/actions/user_dav_token.ts \
${dir_source}/api/actions/calendar_list.ts \
${dir_source}/api/actions/calendar_get.ts \
${dir_source}/api/actions/calendar_add.ts \
@ -75,6 +77,7 @@ ${dir_temp}/zeitbild-unlinked.js: \
${dir_source}/api/actions/calendar_event_change.ts \
${dir_source}/api/actions/calendar_event_remove.ts \
${dir_source}/api/actions/events.ts \
${dir_source}/api/actions/export_ics.ts \
${dir_source}/api/functions.ts \
${dir_source}/main.ts
@ ${cmd_log} "compile …"