[mod]
This commit is contained in:
parent
85f16e3c3b
commit
78014d6a3a
9 changed files with 529 additions and 131 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"version": 1,
|
||||
"log": [
|
||||
{"kind": "stdout", "data": {"threshold": "debug"}}
|
||||
{"kind": "stdout", "data": {"threshold": "info"}}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -338,8 +338,8 @@
|
|||
"data": {
|
||||
"name": "Lixer",
|
||||
"private": true,
|
||||
"read_only": true,
|
||||
"source_url": "https://export.kalender.digital/ics/0/3e10dae66950379d4cc8/gesamterkalender.ics?past_months=3&future_months=36"
|
||||
"url": "https://export.kalender.digital/ics/0/3e10dae66950379d4cc8/gesamterkalender.ics?past_months=3&future_months=36",
|
||||
"read_only": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
157
source/api/actions/events.ts
Normal file
157
source/api/actions/events.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
|
||||
namespace _zeitbild.api
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function register_events(
|
||||
rest_subject : lib_plankton.rest.type_rest
|
||||
) : void
|
||||
{
|
||||
register<
|
||||
{
|
||||
from : int;
|
||||
to : int;
|
||||
calendar_ids : (
|
||||
null
|
||||
|
|
||||
Array<_zeitbild.type.calendar_id>
|
||||
);
|
||||
},
|
||||
Array<
|
||||
{
|
||||
calendar_id : int;
|
||||
event : _zeitbild.type.event_object;
|
||||
}
|
||||
>
|
||||
>(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.post,
|
||||
"/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
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"to",
|
||||
]
|
||||
}),
|
||||
"output_schema": () => ({
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"nullable": false,
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"calendar_id": {
|
||||
"type": "number",
|
||||
"nullable": false,
|
||||
},
|
||||
"event": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"nullable": false,
|
||||
},
|
||||
"begin": {
|
||||
"type": "int",
|
||||
"nullable": false,
|
||||
},
|
||||
"end": {
|
||||
"type": "int",
|
||||
"nullable": true,
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"begin",
|
||||
"end",
|
||||
"location",
|
||||
"description",
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"calendar_id",
|
||||
"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)
|
||||
)
|
||||
)
|
||||
)
|
||||
.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,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -28,6 +28,10 @@ namespace _zeitbild.api
|
|||
{
|
||||
_zeitbild.api.register_calendar_list(rest_subject);
|
||||
}
|
||||
// misc
|
||||
{
|
||||
_zeitbild.api.register_events(rest_subject);
|
||||
}
|
||||
|
||||
|
||||
return rest_subject;
|
||||
|
|
|
@ -275,5 +275,44 @@ namespace _zeitbild.repository.calendar
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function overview(
|
||||
user_id : _zeitbild.type.user_id
|
||||
) : Promise<
|
||||
Array<
|
||||
{
|
||||
id : _zeitbild.type.calendar_id;
|
||||
name : string;
|
||||
public : boolean;
|
||||
role : (null | _zeitbild.type.role);
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return (
|
||||
_zeitbild.database.get_implementation().query_free_get(
|
||||
{
|
||||
"template": "SELECT x.id AS id, x.name AS name, x.public AS public, MAX(y.role) AS role FROM calendars AS x LEFT OUTER JOIN calendar_members AS y ON (x.id = y.calendar_id) WHERE (x.public OR (y.user_id = $user_id)) GROUP BY x.id;",
|
||||
"arguments": {
|
||||
"user_id": user_id,
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(
|
||||
(rows) => Promise.resolve(
|
||||
rows.map(
|
||||
(row) => ({
|
||||
"id": row["id"],
|
||||
"name": row["name"],
|
||||
"public": row["public"],
|
||||
"role": row["role"],
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -284,7 +284,7 @@ namespace _zeitbild.repository.resource
|
|||
{
|
||||
"kind": "local",
|
||||
"data": {
|
||||
"events": datasets_extra_local_events.map(x => decode_event(x)),
|
||||
"events": datasets_extra_local_events.map(x => decode_event(x.preview)),
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -31,6 +31,25 @@ namespace _zeitbild.service.calendar
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function overview(
|
||||
user_id : _zeitbild.type.user_id
|
||||
) : Promise<
|
||||
Array<
|
||||
{
|
||||
id : _zeitbild.type.calendar_id;
|
||||
name : string;
|
||||
public : boolean;
|
||||
role : (null | _zeitbild.type.role);
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return _zeitbild.repository.calendar.overview(user_id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function get(
|
||||
|
@ -43,33 +62,21 @@ namespace _zeitbild.service.calendar
|
|||
|
||||
/**
|
||||
*/
|
||||
async function gather_events(
|
||||
calendar_ids : Array<_zeitbild.type.calendar_id>,
|
||||
async function get_events(
|
||||
calendar_id : _zeitbild.type.calendar_id,
|
||||
from_pit : _zeitbild.helpers.type_pit,
|
||||
to_pit : _zeitbild.helpers.type_pit
|
||||
) : Promise<
|
||||
Array<
|
||||
{
|
||||
calendar_id : _zeitbild.type.calendar_id;
|
||||
event : _zeitbild.type.event_object;
|
||||
}
|
||||
_zeitbild.type.event_object
|
||||
>
|
||||
>
|
||||
{
|
||||
let result : Array<
|
||||
{
|
||||
calendar_id : _zeitbild.type.calendar_id;
|
||||
event : _zeitbild.type.event_object;
|
||||
}
|
||||
> = [];
|
||||
for await (const calendar_id of calendar_ids) {
|
||||
const calendar_object : _zeitbild.type.calendar_object = await _zeitbild.repository.calendar.read(calendar_id);
|
||||
const resource_object : _zeitbild.type.resource_object = await _zeitbild.repository.resource.read(calendar_object.resource_id);
|
||||
switch (resource_object.kind) {
|
||||
case "local": {
|
||||
result = (
|
||||
result
|
||||
.concat(
|
||||
return Promise.resolve(
|
||||
resource_object.data.events
|
||||
.filter(
|
||||
(event : _zeitbild.type.event_object) => _zeitbild.helpers.pit_is_between(
|
||||
|
@ -78,20 +85,13 @@ namespace _zeitbild.service.calendar
|
|||
to_pit
|
||||
)
|
||||
)
|
||||
.map(
|
||||
(event : _zeitbild.type.event_object) => ({
|
||||
"calendar_id": calendar_id,
|
||||
"event": event,
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "caldav": {
|
||||
// TODO readonly
|
||||
const url : lib_plankton.url.type_url = lib_plankton.url.decode(
|
||||
calendar_object.data.url
|
||||
resource_object.data.url
|
||||
);
|
||||
const http_request : lib_plankton.http.type_request = {
|
||||
"version": "HTTP/2",
|
||||
|
@ -114,9 +114,7 @@ namespace _zeitbild.service.calendar
|
|||
{
|
||||
}
|
||||
);
|
||||
result = (
|
||||
result
|
||||
.concat(
|
||||
return Promise.resolve(
|
||||
vcalendar.vevents
|
||||
.map(
|
||||
(vevent : lib_plankton.ical.type_vevent) => (
|
||||
|
@ -167,13 +165,6 @@ namespace _zeitbild.service.calendar
|
|||
to_pit
|
||||
)
|
||||
)
|
||||
.map(
|
||||
(event) => ({
|
||||
"calendar_id": calendar_id,
|
||||
"event": event,
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
@ -185,7 +176,52 @@ namespace _zeitbild.service.calendar
|
|||
}
|
||||
}
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
|
||||
|
||||
/**
|
||||
* @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,
|
||||
) : Promise<
|
||||
Array<
|
||||
{
|
||||
calendar_id : _zeitbild.type.calendar_id;
|
||||
event : _zeitbild.type.event_object;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return (
|
||||
Promise.all(
|
||||
calendar_ids
|
||||
.map(
|
||||
(calendar_id) => get_events(
|
||||
calendar_id,
|
||||
from_pit,
|
||||
to_pit
|
||||
)
|
||||
.then(
|
||||
(events) => Promise.resolve(
|
||||
events.map(
|
||||
(event) => ({
|
||||
"calendar_id": calendar_id,
|
||||
"event": event,
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(
|
||||
(sub_results) => sub_results.reduce(
|
||||
(x, y) => x.concat(y),
|
||||
[]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
161
tools/convert
Executable file
161
tools/convert
Executable file
|
@ -0,0 +1,161 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import json as _json
|
||||
import datetime as _datetime
|
||||
|
||||
|
||||
def sql_format(
|
||||
value
|
||||
):
|
||||
if (value is None):
|
||||
return "NULL"
|
||||
else:
|
||||
if (type(value) == bool):
|
||||
return ('TRUE' if value else 'FALSE')
|
||||
elif (type(value) == int):
|
||||
return ("%u" % value)
|
||||
elif (type(value) == str):
|
||||
return ("'%s'" % value)
|
||||
else:
|
||||
raise ValueError("unhandled type: " + str(type(value)))
|
||||
|
||||
|
||||
def string_coin(
|
||||
template,
|
||||
arguments
|
||||
):
|
||||
result = template
|
||||
for (key, value, ) in arguments.items():
|
||||
result = result.replace("{{%s}}" % key, value)
|
||||
return result
|
||||
|
||||
|
||||
def file_read(
|
||||
path
|
||||
):
|
||||
handle = open(path, "r")
|
||||
content = handle.read()
|
||||
handle.close()
|
||||
return content
|
||||
|
||||
|
||||
def datetime_convert(
|
||||
datetime
|
||||
):
|
||||
return (
|
||||
None
|
||||
if
|
||||
(datetime is None)
|
||||
else
|
||||
string_coin(
|
||||
"{{timezone_shift}}|{{year}}-{{month}}-{{day}}{{macro_time}}",
|
||||
{
|
||||
"timezone_shift": ("%02u" % datetime["timezone_shift"]),
|
||||
"year": ("%04u" % datetime["date"]["year"]),
|
||||
"month": ("%02u" % datetime["date"]["month"]),
|
||||
"day": ("%02u" % datetime["date"]["day"]),
|
||||
"macro_time": (
|
||||
""
|
||||
if
|
||||
(datetime["time"] is None)
|
||||
else
|
||||
string_coin(
|
||||
"T{{hour}}:{{minute}}:{{second}}",
|
||||
{
|
||||
"hour": ("%02u" % datetime["time"]["hour"]),
|
||||
"minute": ("%02u" % datetime["time"]["minute"]),
|
||||
"second": ("%02u" % datetime["time"]["second"]),
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def main(
|
||||
):
|
||||
data = _json.loads(file_read("data/example.kal.json"))
|
||||
for user in data["users"]:
|
||||
print(
|
||||
string_coin(
|
||||
"INSERT INTO users(id,name) VALUES ({{id}},{{name}});\n",
|
||||
{
|
||||
"id": sql_format(user["id"]),
|
||||
"name": sql_format(user["object"]["name"]),
|
||||
}
|
||||
)
|
||||
)
|
||||
ids = {
|
||||
"local_resource": 0,
|
||||
"caldav_resource": 0,
|
||||
}
|
||||
for calendar in data["calendars"]:
|
||||
if (calendar["object"]["kind"] == "concrete"):
|
||||
ids["local_resource"] += 1
|
||||
print(
|
||||
string_coin(
|
||||
"INSERT INTO local_resources(id) VALUES ({{id}});\n",
|
||||
{
|
||||
"id": sql_format(ids["local_resource"])
|
||||
}
|
||||
)
|
||||
)
|
||||
for event in calendar["object"]["data"]["events"]:
|
||||
print(
|
||||
string_coin(
|
||||
"INSERT INTO local_resource_events(local_resource_id,name,begin,end,location,description) VALUES ({{local_resource_id}},{{name}},{{begin}},{{end}},{{location}},{{description}});\n",
|
||||
{
|
||||
"local_resource_id": sql_format(ids["local_resource"]),
|
||||
"name": sql_format(event["name"]),
|
||||
"begin": sql_format(datetime_convert(event["begin"])),
|
||||
"end": sql_format(datetime_convert(event["end"])),
|
||||
"location": sql_format(event["location"]),
|
||||
"description": sql_format(event["description"]),
|
||||
}
|
||||
)
|
||||
)
|
||||
print(
|
||||
string_coin(
|
||||
"INSERT INTO resources(kind,sub_id) VALUES ({{kind}},{{sub_id}});\n",
|
||||
{
|
||||
"kind": sql_format("local"),
|
||||
"sub_id": sql_format(ids["local_resource"])
|
||||
}
|
||||
)
|
||||
)
|
||||
elif (calendar["object"]["kind"] == "caldav"):
|
||||
ids["caldav_resource"] += 1
|
||||
print(
|
||||
string_coin(
|
||||
"INSERT INTO caldav_resources(id,url,read_only) VALUES ({{id}},{{url}},{{read_only}});\n",
|
||||
{
|
||||
"id": sql_format(ids["caldav_resource"]),
|
||||
"url": sql_format(calendar["object"]["data"]["url"]),
|
||||
"read_only": sql_format(calendar["object"]["data"]["read_only"]),
|
||||
}
|
||||
)
|
||||
)
|
||||
print(
|
||||
string_coin(
|
||||
"INSERT INTO resources(kind,sub_id) VALUES ({{kind}},{{sub_id}});\n",
|
||||
{
|
||||
"kind": sql_format("caldav"),
|
||||
"sub_id": sql_format(ids["caldav_resource"])
|
||||
}
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValueError("invalid")
|
||||
print(
|
||||
string_coin(
|
||||
"INSERT INTO calendars(name,public,resource_id) VALUES ({{name}},{{public}},LAST_INSERT_ROWID());\n",
|
||||
{
|
||||
"name": sql_format(calendar["object"]["data"]["name"]),
|
||||
"public": sql_format(not calendar["object"]["data"]["private"]),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
main()
|
|
@ -33,6 +33,7 @@ ${dir_temp}/zeitbild-unlinked.js: \
|
|||
${dir_source}/api/actions/meta_ping.ts \
|
||||
${dir_source}/api/actions/meta_spec.ts \
|
||||
${dir_source}/api/actions/calendar_list.ts \
|
||||
${dir_source}/api/actions/events.ts \
|
||||
${dir_source}/api/functions.ts \
|
||||
${dir_source}/main.ts
|
||||
@ ${cmd_log} "compile …"
|
||||
|
|
Loading…
Add table
Reference in a new issue