2024-09-12 00:03:29 +02:00
|
|
|
|
|
|
|
namespace _zeitbild.service.calendar
|
|
|
|
{
|
|
|
|
|
2024-09-18 18:17:25 +02:00
|
|
|
/**
|
2024-09-30 19:52:24 +02:00
|
|
|
* checks if a user has a sufficient access level
|
2024-09-18 18:17:25 +02:00
|
|
|
*/
|
2024-09-30 19:52:24 +02:00
|
|
|
function get_access_level(
|
|
|
|
calendar_object : _zeitbild.type_calendar_object,
|
|
|
|
user_id : _zeitbild.type_user_id
|
|
|
|
) : _zeitbild.enum_access_level
|
2024-09-18 18:17:25 +02:00
|
|
|
{
|
2024-09-30 19:52:24 +02:00
|
|
|
return calendar_object.access.attributed.get(
|
|
|
|
user_id,
|
|
|
|
lib_plankton.pod.make_filled<_zeitbild.enum_access_level>(
|
|
|
|
calendar_object.access.default_level
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* checks if a user has a sufficient access level
|
|
|
|
*/
|
|
|
|
function wrap_check_access_level<type_result>(
|
|
|
|
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<type_result>
|
|
|
|
)
|
|
|
|
) : Promise<type_result>
|
|
|
|
{
|
|
|
|
const access_level : _zeitbild.enum_access_level = get_access_level(
|
|
|
|
calendar_object,
|
|
|
|
user_id
|
|
|
|
);
|
|
|
|
if (! _zeitbild.value_object.access_level.order(threshold, access_level)) {
|
|
|
|
return Promise.reject<type_result>(
|
|
|
|
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);
|
|
|
|
}
|
2024-09-18 18:17:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-12 19:35:31 +02:00
|
|
|
/**
|
|
|
|
*/
|
|
|
|
export function overview(
|
2024-09-21 11:05:24 +02:00
|
|
|
user_id : _zeitbild.type_user_id
|
2024-09-12 19:35:31 +02:00
|
|
|
) : Promise<
|
|
|
|
Array<
|
|
|
|
{
|
2024-09-21 11:05:24 +02:00
|
|
|
id : _zeitbild.type_calendar_id;
|
2024-09-12 19:35:31 +02:00
|
|
|
name : string;
|
2024-09-21 11:05:24 +02:00
|
|
|
access_level : _zeitbild.enum_access_level;
|
2024-09-12 19:35:31 +02:00
|
|
|
}
|
|
|
|
>
|
|
|
|
>
|
|
|
|
{
|
|
|
|
return _zeitbild.repository.calendar.overview(user_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-12 00:03:29 +02:00
|
|
|
/**
|
|
|
|
*/
|
|
|
|
export async function get(
|
2024-09-30 19:52:24 +02:00
|
|
|
calendar_id : _zeitbild.type_calendar_id,
|
|
|
|
user_id : _zeitbild.type_user_id
|
2024-09-21 11:05:24 +02:00
|
|
|
) : Promise<_zeitbild.type_calendar_object>
|
2024-09-12 00:03:29 +02:00
|
|
|
{
|
2024-09-30 19:52:24 +02:00
|
|
|
const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(calendar_id);
|
|
|
|
return wrap_check_access_level<_zeitbild.type_calendar_object>(
|
|
|
|
calendar_object,
|
|
|
|
user_id,
|
|
|
|
_zeitbild.enum_access_level.view,
|
|
|
|
() => Promise.resolve(calendar_object)
|
|
|
|
);
|
2024-09-12 00:03:29 +02:00
|
|
|
}
|
2024-09-12 19:35:31 +02:00
|
|
|
|
2024-09-12 00:03:29 +02:00
|
|
|
|
2024-09-26 10:33:33 +02:00
|
|
|
/**
|
|
|
|
*/
|
2024-09-30 19:52:24 +02:00
|
|
|
export function add(
|
|
|
|
calendar_object : _zeitbild.type_calendar_object
|
|
|
|
) : Promise<_zeitbild.type_calendar_id>
|
|
|
|
{
|
|
|
|
return _zeitbild.repository.calendar.create(calendar_object);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*/
|
|
|
|
export async function change(
|
|
|
|
calendar_id : _zeitbild.type_calendar_id,
|
2024-09-26 10:33:33 +02:00
|
|
|
calendar_object : _zeitbild.type_calendar_object,
|
2024-09-30 19:52:24 +02:00
|
|
|
user_id : _zeitbild.type_user_id
|
|
|
|
) : Promise<void>
|
2024-09-26 10:33:33 +02:00
|
|
|
{
|
2024-09-30 19:52:24 +02:00
|
|
|
const calendar_object_current : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(calendar_id);
|
|
|
|
return wrap_check_access_level<void>(
|
|
|
|
calendar_object_current,
|
2024-09-26 10:33:33 +02:00
|
|
|
user_id,
|
2024-09-30 19:52:24 +02:00
|
|
|
_zeitbild.enum_access_level.admin,
|
|
|
|
() => _zeitbild.repository.calendar.update(calendar_id, calendar_object)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*/
|
|
|
|
export async function remove(
|
|
|
|
calendar_id : _zeitbild.type_calendar_id,
|
|
|
|
user_id : _zeitbild.type_user_id
|
|
|
|
) : Promise<void>
|
|
|
|
{
|
|
|
|
const calendar_object_current : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(calendar_id);
|
|
|
|
return wrap_check_access_level<void>(
|
|
|
|
calendar_object_current,
|
|
|
|
user_id,
|
|
|
|
_zeitbild.enum_access_level.admin,
|
|
|
|
() => _zeitbild.repository.calendar.delete_(calendar_id)
|
2024-09-26 10:33:33 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-30 12:01:40 +02:00
|
|
|
/**
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-25 14:50:32 +02:00
|
|
|
/**
|
|
|
|
*/
|
|
|
|
export async function event_add(
|
|
|
|
calendar_id : _zeitbild.type_calendar_id,
|
2024-09-26 10:33:33 +02:00
|
|
|
event_object : _zeitbild.type_event_object,
|
|
|
|
user_id : _zeitbild.type_user_id
|
2024-09-25 14:50:32 +02:00
|
|
|
) : Promise<void>
|
|
|
|
{
|
2024-09-25 15:28:25 +02:00
|
|
|
const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(
|
2024-09-25 14:50:32 +02:00
|
|
|
calendar_id
|
|
|
|
);
|
2024-09-26 10:33:33 +02:00
|
|
|
return wrap_check_access_level<void>(
|
|
|
|
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<void>(undefined);
|
|
|
|
}
|
2024-09-25 14:50:32 +02:00
|
|
|
);
|
2024-09-26 10:33:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2024-09-30 12:01:40 +02:00
|
|
|
*/
|
|
|
|
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<void>
|
|
|
|
{
|
|
|
|
const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(
|
|
|
|
calendar_id
|
|
|
|
);
|
|
|
|
return wrap_check_access_level<void>(
|
|
|
|
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<void>(undefined);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2024-09-26 10:33:33 +02:00
|
|
|
*/
|
|
|
|
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<void>
|
|
|
|
{
|
|
|
|
const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(
|
|
|
|
calendar_id
|
|
|
|
);
|
|
|
|
return wrap_check_access_level<void>(
|
|
|
|
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<void>(undefined);
|
|
|
|
}
|
2024-09-25 15:28:25 +02:00
|
|
|
);
|
2024-09-25 14:50:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-09-12 00:03:29 +02:00
|
|
|
/**
|
|
|
|
*/
|
2024-09-12 19:35:31 +02:00
|
|
|
async function get_events(
|
2024-09-21 11:05:24 +02:00
|
|
|
calendar_id : _zeitbild.type_calendar_id,
|
2024-09-26 16:47:38 +02:00
|
|
|
from_pit : lib_plankton.pit.type_pit,
|
|
|
|
to_pit : lib_plankton.pit.type_pit,
|
2024-09-26 10:33:33 +02:00
|
|
|
user_id : _zeitbild.type_user_id
|
2024-09-12 00:03:29 +02:00
|
|
|
) : Promise<
|
|
|
|
Array<
|
2024-09-30 12:01:40 +02:00
|
|
|
{
|
|
|
|
id : (null | _zeitbild.type_local_resource_event_id);
|
|
|
|
object : _zeitbild.type_event_object;
|
|
|
|
}
|
2024-09-12 00:03:29 +02:00
|
|
|
>
|
|
|
|
>
|
|
|
|
{
|
2024-09-21 11:05:24 +02:00
|
|
|
const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(calendar_id);
|
2024-09-30 12:01:40 +02:00
|
|
|
return wrap_check_access_level<Array<{id : (null | _zeitbild.type_local_resource_event_id); object : _zeitbild.type_event_object;}>>(
|
2024-09-26 10:33:33 +02:00
|
|
|
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(
|
2024-09-30 12:01:40 +02:00
|
|
|
(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,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
2024-09-26 10:33:33 +02:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.then(
|
2024-09-30 12:01:40 +02:00
|
|
|
(event_entries) => Promise.resolve(
|
|
|
|
event_entries
|
2024-09-26 10:33:33 +02:00
|
|
|
.filter(
|
2024-09-30 12:01:40 +02:00
|
|
|
(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),
|
2024-09-26 10:33:33 +02:00
|
|
|
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
|
|
|
|
:
|
|
|
|
"???"
|
|
|
|
),
|
2024-10-10 20:24:05 +02:00
|
|
|
"public": true, // todo?
|
2024-09-26 10:33:33 +02:00
|
|
|
"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)
|
|
|
|
)
|
2024-09-30 12:01:40 +02:00
|
|
|
.map(
|
|
|
|
(event) => ({
|
|
|
|
"id": null,
|
|
|
|
"object": event,
|
|
|
|
})
|
|
|
|
)
|
2024-09-25 15:28:25 +02:00
|
|
|
.filter(
|
2024-09-30 12:01:40 +02:00
|
|
|
(event_entry) => lib_plankton.pit.is_between(
|
|
|
|
lib_plankton.pit.from_datetime(event_entry.object.begin),
|
2024-09-25 15:28:25 +02:00
|
|
|
from_pit,
|
|
|
|
to_pit
|
|
|
|
)
|
|
|
|
)
|
2024-09-26 10:33:33 +02:00
|
|
|
);
|
|
|
|
break;
|
2024-09-12 19:35:31 +02:00
|
|
|
}
|
2024-09-26 10:33:33 +02:00
|
|
|
default: {
|
|
|
|
return Promise.reject(
|
|
|
|
new Error("invalid resource kind: " + resource_object["kind"])
|
|
|
|
);
|
|
|
|
break;
|
2024-09-12 19:35:31 +02:00
|
|
|
}
|
2024-09-26 10:33:33 +02:00
|
|
|
}
|
2024-09-12 19:35:31 +02:00
|
|
|
}
|
2024-09-26 10:33:33 +02:00
|
|
|
);
|
2024-09-12 19:35:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2024-09-26 10:33:33 +02:00
|
|
|
* @todo check access level
|
2024-09-12 19:35:31 +02:00
|
|
|
*/
|
|
|
|
export async function gather_events(
|
2024-09-26 10:33:33 +02:00
|
|
|
calendar_ids_wanted : (null | Array<_zeitbild.type_calendar_id>),
|
2024-09-26 16:47:38 +02:00
|
|
|
from_pit : lib_plankton.pit.type_pit,
|
|
|
|
to_pit : lib_plankton.pit.type_pit,
|
2024-09-26 10:33:33 +02:00
|
|
|
user_id : _zeitbild.type_user_id
|
2024-09-12 19:35:31 +02:00
|
|
|
) : Promise<
|
|
|
|
Array<
|
|
|
|
{
|
2024-09-21 11:05:24 +02:00
|
|
|
calendar_id : _zeitbild.type_calendar_id;
|
2024-09-12 20:42:06 +02:00
|
|
|
calendar_name : string;
|
2024-09-30 19:52:24 +02:00
|
|
|
access_level : _zeitbild.enum_access_level;
|
2024-09-30 12:01:40 +02:00
|
|
|
event_id : (null | _zeitbild.type_local_resource_event_id);
|
|
|
|
event_object : _zeitbild.type_event_object;
|
2024-09-12 19:35:31 +02:00
|
|
|
}
|
|
|
|
>
|
|
|
|
>
|
|
|
|
{
|
2024-09-26 10:33:33 +02:00
|
|
|
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();
|
2024-09-12 19:35:31 +02:00
|
|
|
return (
|
|
|
|
Promise.all(
|
|
|
|
calendar_ids
|
|
|
|
.map(
|
2024-09-12 20:42:06 +02:00
|
|
|
async (calendar_id) => {
|
2024-09-21 11:05:24 +02:00
|
|
|
const calendar_object : _zeitbild.type_calendar_object = await _zeitbild.repository.calendar.read(
|
2024-09-12 20:42:06 +02:00
|
|
|
calendar_id
|
|
|
|
);
|
2024-09-30 19:52:24 +02:00
|
|
|
const access_level : _zeitbild.enum_access_level = get_access_level(
|
|
|
|
calendar_object,
|
|
|
|
user_id
|
|
|
|
);
|
2024-09-30 12:01:40 +02:00
|
|
|
const events : Array<
|
|
|
|
{
|
|
|
|
id : (null | _zeitbild.type_local_resource_event_id);
|
|
|
|
object : _zeitbild.type_event_object;
|
|
|
|
}
|
|
|
|
> = await get_events(
|
2024-09-12 20:42:06 +02:00
|
|
|
calendar_id,
|
|
|
|
from_pit,
|
2024-09-26 10:33:33 +02:00
|
|
|
to_pit,
|
|
|
|
user_id
|
2024-09-12 20:42:06 +02:00
|
|
|
);
|
|
|
|
return Promise.resolve(
|
|
|
|
events
|
|
|
|
.map(
|
2024-09-30 12:01:40 +02:00
|
|
|
(event_entry) => ({
|
2024-09-12 16:35:57 +02:00
|
|
|
"calendar_id": calendar_id,
|
2024-09-12 20:42:06 +02:00
|
|
|
"calendar_name": calendar_object.name,
|
2024-09-30 19:52:24 +02:00
|
|
|
"access_level": access_level,
|
2024-09-30 12:01:40 +02:00
|
|
|
"event_id": event_entry.id,
|
|
|
|
"event_object": event_entry.object,
|
2024-09-12 16:35:57 +02:00
|
|
|
})
|
|
|
|
)
|
2024-09-12 20:42:06 +02:00
|
|
|
);
|
|
|
|
}
|
2024-09-12 19:35:31 +02:00
|
|
|
)
|
|
|
|
)
|
|
|
|
.then(
|
|
|
|
(sub_results) => sub_results.reduce(
|
|
|
|
(x, y) => x.concat(y),
|
|
|
|
[]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
2024-09-12 00:03:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|