[mod]
This commit is contained in:
parent
175e57b1f3
commit
85f16e3c3b
7 changed files with 711 additions and 360 deletions
|
@ -1,21 +1,23 @@
|
||||||
- Kalender sollen unabhängig von Nutzern bestehen können
|
- Kalender sollen unabhängig von Nutzern bestehen können
|
||||||
- einem Kalender können beliebig viele Nutzer zugeordnet werden, die jeweils bestimmte Berechtigungen haben (z.B. als Rollen "admin", "editor", "viewer", …)
|
- einem Kalender können beliebig viele Nutzer zugeordnet werden, die jeweils bestimmte Berechtigungen haben (z.B. als Rollen "admin", "editor", "viewer", …)
|
||||||
- Events bilden keine Domäne
|
- Veranstaltungen bilden keine Domäne
|
||||||
|
- es gibt verschiedene Arten von Quellen:
|
||||||
|
- lokal
|
||||||
|
- enthält Veranstaltungen
|
||||||
|
- caldav
|
||||||
|
- enthält keine eigenen Veranstaltungen
|
||||||
|
- sollte read-only- und read/write-Modus haben
|
||||||
- Berechtigungen:
|
- Berechtigungen:
|
||||||
- Kalender anlegen
|
- Kalender anlegen
|
||||||
- Kalender-Stammdaten ändern
|
- Stammdaten ändern
|
||||||
- Kalender-Einträge lesen
|
- Einträge lesen
|
||||||
- Kalender-Einträge erstellen
|
- Einträge erstellen
|
||||||
- Kalender-Einträge ändern
|
- Einträge ändern
|
||||||
- Kalender-Einträge entfernen
|
- Einträge entfernen
|
||||||
|
- Rollen (innerhalb eines Kalendars):
|
||||||
|
- `admin`: kann alles
|
||||||
|
- `editor`: kann bei lokalen
|
||||||
- Kalender sind für gewöhnlichen öffentlich
|
- Kalender sind für gewöhnlichen öffentlich
|
||||||
- es gibt verschiedene Arten von Kalendern:
|
|
||||||
- konkret
|
|
||||||
- enthält Veranstaltungen
|
|
||||||
- extern
|
|
||||||
- über CalDAV
|
|
||||||
- sollte read-only- und read/write-Modus haben
|
|
||||||
- nach dem Anmelden sieht man eine Kalender-Ansicht mit folgenden Kalendern kombiniert angezeigt:
|
- nach dem Anmelden sieht man eine Kalender-Ansicht mit folgenden Kalendern kombiniert angezeigt:
|
||||||
- öffentliche Kalender
|
- öffentliche Kalender
|
||||||
- nicht öffentliche Kalendar, bei welchen man Lese-Berechtigung hat
|
- nicht öffentliche Kalendar, bei welchen man Lese-Berechtigung hat
|
||||||
- Entwurfsname: "zeitbild"
|
|
||||||
|
|
|
@ -4,69 +4,6 @@
|
||||||
namespace _zeitbild.helpers
|
namespace _zeitbild.helpers
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
var _template_cache : Record<string, string> = {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo caching
|
|
||||||
*/
|
|
||||||
export async function template_coin(
|
|
||||||
name : string,
|
|
||||||
data : Record<string, string>
|
|
||||||
) : Promise<string>
|
|
||||||
{
|
|
||||||
let content : string;
|
|
||||||
if (! (name in _template_cache)) {
|
|
||||||
content = (
|
|
||||||
(
|
|
||||||
await lib_plankton.file.read(
|
|
||||||
lib_plankton.string.coin(
|
|
||||||
"templates/{{name}}.html.tpl",
|
|
||||||
{
|
|
||||||
"name": name,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.toString()
|
|
||||||
);
|
|
||||||
_template_cache[name] = content;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
content = _template_cache[name];
|
|
||||||
}
|
|
||||||
return Promise.resolve<string>(
|
|
||||||
lib_plankton.string.coin(
|
|
||||||
content,
|
|
||||||
data
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo outsource
|
|
||||||
*/
|
|
||||||
export async function promise_row<type_result>(
|
|
||||||
members : Array<
|
|
||||||
() => Promise<type_result>
|
|
||||||
>
|
|
||||||
) : Promise<
|
|
||||||
Array<
|
|
||||||
type_result
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
let results : Array<type_result> = [];
|
|
||||||
for await (const member of members) {
|
|
||||||
results.push(await member());
|
|
||||||
}
|
|
||||||
return Promise.resolve<Array<type_result>>(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export function date_object_get_week_of_year(
|
export function date_object_get_week_of_year(
|
||||||
|
@ -153,7 +90,6 @@ namespace _zeitbild.helpers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo negative shift?
|
* @todo negative shift?
|
||||||
*/
|
*/
|
||||||
|
@ -587,4 +523,67 @@ namespace _zeitbild.helpers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
var _template_cache : Record<string, string> = {};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo caching
|
||||||
|
*/
|
||||||
|
export async function template_coin(
|
||||||
|
name : string,
|
||||||
|
data : Record<string, string>
|
||||||
|
) : Promise<string>
|
||||||
|
{
|
||||||
|
let content : string;
|
||||||
|
if (! (name in _template_cache)) {
|
||||||
|
content = (
|
||||||
|
(
|
||||||
|
await lib_plankton.file.read(
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
"templates/{{name}}.html.tpl",
|
||||||
|
{
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toString()
|
||||||
|
);
|
||||||
|
_template_cache[name] = content;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
content = _template_cache[name];
|
||||||
|
}
|
||||||
|
return Promise.resolve<string>(
|
||||||
|
lib_plankton.string.coin(
|
||||||
|
content,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo outsource
|
||||||
|
*/
|
||||||
|
export async function promise_row<type_result>(
|
||||||
|
members : Array<
|
||||||
|
() => Promise<type_result>
|
||||||
|
>
|
||||||
|
) : Promise<
|
||||||
|
Array<
|
||||||
|
type_result
|
||||||
|
>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
let results : Array<type_result> = [];
|
||||||
|
for await (const member of members) {
|
||||||
|
results.push(await member());
|
||||||
|
}
|
||||||
|
return Promise.resolve<Array<type_result>>(results);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,28 @@
|
||||||
namespace _zeitbild.repository.calendar
|
namespace _zeitbild.repository.calendar
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
type type_dispersal = {
|
||||||
|
core_row : Record<
|
||||||
|
string,
|
||||||
|
any
|
||||||
|
>;
|
||||||
|
member_rows : Array<
|
||||||
|
Record<
|
||||||
|
string,
|
||||||
|
any
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
var _core_store : (
|
var _core_store : (
|
||||||
null
|
null
|
||||||
|
|
|
|
||||||
lib_plankton.storage.type_core_store<
|
lib_plankton.storage.type_store<
|
||||||
_zeitbild.type.calendar_id,
|
_zeitbild.type.calendar_id,
|
||||||
Record<string, any>,
|
Record<string, any>,
|
||||||
{},
|
{},
|
||||||
|
@ -19,14 +35,14 @@ namespace _zeitbild.repository.calendar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
var _event_store : (
|
var _member_chest : (
|
||||||
null
|
null
|
||||||
|
|
|
|
||||||
lib_plankton.storage.type_core_store<
|
lib_plankton.storage.type_chest<
|
||||||
_zeitbild.type.event_id,
|
Array<any>,
|
||||||
Record<string, any>,
|
Record<string, any>,
|
||||||
{},
|
lib_plankton.database.type_description_create_table,
|
||||||
lib_plankton.storage.type_sql_table_autokey_search_term,
|
lib_plankton.storage.sql_table_common.type_sql_table_common_search_term,
|
||||||
Record<string, any>
|
Record<string, any>
|
||||||
>
|
>
|
||||||
) = null;
|
) = null;
|
||||||
|
@ -35,7 +51,7 @@ namespace _zeitbild.repository.calendar
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function get_core_store(
|
function get_core_store(
|
||||||
) : lib_plankton.storage.type_core_store<
|
) : lib_plankton.storage.type_store<
|
||||||
_zeitbild.type.calendar_id,
|
_zeitbild.type.calendar_id,
|
||||||
Record<string, any>,
|
Record<string, any>,
|
||||||
{},
|
{},
|
||||||
|
@ -44,7 +60,7 @@ namespace _zeitbild.repository.calendar
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if (_core_store === null) {
|
if (_core_store === null) {
|
||||||
_core_store = lib_plankton.storage.sql_table_autokey_core_store(
|
_core_store = lib_plankton.storage.sql_table_autokey_store(
|
||||||
{
|
{
|
||||||
"database_implementation": _zeitbild.database.get_implementation(),
|
"database_implementation": _zeitbild.database.get_implementation(),
|
||||||
"table_name": "calendars",
|
"table_name": "calendars",
|
||||||
|
@ -61,102 +77,78 @@ namespace _zeitbild.repository.calendar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function get_event_store(
|
function get_member_chest(
|
||||||
) : lib_plankton.storage.type_core_store<
|
) : lib_plankton.storage.type_chest<
|
||||||
_zeitbild.type.event_id,
|
Array<any>,
|
||||||
Record<string, any>,
|
Record<string, any>,
|
||||||
{},
|
lib_plankton.database.type_description_create_table,
|
||||||
lib_plankton.storage.type_sql_table_autokey_search_term,
|
lib_plankton.storage.sql_table_common.type_sql_table_common_search_term,
|
||||||
Record<string, any>
|
Record<string, any>
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if (_event_store === null) {
|
if (_member_chest === null) {
|
||||||
_event_store = lib_plankton.storage.sql_table_autokey_core_store(
|
_member_chest = lib_plankton.storage.sql_table_common.chest(
|
||||||
{
|
{
|
||||||
"database_implementation": _zeitbild.database.get_implementation(),
|
"database_implementation": _zeitbild.database.get_implementation(),
|
||||||
"table_name": "events",
|
"table_name": "calendar_members",
|
||||||
"key_name": "id",
|
"key_names": ["calendar_id","user_id"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
return _event_store;
|
return _member_chest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo use events table
|
|
||||||
*/
|
*/
|
||||||
function encode(
|
function encode(
|
||||||
object : _zeitbild.type.calendar_object
|
object : _zeitbild.type.calendar_object
|
||||||
) : Record<string, any>
|
) : type_dispersal
|
||||||
{
|
{
|
||||||
switch (object.kind) {
|
|
||||||
/*
|
|
||||||
case "concrete": {
|
|
||||||
const data_raw : any = lib_plankton.json.encode(object.data);
|
|
||||||
data_raw["users"]
|
|
||||||
return {
|
return {
|
||||||
|
"core_row": {
|
||||||
"name": object.name,
|
"name": object.name,
|
||||||
"private": object.private,
|
"public": object.public,
|
||||||
"kind": object.kind,
|
"resource_id": object.resource_id,
|
||||||
"data": {
|
|
||||||
"users": data_raw["users"],
|
|
||||||
"events": [] // TODO
|
|
||||||
},
|
},
|
||||||
|
"member_rows": (
|
||||||
|
object.members
|
||||||
|
.map(
|
||||||
|
(member) => ({
|
||||||
|
// "calendar_id": calendar_id,
|
||||||
|
"user_id": member.user_id,
|
||||||
|
"role": member.role,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
default: {
|
|
||||||
return {
|
|
||||||
"name": object.name,
|
|
||||||
"private": object.private,
|
|
||||||
"kind": object.kind,
|
|
||||||
"data": lib_plankton.json.encode(object.data),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function decode(
|
function decode(
|
||||||
row : Record<string, any>
|
dispersal : type_dispersal
|
||||||
) : _zeitbild.type.calendar_object
|
) : _zeitbild.type.calendar_object
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
"name": row["name"],
|
"name": dispersal.core_row["name"],
|
||||||
"private": row["private"],
|
"public": dispersal.core_row["public"],
|
||||||
"kind": row["kind"],
|
"members": (
|
||||||
"data": lib_plankton.json.decode(row["data"]),
|
dispersal.member_rows
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export async function dump(
|
|
||||||
) : Promise<
|
|
||||||
Array<
|
|
||||||
{
|
|
||||||
id : _zeitbild.type.calendar_id;
|
|
||||||
object : _zeitbild.type.calendar_object;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
(await get_core_store().search(null))
|
|
||||||
.map(
|
.map(
|
||||||
({"key": key, "preview": preview}) => ({
|
(member_row) => ({
|
||||||
"id": key,
|
"calendar_id": member_row["calendar_id"],
|
||||||
"object": (preview as _zeitbild.type.calendar_object),
|
"user_id": member_row["user_id"],
|
||||||
|
"role": member_row["role"],
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
),
|
||||||
|
"resource_id": dispersal.core_row["resource_id"],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,7 +169,15 @@ namespace _zeitbild.repository.calendar
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
(await get_core_store().search(null))
|
(
|
||||||
|
await get_core_store().search(
|
||||||
|
{
|
||||||
|
"expression": "(public = TRUE)",
|
||||||
|
"arguments": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
.filter(
|
.filter(
|
||||||
({"key": key, "preview": preview}) => (
|
({"key": key, "preview": preview}) => (
|
||||||
(
|
(
|
||||||
|
@ -205,49 +205,74 @@ namespace _zeitbild.repository.calendar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export async function read(
|
export function read(
|
||||||
id : _zeitbild.type.calendar_id
|
id : _zeitbild.type.calendar_id
|
||||||
) : Promise<_zeitbild.type.calendar_object>
|
) : Promise<_zeitbild.type.calendar_object>
|
||||||
{
|
{
|
||||||
const row : Record<string, any> = await get_core_store().read(id);
|
return (
|
||||||
|
get_core_store().read(id)
|
||||||
return decode(row);
|
.then(
|
||||||
|
(core_row) => (
|
||||||
|
get_member_chest().search(
|
||||||
|
{
|
||||||
|
"expression": "(calendar_id = $calendar_id)",
|
||||||
|
"arguments": {
|
||||||
|
"calendar_id": id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(member_rows) => Promise.resolve<type_dispersal>(
|
||||||
|
{
|
||||||
|
"core_row": core_row,
|
||||||
|
"member_rows": member_rows,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(dispersal) => Promise.resolve<_zeitbild.type.calendar_object>(
|
||||||
|
decode(dispersal)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export async function create(
|
export function create(
|
||||||
value : _zeitbild.type.calendar_object
|
calendar_object : _zeitbild.type.calendar_object
|
||||||
) : Promise<_zeitbild.type.calendar_id>
|
) : Promise<_zeitbild.type.calendar_id>
|
||||||
{
|
{
|
||||||
const row : Record<string, any> = encode(value);
|
return (
|
||||||
const id : _zeitbild.type.calendar_id = await get_core_store().create(row);
|
Promise.resolve<_zeitbild.type.calendar_object>(calendar_object)
|
||||||
|
.then<type_dispersal>(
|
||||||
return id;
|
(calendar_object) => Promise.resolve<type_dispersal>(encode(calendar_object))
|
||||||
}
|
)
|
||||||
|
.then<_zeitbild.type.calendar_id>(
|
||||||
|
(dispersal) => (
|
||||||
/**
|
get_core_store().create(dispersal.core_row)
|
||||||
*/
|
.then<_zeitbild.type.calendar_id>(
|
||||||
export async function update(
|
(calendar_id) => (
|
||||||
id : _zeitbild.type.calendar_id,
|
Promise.all(
|
||||||
value : _zeitbild.type.calendar_object
|
dispersal.member_rows
|
||||||
) : Promise<void>
|
.map(
|
||||||
{
|
(member_row) => get_member_chest().write(
|
||||||
const row : Record<string, any> = encode(value);
|
[calendar_id, member_row["user_id"]],
|
||||||
|
{"role": member_row["role"]}
|
||||||
await get_core_store().update(id, row);
|
)
|
||||||
}
|
)
|
||||||
|
)
|
||||||
|
.then(
|
||||||
/**
|
() => Promise.resolve<_zeitbild.type.calendar_id>(calendar_id)
|
||||||
*/
|
)
|
||||||
export async function delete_(
|
)
|
||||||
id : _zeitbild.type.calendar_id
|
)
|
||||||
) : Promise<void>
|
)
|
||||||
{
|
)
|
||||||
await get_core_store().delete(id);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
314
source/repositories/resource.ts
Normal file
314
source/repositories/resource.ts
Normal file
|
@ -0,0 +1,314 @@
|
||||||
|
|
||||||
|
namespace _zeitbild.repository.resource
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
var _local_resource_core_store : (
|
||||||
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.storage.type_store<
|
||||||
|
int,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
) = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
var _local_resource_event_store : (
|
||||||
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.storage.type_store<
|
||||||
|
int,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
) = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
var _caldav_resource_store : (
|
||||||
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.storage.type_store<
|
||||||
|
int,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
) = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
var _resource_core_store : (
|
||||||
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.storage.type_store<
|
||||||
|
_zeitbild.type.resource_id,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
) = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function get_local_resource_core_store(
|
||||||
|
) : lib_plankton.storage.type_store<
|
||||||
|
int,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if (_local_resource_core_store === null) {
|
||||||
|
_local_resource_core_store = lib_plankton.storage.sql_table_autokey_store(
|
||||||
|
{
|
||||||
|
"database_implementation": _zeitbild.database.get_implementation(),
|
||||||
|
"table_name": "local_resources",
|
||||||
|
"key_name": "id",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return _local_resource_core_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function get_local_resource_event_store(
|
||||||
|
) : lib_plankton.storage.type_store<
|
||||||
|
int,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if (_local_resource_event_store === null) {
|
||||||
|
_local_resource_event_store = lib_plankton.storage.sql_table_autokey_store(
|
||||||
|
{
|
||||||
|
"database_implementation": _zeitbild.database.get_implementation(),
|
||||||
|
"table_name": "local_resource_events",
|
||||||
|
"key_name": "id",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return _local_resource_event_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function get_caldav_resource_store(
|
||||||
|
) : lib_plankton.storage.type_store<
|
||||||
|
int,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if (_caldav_resource_store === null) {
|
||||||
|
_caldav_resource_store = lib_plankton.storage.sql_table_autokey_store(
|
||||||
|
{
|
||||||
|
"database_implementation": _zeitbild.database.get_implementation(),
|
||||||
|
"table_name": "caldav_resources",
|
||||||
|
"key_name": "id",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return _caldav_resource_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function get_resource_core_store(
|
||||||
|
) : lib_plankton.storage.type_store<
|
||||||
|
_zeitbild.type.resource_id,
|
||||||
|
Record<string, any>,
|
||||||
|
{},
|
||||||
|
lib_plankton.storage.type_sql_table_autokey_search_term,
|
||||||
|
Record<string, any>
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if (_resource_core_store === null) {
|
||||||
|
_resource_core_store = lib_plankton.storage.sql_table_autokey_store(
|
||||||
|
{
|
||||||
|
"database_implementation": _zeitbild.database.get_implementation(),
|
||||||
|
"table_name": "resources",
|
||||||
|
"key_name": "id",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return _resource_core_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
function encode_resource_core(
|
||||||
|
stuff : {
|
||||||
|
object : _zeitbild.type.resource_object;
|
||||||
|
sub_id : int;
|
||||||
|
}
|
||||||
|
) : Record<string, any>
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"kind": stuff.object.kind,
|
||||||
|
"sub_id": stuff.sub_id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo data
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
function decode_resource_core(
|
||||||
|
row : Record<string, any>
|
||||||
|
) : {
|
||||||
|
object : _zeitbild.type.resource_object;
|
||||||
|
sub_id : int;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"object": {
|
||||||
|
"kind": row["kind"],
|
||||||
|
"data": null,
|
||||||
|
},
|
||||||
|
"sub_id": row["sub_id"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function decode_event(
|
||||||
|
row : Record<string, any>
|
||||||
|
) : _zeitbild.type.event_object
|
||||||
|
{
|
||||||
|
const decode_datetime : ((datetime_raw : string) => _zeitbild.helpers.type_datetime) = ((datetime_raw) => {
|
||||||
|
const parts : Array<string> = datetime_raw.split("|");
|
||||||
|
const timezone_shift : int = parseInt(parts[0]);
|
||||||
|
if (parts[1].length <= 10) {
|
||||||
|
return {
|
||||||
|
"timezone_shift": timezone_shift,
|
||||||
|
"date": {
|
||||||
|
"year": parseInt(parts[1].slice(0, 4)),
|
||||||
|
"month": parseInt(parts[1].slice(5, 7)),
|
||||||
|
"day": parseInt(parts[1].slice(8, 10)),
|
||||||
|
},
|
||||||
|
"time": null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
"timezone_shift": timezone_shift,
|
||||||
|
"date": {
|
||||||
|
"year": parseInt(parts[1].slice(0, 4)),
|
||||||
|
"month": parseInt(parts[1].slice(5, 7)),
|
||||||
|
"day": parseInt(parts[1].slice(8, 10)),
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"hour": parseInt(parts[1].slice(11, 13)),
|
||||||
|
"minute": parseInt(parts[1].slice(14, 16)),
|
||||||
|
"second": parseInt(parts[1].slice(17, 19)),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
"name": row["name"],
|
||||||
|
"begin": decode_datetime(row["begin"]),
|
||||||
|
"end": (
|
||||||
|
(row["end"] === null)
|
||||||
|
?
|
||||||
|
null
|
||||||
|
:
|
||||||
|
decode_datetime(row["end"])
|
||||||
|
),
|
||||||
|
"location": row["location"],
|
||||||
|
"description": row["description"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export async function read(
|
||||||
|
resource_id : _zeitbild.type.resource_id
|
||||||
|
) : Promise<_zeitbild.type.resource_object>
|
||||||
|
{
|
||||||
|
const dataset_core : Record<string, any> = await get_resource_core_store().read(resource_id);
|
||||||
|
switch (dataset_core.kind) {
|
||||||
|
case "local": {
|
||||||
|
const dataset_extra_local_core : Record<string, any> = await get_local_resource_core_store().read(dataset_core.sub_id);
|
||||||
|
const datasets_extra_local_events : Array<Record<string, any>> = await get_local_resource_event_store().search(
|
||||||
|
{
|
||||||
|
"expression": "(local_resource_id = $local_resource_id)",
|
||||||
|
"arguments": {
|
||||||
|
"local_resource_id": dataset_core.sub_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return Promise.resolve<_zeitbild.type.resource_object>(
|
||||||
|
{
|
||||||
|
"kind": "local",
|
||||||
|
"data": {
|
||||||
|
"events": datasets_extra_local_events.map(x => decode_event(x)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "caldav": {
|
||||||
|
const dataset_extra_caldav : Record<string, any> = await get_caldav_resource_store().read(dataset_core.sub_id);
|
||||||
|
return Promise.resolve<_zeitbild.type.resource_object>(
|
||||||
|
{
|
||||||
|
"kind": "caldav",
|
||||||
|
"data": {
|
||||||
|
"url": dataset_extra_caldav["url"],
|
||||||
|
"read_only": dataset_extra_caldav["read_only"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return Promise.reject<_zeitbild.type.resource_object>(
|
||||||
|
new Error("invalid resource kind: " + dataset_core.kind)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,9 +42,8 @@ namespace _zeitbild.service.calendar
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo prevent loops
|
|
||||||
*/
|
*/
|
||||||
export async function gather_events(
|
async function gather_events(
|
||||||
calendar_ids : Array<_zeitbild.type.calendar_id>,
|
calendar_ids : Array<_zeitbild.type.calendar_id>,
|
||||||
from_pit : _zeitbild.helpers.type_pit,
|
from_pit : _zeitbild.helpers.type_pit,
|
||||||
to_pit : _zeitbild.helpers.type_pit
|
to_pit : _zeitbild.helpers.type_pit
|
||||||
|
@ -52,44 +51,26 @@ namespace _zeitbild.service.calendar
|
||||||
Array<
|
Array<
|
||||||
{
|
{
|
||||||
calendar_id : _zeitbild.type.calendar_id;
|
calendar_id : _zeitbild.type.calendar_id;
|
||||||
calendar_name : string;
|
|
||||||
event : _zeitbild.type.event_object;
|
event : _zeitbild.type.event_object;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
lib_plankton.log.info(
|
|
||||||
"calendar_gather_events",
|
|
||||||
{
|
|
||||||
"calendar_ids": calendar_ids,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
let result : Array<
|
let result : Array<
|
||||||
{
|
{
|
||||||
calendar_id : _zeitbild.type.calendar_id;
|
calendar_id : _zeitbild.type.calendar_id;
|
||||||
calendar_name : string;
|
|
||||||
event : _zeitbild.type.event_object;
|
event : _zeitbild.type.event_object;
|
||||||
}
|
}
|
||||||
> = [];
|
> = [];
|
||||||
for await (const calendar_id of calendar_ids) {
|
for await (const calendar_id of calendar_ids) {
|
||||||
const calendar_object : _zeitbild.type.calendar_object = await _zeitbild.repository.calendar.read(
|
const calendar_object : _zeitbild.type.calendar_object = await _zeitbild.repository.calendar.read(calendar_id);
|
||||||
calendar_id
|
const resource_object : _zeitbild.type.resource_object = await _zeitbild.repository.resource.read(calendar_object.resource_id);
|
||||||
);
|
switch (resource_object.kind) {
|
||||||
if (calendar_object.private) {
|
case "local": {
|
||||||
lib_plankton.log.info(
|
|
||||||
"calendar_gather_events_private_calendar_blocked",
|
|
||||||
{
|
|
||||||
"calendar_id": calendar_id,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
switch (calendar_object.kind) {
|
|
||||||
case "concrete": {
|
|
||||||
result = (
|
result = (
|
||||||
result
|
result
|
||||||
.concat(
|
.concat(
|
||||||
calendar_object.data.events
|
resource_object.data.events
|
||||||
.filter(
|
.filter(
|
||||||
(event : _zeitbild.type.event_object) => _zeitbild.helpers.pit_is_between(
|
(event : _zeitbild.type.event_object) => _zeitbild.helpers.pit_is_between(
|
||||||
_zeitbild.helpers.pit_from_datetime(event.begin),
|
_zeitbild.helpers.pit_from_datetime(event.begin),
|
||||||
|
@ -100,8 +81,7 @@ namespace _zeitbild.service.calendar
|
||||||
.map(
|
.map(
|
||||||
(event : _zeitbild.type.event_object) => ({
|
(event : _zeitbild.type.event_object) => ({
|
||||||
"calendar_id": calendar_id,
|
"calendar_id": calendar_id,
|
||||||
"calendar_name": calendar_object.name,
|
"event": event,
|
||||||
"event": event
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -109,8 +89,9 @@ namespace _zeitbild.service.calendar
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "caldav": {
|
case "caldav": {
|
||||||
|
// TODO readonly
|
||||||
const url : lib_plankton.url.type_url = lib_plankton.url.decode(
|
const url : lib_plankton.url.type_url = lib_plankton.url.decode(
|
||||||
calendar_object.data.source_url
|
calendar_object.data.url
|
||||||
);
|
);
|
||||||
const http_request : lib_plankton.http.type_request = {
|
const http_request : lib_plankton.http.type_request = {
|
||||||
"version": "HTTP/2",
|
"version": "HTTP/2",
|
||||||
|
@ -189,7 +170,6 @@ namespace _zeitbild.service.calendar
|
||||||
.map(
|
.map(
|
||||||
(event) => ({
|
(event) => ({
|
||||||
"calendar_id": calendar_id,
|
"calendar_id": calendar_id,
|
||||||
"calendar_name": calendar_object.name,
|
|
||||||
"event": event,
|
"event": event,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -197,6 +177,11 @@ namespace _zeitbild.service.calendar
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
return Promise.reject(
|
||||||
|
new Error("invalid resource kind: " + resource_object["kind"])
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ namespace _zeitbild.type
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
type role = (
|
export type role = (
|
||||||
|
"admin"
|
||||||
|
|
|
||||||
"editor"
|
"editor"
|
||||||
|
|
|
|
||||||
"viewer"
|
"viewer"
|
||||||
|
@ -15,21 +17,16 @@ namespace _zeitbild.type
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
type user_id = int;
|
export type user_id = int;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
type user_object = {
|
export type user_object = {
|
||||||
name : string;
|
name : string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
export type event_id = int;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type event_object = {
|
export type event_object = {
|
||||||
|
@ -55,28 +52,18 @@ namespace _zeitbild.type
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type calendar_id = int;
|
export type resource_id = int;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type calendar_object = (
|
export type resource_object = (
|
||||||
{
|
{
|
||||||
name : string;
|
kind : "local";
|
||||||
private : boolean;
|
|
||||||
}
|
|
||||||
&
|
|
||||||
(
|
|
||||||
{
|
|
||||||
kind : "concrete";
|
|
||||||
data : {
|
data : {
|
||||||
users : Array<
|
events : Array<
|
||||||
{
|
event_object
|
||||||
id : user_id;
|
|
||||||
role : role;
|
|
||||||
}
|
|
||||||
>;
|
>;
|
||||||
events : Array<event_object>;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
|
||||||
|
@ -84,10 +71,48 @@ namespace _zeitbild.type
|
||||||
kind : "caldav";
|
kind : "caldav";
|
||||||
data : {
|
data : {
|
||||||
read_only : boolean;
|
read_only : boolean;
|
||||||
source_url : string;
|
url : string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type calendar_id = int;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type calendar_object = {
|
||||||
|
name : string;
|
||||||
|
public : boolean;
|
||||||
|
members : Array<
|
||||||
|
{
|
||||||
|
user_id : user_id;
|
||||||
|
role : role;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
// resource : resource_object;
|
||||||
|
resource_id : resource_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export type root = {
|
||||||
|
users : Array<
|
||||||
|
{
|
||||||
|
id : user_id;
|
||||||
|
object : user_object;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
calendars : Array<
|
||||||
|
{
|
||||||
|
id : calendar_id;
|
||||||
|
object : calendar_object;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ ${dir_temp}/zeitbild-unlinked.js: \
|
||||||
${dir_source}/conf.ts \
|
${dir_source}/conf.ts \
|
||||||
${dir_source}/database.ts \
|
${dir_source}/database.ts \
|
||||||
${dir_source}/types.ts \
|
${dir_source}/types.ts \
|
||||||
|
${dir_source}/repositories/resource.ts \
|
||||||
${dir_source}/repositories/calendar.ts \
|
${dir_source}/repositories/calendar.ts \
|
||||||
${dir_source}/services/calendar.ts \
|
${dir_source}/services/calendar.ts \
|
||||||
${dir_source}/api/base.ts \
|
${dir_source}/api/base.ts \
|
||||||
|
|
Loading…
Add table
Reference in a new issue