[task-192] [int] geht zum Teil
This commit is contained in:
parent
c5d52a7df5
commit
8ddba38bd5
15 changed files with 865 additions and 168 deletions
|
@ -5,7 +5,7 @@
|
||||||
"kind": "stdout",
|
"kind": "stdout",
|
||||||
"data": {
|
"data": {
|
||||||
"threshold": "info",
|
"threshold": "info",
|
||||||
"format": "human_readable"
|
"format": "jsonl_structured"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,14 +11,16 @@ namespace _zeitbild.api
|
||||||
register<
|
register<
|
||||||
null,
|
null,
|
||||||
(
|
(
|
||||||
lib_plankton.ical.type_vcalendar
|
null
|
||||||
|
|
|
|
||||||
string
|
string
|
||||||
|
|
|
||||||
|
lib_plankton.ical.type_vcalendar
|
||||||
)
|
)
|
||||||
>(
|
>(
|
||||||
rest_subject,
|
rest_subject,
|
||||||
lib_plankton.caldav.enum_method.report,
|
lib_plankton.caldav.enum_method.report,
|
||||||
"/caldav",
|
"/caldav/project/:id",
|
||||||
{
|
{
|
||||||
"description": "trägt Veranstaltungen aus verschiedenen Kalendern zusammen im ical-Format",
|
"description": "trägt Veranstaltungen aus verschiedenen Kalendern zusammen im ical-Format",
|
||||||
"query_parameters": () => ([
|
"query_parameters": () => ([
|
||||||
|
@ -48,89 +50,82 @@ namespace _zeitbild.api
|
||||||
"type": "string",
|
"type": "string",
|
||||||
}),
|
}),
|
||||||
"response_body_mimetype": "text/calendar",
|
"response_body_mimetype": "text/calendar",
|
||||||
"response_body_encode": (output) => Buffer.from(
|
"response_body_encode": (output) => (
|
||||||
(typeof(output) === "string")
|
(output === null)
|
||||||
?
|
?
|
||||||
output
|
null
|
||||||
:
|
:
|
||||||
lib_plankton.ical.ics_encode(output)
|
Buffer.from(
|
||||||
|
(typeof(output) === "string")
|
||||||
|
?
|
||||||
|
output
|
||||||
|
:
|
||||||
|
lib_plankton.ical.ics_encode(output)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"restriction": restriction_none,
|
"restriction": restriction_none,
|
||||||
|
/**
|
||||||
|
* @todo use stuff.path_parameters["id"]
|
||||||
|
*/
|
||||||
"execution": async (stuff) => {
|
"execution": async (stuff) => {
|
||||||
const user_id : (null | _zeitbild.type_user_id) = await (
|
const user_id : (null | type_user_id) = await _zeitbild.api.web_auth(
|
||||||
session_from_stuff(stuff)
|
stuff.headers["Authorization"]
|
||||||
.then(
|
??
|
||||||
(session : {key : string; value : lib_plankton.session.type_session;}) => (
|
stuff.headers["authorization"]
|
||||||
_zeitbild.service.user.identify(session.value.name)
|
??
|
||||||
.catch(x => Promise.resolve(null))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.catch(x => Promise.resolve(null))
|
|
||||||
);
|
|
||||||
|
|
||||||
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
|
null
|
||||||
);
|
);
|
||||||
|
if (user_id === null) {
|
||||||
const auth_hash_shall : string = lib_plankton.sha256.get(
|
|
||||||
(stuff.query_parameters["calendar_ids"] ?? ""),
|
|
||||||
_zeitbild.conf.get()["misc"]["auth_salt"]
|
|
||||||
);
|
|
||||||
const auth_hash_is : string = stuff.query_parameters["auth"];
|
|
||||||
/**
|
|
||||||
* @todo remove
|
|
||||||
*/
|
|
||||||
lib_plankton.log.info(
|
|
||||||
"auth_hashes",
|
|
||||||
{
|
|
||||||
"shall": auth_hash_shall,
|
|
||||||
"is": auth_hash_is,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (! (auth_hash_is === auth_hash_shall)) {
|
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
{
|
{
|
||||||
"status_code": 403,
|
"status_code": 401,
|
||||||
"data": "not authorized",
|
"data": null,
|
||||||
|
"extra_headers": {
|
||||||
|
"WWW-Authenticate": "Basic realm=Restricted",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
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 (
|
return (
|
||||||
_zeitbild.service.calendar.gather_events(
|
_zeitbild.service.calendar.gather_events(
|
||||||
calendar_ids_wanted,
|
calendar_ids_wanted,
|
||||||
|
|
|
@ -9,46 +9,45 @@ namespace _zeitbild.api
|
||||||
) : void
|
) : void
|
||||||
{
|
{
|
||||||
register<
|
register<
|
||||||
null,
|
(
|
||||||
string
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.xml.type_node_data
|
||||||
|
),
|
||||||
|
lib_plankton.xml.type_node_data
|
||||||
>(
|
>(
|
||||||
rest_subject,
|
rest_subject,
|
||||||
lib_plankton.caldav.enum_method.propfind,
|
lib_plankton.caldav.enum_method.propfind,
|
||||||
"/caldav",
|
"/caldav",
|
||||||
{
|
{
|
||||||
"query_parameters": () => ([
|
"request_body_mimetype": () => "text/xml",
|
||||||
{
|
"request_body_decode": () => async (body, header_content_type) => (
|
||||||
"name": "from",
|
(
|
||||||
"required": false,
|
(header_content_type !== null)
|
||||||
"description": "UNIX timestamp",
|
&&
|
||||||
},
|
(
|
||||||
{
|
(header_content_type.startsWith("text/xml"))
|
||||||
"name": "to",
|
||
|
||||||
"required": false,
|
(header_content_type.startsWith("application/xml"))
|
||||||
"description": "UNIX timestamp",
|
)
|
||||||
},
|
)
|
||||||
{
|
?
|
||||||
"name": "calendar_ids",
|
lib_plankton.xml.parse(body.toString())
|
||||||
"required": false,
|
:
|
||||||
"description": "comma separated",
|
Promise.resolve<any>(null)
|
||||||
},
|
),
|
||||||
{
|
|
||||||
"name": "auth",
|
|
||||||
"required": true,
|
|
||||||
"description": "",
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
"output_schema": () => ({
|
"output_schema": () => ({
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
}),
|
}),
|
||||||
"response_body_mimetype": "text/xml; charset=utf-8",
|
"response_body_mimetype": "text/xml",
|
||||||
"response_body_encode": output => Buffer.from(output),
|
"response_body_encode": output => Promise.resolve<Buffer>(
|
||||||
|
Buffer.from(
|
||||||
|
lib_plankton.xml.get_node_logic(output).compile(0)
|
||||||
|
)
|
||||||
|
),
|
||||||
// "restriction": restriction_basic_auth,
|
// "restriction": restriction_basic_auth,
|
||||||
"restriction": restriction_none,
|
"restriction": restriction_none,
|
||||||
/**
|
|
||||||
* @todo examine body
|
|
||||||
*/
|
|
||||||
"execution": async (stuff) => {
|
"execution": async (stuff) => {
|
||||||
const user_id : (null | type_user_id) = await _zeitbild.api.web_auth(
|
const user_id : (null | type_user_id) = await _zeitbild.api.web_auth(
|
||||||
stuff.headers["Authorization"]
|
stuff.headers["Authorization"]
|
||||||
|
@ -61,7 +60,10 @@ namespace _zeitbild.api
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
{
|
{
|
||||||
"status_code": 401,
|
"status_code": 401,
|
||||||
"data": "",
|
"data": {
|
||||||
|
"kind": "text",
|
||||||
|
"data": ""
|
||||||
|
},
|
||||||
"extra_headers": {
|
"extra_headers": {
|
||||||
"WWW-Authenticate": "Basic realm=Restricted",
|
"WWW-Authenticate": "Basic realm=Restricted",
|
||||||
}
|
}
|
||||||
|
@ -69,54 +71,35 @@ namespace _zeitbild.api
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (
|
const output : (null | lib_plankton.xml.type_node_data) = _zeitbild.service.caldav.probe(
|
||||||
_zeitbild.service.calendar.overview(user_id)
|
stuff.input
|
||||||
.then(
|
|
||||||
(data_raw) => Promise.resolve(
|
|
||||||
data_raw
|
|
||||||
.map(
|
|
||||||
(entry) => ({
|
|
||||||
"id": entry.id,
|
|
||||||
"name": entry.name,
|
|
||||||
"access_level": _zeitbild.value_object.access_level.to_string(entry.access_level),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then(
|
|
||||||
(data) => Promise.resolve({
|
|
||||||
"status_code": 207,
|
|
||||||
"data": (
|
|
||||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
|
||||||
+
|
|
||||||
lib_plankton.webdav.data_multistatus_encode(
|
|
||||||
{
|
|
||||||
"responses": [
|
|
||||||
{
|
|
||||||
"href": "/caldav/events",
|
|
||||||
"body": {
|
|
||||||
"propstats": data.map(
|
|
||||||
(entry) => ({
|
|
||||||
"prop": [
|
|
||||||
{"name": "displayname", "value": entry.name},
|
|
||||||
// {"name": "cs:getctag", "value": "47"}, // TODO correct value
|
|
||||||
// {"name": "current-user-privilege-set", "value": ""},
|
|
||||||
],
|
|
||||||
"status": "HTTP/2.0 200 OK",
|
|
||||||
"description": entry.access_level,
|
|
||||||
})
|
|
||||||
),
|
|
||||||
},
|
|
||||||
"description": null,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": null,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
if (output !== null) {
|
||||||
|
return Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 207,
|
||||||
|
"data": output
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 501,
|
||||||
|
"data": {
|
||||||
|
"kind": "root",
|
||||||
|
"data": {
|
||||||
|
"version": "1.0",
|
||||||
|
"encoding": "utf-8",
|
||||||
|
"content": {
|
||||||
|
"kind": "text",
|
||||||
|
"data": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
115
source/api/actions/caldav_probe_via_well_known.ts
Normal file
115
source/api/actions/caldav_probe_via_well_known.ts
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
namespace _zeitbild.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function register_caldav_probe_via_well_known(
|
||||||
|
rest_subject : lib_plankton.rest_caldav.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
register<
|
||||||
|
(
|
||||||
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.xml.type_node_data
|
||||||
|
),
|
||||||
|
lib_plankton.xml.type_node_data
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.caldav.enum_method.propfind,
|
||||||
|
"/.well-known/caldav",
|
||||||
|
{
|
||||||
|
"request_body_mimetype": () => "text/xml",
|
||||||
|
"request_body_decode": () => async (body, header_content_type) => (
|
||||||
|
(
|
||||||
|
(header_content_type !== null)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
(header_content_type.startsWith("text/xml"))
|
||||||
|
||
|
||||||
|
(header_content_type.startsWith("application/xml"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
?
|
||||||
|
lib_plankton.xml.parse(body.toString())
|
||||||
|
:
|
||||||
|
Promise.resolve<any>(null)
|
||||||
|
),
|
||||||
|
"output_schema": () => ({
|
||||||
|
"nullable": false,
|
||||||
|
"type": "string",
|
||||||
|
}),
|
||||||
|
"response_body_mimetype": "text/xml",
|
||||||
|
"response_body_encode": output => Promise.resolve<Buffer>(
|
||||||
|
Buffer.from(
|
||||||
|
lib_plankton.xml.get_node_logic(output).compile(0)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// "restriction": restriction_basic_auth,
|
||||||
|
"restriction": restriction_none,
|
||||||
|
"execution": async (stuff) => {
|
||||||
|
const user_id : (null | type_user_id) = await _zeitbild.api.web_auth(
|
||||||
|
stuff.headers["Authorization"]
|
||||||
|
??
|
||||||
|
stuff.headers["authorization"]
|
||||||
|
??
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if (user_id === null) {
|
||||||
|
return Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 401,
|
||||||
|
"data": {
|
||||||
|
"kind": "text",
|
||||||
|
"data": ""
|
||||||
|
},
|
||||||
|
"extra_headers": {
|
||||||
|
"WWW-Authenticate": "Basic realm=Restricted",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const output : (null | lib_plankton.xml.type_node_data) = _zeitbild.service.caldav.probe(
|
||||||
|
stuff.input,
|
||||||
|
{
|
||||||
|
"force_props": [
|
||||||
|
"D:displayname",
|
||||||
|
"D:resourcetype",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (output !== null) {
|
||||||
|
return Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 207,
|
||||||
|
"data": output
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 501,
|
||||||
|
"data": {
|
||||||
|
"kind": "root",
|
||||||
|
"data": {
|
||||||
|
"version": "1.0",
|
||||||
|
"encoding": "utf-8",
|
||||||
|
"content": {
|
||||||
|
"kind": "text",
|
||||||
|
"data": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
91
source/api/actions/caldav_projects.ts
Normal file
91
source/api/actions/caldav_projects.ts
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
namespace _zeitbild.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function register_caldav_projects(
|
||||||
|
rest_subject : lib_plankton.rest_caldav.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
register<
|
||||||
|
(
|
||||||
|
null
|
||||||
|
|
|
||||||
|
lib_plankton.xml.type_node_data
|
||||||
|
),
|
||||||
|
lib_plankton.xml.type_node_data
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.caldav.enum_method.propfind,
|
||||||
|
"/caldav/project",
|
||||||
|
{
|
||||||
|
"output_schema": () => ({
|
||||||
|
"nullable": false,
|
||||||
|
"type": "string",
|
||||||
|
}),
|
||||||
|
"request_body_mimetype": () => "text/xml",
|
||||||
|
"request_body_decode": () => async (body, header_content_type) => (
|
||||||
|
(
|
||||||
|
(header_content_type !== null)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
(header_content_type.startsWith("text/xml"))
|
||||||
|
||
|
||||||
|
(header_content_type.startsWith("application/xml"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
?
|
||||||
|
lib_plankton.xml.parse(body.toString())
|
||||||
|
:
|
||||||
|
Promise.resolve<any>(null)
|
||||||
|
),
|
||||||
|
"response_body_mimetype": "text/xml",
|
||||||
|
"response_body_encode": output => Promise.resolve<Buffer>(
|
||||||
|
Buffer.from(
|
||||||
|
lib_plankton.xml.get_node_logic(output).compile(0)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// "restriction": restriction_basic_auth,
|
||||||
|
"restriction": restriction_none,
|
||||||
|
"execution": async (stuff) => {
|
||||||
|
const user_id : (null | type_user_id) = await _zeitbild.api.web_auth(
|
||||||
|
stuff.headers["Authorization"]
|
||||||
|
??
|
||||||
|
stuff.headers["authorization"]
|
||||||
|
??
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if (user_id === null) {
|
||||||
|
return Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 401,
|
||||||
|
"data": {
|
||||||
|
"kind": "text",
|
||||||
|
"data": ""
|
||||||
|
},
|
||||||
|
"extra_headers": {
|
||||||
|
"WWW-Authenticate": "Basic realm=Restricted",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (
|
||||||
|
_zeitbild.service.caldav.projects(user_id)
|
||||||
|
.then(
|
||||||
|
(output) => Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 207,
|
||||||
|
"data": output,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
source/api/actions/caldav_put.ts
Normal file
32
source/api/actions/caldav_put.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
namespace _zeitbild.api
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function register_caldav_put(
|
||||||
|
rest_subject : lib_plankton.rest_caldav.type_rest
|
||||||
|
) : void
|
||||||
|
{
|
||||||
|
register<
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
>(
|
||||||
|
rest_subject,
|
||||||
|
lib_plankton.caldav.enum_method.put,
|
||||||
|
"/caldav",
|
||||||
|
{
|
||||||
|
"restriction": restriction_none,
|
||||||
|
"execution": async (stuff) => {
|
||||||
|
return Promise.resolve(
|
||||||
|
{
|
||||||
|
"status_code": 200,
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ namespace _zeitbild.api
|
||||||
lib_plankton.http.enum_method.get,
|
lib_plankton.http.enum_method.get,
|
||||||
_zeitbild.conf.get().server.path_base + "/meta/ping",
|
_zeitbild.conf.get().server.path_base + "/meta/ping",
|
||||||
{
|
{
|
||||||
"description": "sendet ein 'pong' zurück; gedacht um die Erreichbarkeit des Backends zu prüfen",
|
"description": () => "sendet ein 'pong' zurück; gedacht um die Erreichbarkeit des Backends zu prüfen",
|
||||||
"input_schema": () => ({
|
"input_schema": () => ({
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
}),
|
}),
|
||||||
|
@ -25,8 +25,10 @@ namespace _zeitbild.api
|
||||||
"nullable": false,
|
"nullable": false,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
}),
|
}),
|
||||||
"restriction": restriction_none,
|
"response_body_encode": () => (body) => Promise.resolve<string>(body),
|
||||||
"execution": () => {
|
"response_body_mimetype": () => "text/plain",
|
||||||
|
"restriction": () => restriction_none,
|
||||||
|
"execution": () => () => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"data": "pong",
|
"data": "pong",
|
||||||
|
|
|
@ -17,14 +17,14 @@ namespace _zeitbild.api
|
||||||
lib_plankton.http.enum_method.get,
|
lib_plankton.http.enum_method.get,
|
||||||
_zeitbild.conf.get().server.path_base + "/meta/spec",
|
_zeitbild.conf.get().server.path_base + "/meta/spec",
|
||||||
{
|
{
|
||||||
"description": "gibt die API-Spezifikation im OpenAPI-Format aus",
|
"description": () => "gibt die API-Spezifikation im OpenAPI-Format aus",
|
||||||
"input_schema": () => ({
|
"input_schema": () => ({
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
}),
|
}),
|
||||||
"output_schema": () => ({
|
"output_schema": () => ({
|
||||||
}),
|
}),
|
||||||
"restriction": restriction_none,
|
"restriction": () => restriction_none,
|
||||||
"execution": () => {
|
"execution": () => () => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"data": lib_plankton.rest_caldav.to_oas(rest_subject),
|
"data": lib_plankton.rest_caldav.to_oas(rest_subject),
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace _zeitbild.api
|
||||||
lib_plankton.http.enum_method.post,
|
lib_plankton.http.enum_method.post,
|
||||||
"/session/begin",
|
"/session/begin",
|
||||||
{
|
{
|
||||||
"description": "führt die Anmeldung am System aus um geschützte Aktionen nutzen zu können",
|
"description": () => "führt die Anmeldung am System aus um geschützte Aktionen nutzen zu können",
|
||||||
"input_schema": () => ({
|
"input_schema": () => ({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -44,8 +44,8 @@ namespace _zeitbild.api
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "der Sitzungs-Schlüssel, der als Header 'X-Session-Key' gesetzt werden muss um Erlaubnis zur Ausführung geschützter Aktionen zu erhalten",
|
"description": "der Sitzungs-Schlüssel, der als Header 'X-Session-Key' gesetzt werden muss um Erlaubnis zur Ausführung geschützter Aktionen zu erhalten",
|
||||||
}),
|
}),
|
||||||
"restriction": restriction_none,
|
"restriction": () => restriction_none,
|
||||||
"execution": async ({"input": input}) => {
|
"execution": () => async ({"input": input}) => {
|
||||||
if (input === null) {
|
if (input === null) {
|
||||||
return Promise.reject(new Error("impossible"));
|
return Promise.reject(new Error("impossible"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,15 +19,15 @@ namespace _zeitbild.api
|
||||||
lib_plankton.http.enum_method.post,
|
lib_plankton.http.enum_method.post,
|
||||||
"/session/prepare",
|
"/session/prepare",
|
||||||
{
|
{
|
||||||
"description": "gibt die nötigen Werkzeuge für eine Anmeldung aus",
|
"description": () => "gibt die nötigen Werkzeuge für eine Anmeldung aus",
|
||||||
"input_schema": () => ({
|
"input_schema": () => ({
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
}),
|
}),
|
||||||
"output_schema": () => ({
|
"output_schema": () => ({
|
||||||
"nullable": false
|
"nullable": false
|
||||||
}),
|
}),
|
||||||
"restriction": restriction_none,
|
"restriction": () => restriction_none,
|
||||||
"execution": async (stuff) => {
|
"execution": () => async (stuff) => {
|
||||||
const preparation = await _zeitbild.auth.prepare(stuff.input);
|
const preparation = await _zeitbild.auth.prepare(stuff.input);
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace _zeitbild.api
|
||||||
http_method : lib_plankton.caldav.enum_method,
|
http_method : lib_plankton.caldav.enum_method,
|
||||||
path : string,
|
path : string,
|
||||||
options : {
|
options : {
|
||||||
active ?: ((version : string) => boolean);
|
active ?: ((version : (null | string)) => boolean);
|
||||||
restriction ?: (null | lib_plankton.rest_caldav.type_restriction<type_input>);
|
restriction ?: (null | lib_plankton.rest_caldav.type_restriction<type_input>);
|
||||||
execution ?: lib_plankton.rest_caldav.type_execution<type_input, type_output>;
|
execution ?: lib_plankton.rest_caldav.type_execution<type_input, type_output>;
|
||||||
title ?: (null | string);
|
title ?: (null | string);
|
||||||
|
@ -155,10 +155,24 @@ namespace _zeitbild.api
|
||||||
>);
|
>);
|
||||||
input_schema ?: ((version: (null | string)) => lib_plankton.rest_caldav.type_oas_schema);
|
input_schema ?: ((version: (null | string)) => lib_plankton.rest_caldav.type_oas_schema);
|
||||||
output_schema ?: ((version: (null | string)) => lib_plankton.rest_caldav.type_oas_schema);
|
output_schema ?: ((version: (null | string)) => lib_plankton.rest_caldav.type_oas_schema);
|
||||||
request_body_mimetype ?: string;
|
request_body_mimetype ?: (
|
||||||
request_body_decode ?: ((http_request_body : Buffer, http_request_header_content_type : (null | string)) => any);
|
(version : (null | string))
|
||||||
|
=>
|
||||||
|
string
|
||||||
|
);
|
||||||
|
request_body_decode ?: (
|
||||||
|
(version : (null | string))
|
||||||
|
=>
|
||||||
|
(http_request_body : Buffer, http_request_header_content_type : (null | string))
|
||||||
|
=>
|
||||||
|
Promise<any>
|
||||||
|
);
|
||||||
response_body_mimetype ?: string;
|
response_body_mimetype ?: string;
|
||||||
response_body_encode ?: ((output : any) => Buffer);
|
response_body_encode ?: (
|
||||||
|
(output : any)
|
||||||
|
=>
|
||||||
|
Promise<Buffer>
|
||||||
|
);
|
||||||
} = {}
|
} = {}
|
||||||
) : void
|
) : void
|
||||||
{
|
{
|
||||||
|
@ -171,7 +185,74 @@ namespace _zeitbild.api
|
||||||
rest_subject,
|
rest_subject,
|
||||||
http_method,
|
http_method,
|
||||||
(_zeitbild.conf.get().server.path_base + path),
|
(_zeitbild.conf.get().server.path_base + path),
|
||||||
options
|
{
|
||||||
|
"active": options.active,
|
||||||
|
/**
|
||||||
|
* @todo heed version
|
||||||
|
*/
|
||||||
|
"restriction": (
|
||||||
|
((options.restriction === undefined) || (options.restriction === null))
|
||||||
|
?
|
||||||
|
undefined
|
||||||
|
:
|
||||||
|
(version) => (options.restriction as lib_plankton.rest_caldav.type_restriction<type_input>)
|
||||||
|
),
|
||||||
|
/**
|
||||||
|
* @todo heed version
|
||||||
|
*/
|
||||||
|
"execution": (
|
||||||
|
((options.execution === undefined) || (options.execution === null))
|
||||||
|
?
|
||||||
|
undefined
|
||||||
|
:
|
||||||
|
(version) => (options.execution as lib_plankton.rest_caldav.type_execution<type_input, type_output>)
|
||||||
|
),
|
||||||
|
/**
|
||||||
|
* @todo heed version
|
||||||
|
*/
|
||||||
|
"title": (
|
||||||
|
((options.title === undefined) || (options.title === null))
|
||||||
|
?
|
||||||
|
(version) => null
|
||||||
|
:
|
||||||
|
(version) => (options.title as string)
|
||||||
|
),
|
||||||
|
/**
|
||||||
|
* @todo heed version
|
||||||
|
*/
|
||||||
|
"description": (
|
||||||
|
((options.description === undefined) || (options.description === null))
|
||||||
|
?
|
||||||
|
(version) => null
|
||||||
|
:
|
||||||
|
(version) => (options.description as string)
|
||||||
|
),
|
||||||
|
"query_parameters": options.query_parameters,
|
||||||
|
"input_schema": options.input_schema,
|
||||||
|
"output_schema": options.output_schema,
|
||||||
|
"request_body_mimetype": options.request_body_mimetype,
|
||||||
|
"request_body_decode": options.request_body_decode,
|
||||||
|
/**
|
||||||
|
* @todo heed version
|
||||||
|
*/
|
||||||
|
"response_body_mimetype": (
|
||||||
|
((options.response_body_mimetype === undefined) || (options.response_body_mimetype === null))
|
||||||
|
?
|
||||||
|
undefined
|
||||||
|
:
|
||||||
|
(version) => (options.response_body_mimetype as string)
|
||||||
|
),
|
||||||
|
/**
|
||||||
|
* @todo heed version
|
||||||
|
*/
|
||||||
|
"response_body_encode": (
|
||||||
|
((options.response_body_encode === undefined) || (options.response_body_encode === null))
|
||||||
|
?
|
||||||
|
undefined
|
||||||
|
:
|
||||||
|
(version) => (options.response_body_encode as ((output : any) => Promise<Buffer>))
|
||||||
|
),
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace _zeitbild.api
|
||||||
"set_access_control_headers": true,
|
"set_access_control_headers": true,
|
||||||
"authentication": {
|
"authentication": {
|
||||||
"kind": "key_header",
|
"kind": "key_header",
|
||||||
"parameters": {"name": "X-Session-Key"}
|
"data": {"name": "X-Session-Key"}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -53,7 +53,10 @@ namespace _zeitbild.api
|
||||||
// caldav
|
// caldav
|
||||||
{
|
{
|
||||||
_zeitbild.api.register_caldav_sniff(rest_subject);
|
_zeitbild.api.register_caldav_sniff(rest_subject);
|
||||||
|
_zeitbild.api.register_caldav_put(rest_subject);
|
||||||
_zeitbild.api.register_caldav_probe(rest_subject);
|
_zeitbild.api.register_caldav_probe(rest_subject);
|
||||||
|
_zeitbild.api.register_caldav_probe_via_well_known(rest_subject);
|
||||||
|
_zeitbild.api.register_caldav_projects(rest_subject);
|
||||||
_zeitbild.api.register_caldav_get(rest_subject);
|
_zeitbild.api.register_caldav_get(rest_subject);
|
||||||
}
|
}
|
||||||
// misc
|
// misc
|
||||||
|
|
5
source/services/caldal.ts
Normal file
5
source/services/caldal.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
namespace _zeitbild.service.caldav
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
386
source/services/caldav.ts
Normal file
386
source/services/caldav.ts
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
|
||||||
|
namespace _zeitbild.service.caldav
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo use pod for output
|
||||||
|
* @todo get api paths in props from config
|
||||||
|
* @todo consider to outsorce to plankton
|
||||||
|
*/
|
||||||
|
export function probe(
|
||||||
|
input : (null | lib_plankton.xml.type_node_data),
|
||||||
|
{
|
||||||
|
"force_props": force_props = null,
|
||||||
|
} : {
|
||||||
|
force_props ?: (null | Array<string>);
|
||||||
|
} = {
|
||||||
|
}
|
||||||
|
) : (null | lib_plankton.xml.type_node_data)
|
||||||
|
{
|
||||||
|
const http_protocol : string = "HTTP/1.1";
|
||||||
|
let props : (null | Array<string>);
|
||||||
|
if (force_props) {
|
||||||
|
props = force_props;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (
|
||||||
|
(input !== null)
|
||||||
|
&&
|
||||||
|
(input.kind === "complex")
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
(input.data.tag.toLowerCase() === "d:propfind")
|
||||||
|
||
|
||||||
|
(input.data.tag.toLowerCase() === "propfind")
|
||||||
|
)
|
||||||
|
&&
|
||||||
|
(input.data.children.length === 1)
|
||||||
|
&&
|
||||||
|
(input.data.children[0].kind === "complex")
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
(input.data.children[0].data.tag.toLowerCase() === "d:prop")
|
||||||
|
||
|
||||||
|
(input.data.children[0].data.tag.toLowerCase() === "prop")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
props = input.data.children[0].data.children.map(
|
||||||
|
node => {
|
||||||
|
switch (node.kind) {
|
||||||
|
case "complex": {
|
||||||
|
return node.data.tag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw (new Error("unexpected node type for prop"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
props.sort();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
props = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (props === null) {
|
||||||
|
lib_plankton.log.notice(
|
||||||
|
"service.caldav.probe.unexpected_input",
|
||||||
|
{
|
||||||
|
"input": input,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const answers : Record<
|
||||||
|
string,
|
||||||
|
lib_plankton.webdav.type_data_prop_value
|
||||||
|
> = {
|
||||||
|
// webdav 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.2
|
||||||
|
*/
|
||||||
|
"displayname": {
|
||||||
|
"kind": "primitive",
|
||||||
|
"data": "projects"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.4
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
"getcontentlength": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.5
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
"getcontenttype": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.7
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
"getlastmodified": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc2518#section-13.9
|
||||||
|
*/
|
||||||
|
"resourcetype": {
|
||||||
|
"kind": "resourcetype",
|
||||||
|
"data": {
|
||||||
|
"kind": "collection",
|
||||||
|
"type": "calendar",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// webdav 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc3744#section-4.2
|
||||||
|
*/
|
||||||
|
"principal-url": {
|
||||||
|
"kind": "href",
|
||||||
|
"data": "/caldav"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc3744#section-5.1
|
||||||
|
*/
|
||||||
|
"owner": {
|
||||||
|
"kind": "primitive",
|
||||||
|
"data": ""
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc3744#section-5.4
|
||||||
|
*/
|
||||||
|
"current-user-privilege-set": {
|
||||||
|
"kind": "privileges",
|
||||||
|
"data": [
|
||||||
|
"read"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// caldav
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc4791#section-6.2.1
|
||||||
|
*/
|
||||||
|
"calendar-home-set": {
|
||||||
|
"kind": "href",
|
||||||
|
"data": "/caldav/project"
|
||||||
|
},
|
||||||
|
|
||||||
|
// WebDAV Current Principal Extension
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://datatracker.ietf.org/doc/html/rfc5397#section-3
|
||||||
|
*/
|
||||||
|
"current-user-principal": {
|
||||||
|
"kind": "href",
|
||||||
|
"data": "/caldav"
|
||||||
|
},
|
||||||
|
|
||||||
|
// unknown
|
||||||
|
|
||||||
|
/*
|
||||||
|
"calendar-color": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
"executable": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
"checked-in": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
"checked-out": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
"calendar-user-address-set": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
"kind": "root",
|
||||||
|
"data": {
|
||||||
|
"version": "1.0",
|
||||||
|
"encoding": "utf-8",
|
||||||
|
"content": lib_plankton.webdav.data_multistatus_encode_xml(
|
||||||
|
{
|
||||||
|
"responses": [
|
||||||
|
{
|
||||||
|
"href": "/caldav/project",
|
||||||
|
"body": {
|
||||||
|
/**
|
||||||
|
* @todo maybe propstats needs to be filled with props (.map …)
|
||||||
|
*/
|
||||||
|
"propstats": (
|
||||||
|
false
|
||||||
|
?
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"prop": (props ?? []).map(
|
||||||
|
(prop) => {
|
||||||
|
const prop_parts : Array<string> = prop.toLowerCase().split(":");
|
||||||
|
const prop_normalized : string = ((prop_parts.length <= 1) ? prop_parts[0] : prop_parts.slice(1).join(":"));
|
||||||
|
if (! (prop_normalized in answers)) {
|
||||||
|
lib_plankton.log.error(
|
||||||
|
"api.caldav_probe.unhandled_prop",
|
||||||
|
prop_normalized
|
||||||
|
);
|
||||||
|
throw (new Error("unhandled prop: " + prop_normalized));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
"name": prop,
|
||||||
|
"value": (
|
||||||
|
answers[prop_normalized]
|
||||||
|
??
|
||||||
|
{
|
||||||
|
"kind": "none",
|
||||||
|
"data": null,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"status": (http_protocol + " 200 OK"),
|
||||||
|
"description": null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
:
|
||||||
|
props.map(
|
||||||
|
(prop) => {
|
||||||
|
const prop_parts : Array<string> = prop.toLowerCase().split(":");
|
||||||
|
const prop_normalized : string = (
|
||||||
|
(prop_parts.length <= 1)
|
||||||
|
?
|
||||||
|
prop_parts[0]
|
||||||
|
:
|
||||||
|
prop_parts.slice(1).join(":")
|
||||||
|
);
|
||||||
|
if (! (prop_normalized in answers)) {
|
||||||
|
lib_plankton.log.notice(
|
||||||
|
"api.caldav_probe.unhandled_prop",
|
||||||
|
prop_normalized
|
||||||
|
);
|
||||||
|
/*
|
||||||
|
throw (new Error("unhandled prop: " + prop_normalized));
|
||||||
|
*/
|
||||||
|
return {
|
||||||
|
"prop": [
|
||||||
|
{
|
||||||
|
"name": prop,
|
||||||
|
"value": {
|
||||||
|
"kind": "none",
|
||||||
|
"data": null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"status": (http_protocol + " 404 Not Found"),
|
||||||
|
"description": null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
"prop": [
|
||||||
|
{
|
||||||
|
"name": prop,
|
||||||
|
"value": answers[prop_normalized],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"status": (http_protocol + " 200 OK"),
|
||||||
|
"description": null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
"description": null,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": null,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
export function projects(
|
||||||
|
user_id : type_user_id
|
||||||
|
) : Promise<lib_plankton.xml.type_node_data>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
_zeitbild.service.calendar.overview(user_id)
|
||||||
|
.then(
|
||||||
|
(data_raw) => Promise.resolve(
|
||||||
|
data_raw
|
||||||
|
.map(
|
||||||
|
(entry) => ({
|
||||||
|
"id": entry.id,
|
||||||
|
"name": entry.name,
|
||||||
|
"access_level": _zeitbild.value_object.access_level.to_string(entry.access_level),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(data) => Promise.resolve(
|
||||||
|
{
|
||||||
|
"kind": "root",
|
||||||
|
"data": {
|
||||||
|
"version": "1.0",
|
||||||
|
"encoding": "utf-8",
|
||||||
|
"content": lib_plankton.webdav.data_multistatus_encode_xml(
|
||||||
|
{
|
||||||
|
"responses": data.map(
|
||||||
|
(entry) => ({
|
||||||
|
"href": lib_plankton.string.coin(
|
||||||
|
"/caldav/project/{{id}}",
|
||||||
|
{
|
||||||
|
"id": entry.id.toFixed(0),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"body": {
|
||||||
|
"propstats": [
|
||||||
|
{
|
||||||
|
"prop": [
|
||||||
|
{
|
||||||
|
"name": "D:displayname",
|
||||||
|
"value": {
|
||||||
|
"kind": "primitive",
|
||||||
|
"data": entry.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "D:resourcetype",
|
||||||
|
"value": {
|
||||||
|
"kind": "resourcetype",
|
||||||
|
"data": {
|
||||||
|
"kind": "collection",
|
||||||
|
"type": "calendar",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"status": "HTTP/1.1 200 OK",
|
||||||
|
"description": null,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"description": null,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
"description": null,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -56,6 +56,7 @@ ${dir_temp}/zeitbild-unlinked.js: \
|
||||||
${dir_source}/services/user.ts \
|
${dir_source}/services/user.ts \
|
||||||
${dir_source}/services/resource.ts \
|
${dir_source}/services/resource.ts \
|
||||||
${dir_source}/services/calendar.ts \
|
${dir_source}/services/calendar.ts \
|
||||||
|
${dir_source}/services/caldav.ts \
|
||||||
${dir_source}/api/base.ts \
|
${dir_source}/api/base.ts \
|
||||||
${dir_source}/api/transformations/datetime.ts \
|
${dir_source}/api/transformations/datetime.ts \
|
||||||
${dir_source}/api/actions/meta_ping.ts \
|
${dir_source}/api/actions/meta_ping.ts \
|
||||||
|
@ -77,7 +78,10 @@ ${dir_temp}/zeitbild-unlinked.js: \
|
||||||
${dir_source}/api/actions/events.ts \
|
${dir_source}/api/actions/events.ts \
|
||||||
${dir_source}/api/actions/export_ical.ts \
|
${dir_source}/api/actions/export_ical.ts \
|
||||||
${dir_source}/api/actions/caldav_sniff.ts \
|
${dir_source}/api/actions/caldav_sniff.ts \
|
||||||
|
${dir_source}/api/actions/caldav_put.ts \
|
||||||
${dir_source}/api/actions/caldav_probe.ts \
|
${dir_source}/api/actions/caldav_probe.ts \
|
||||||
|
${dir_source}/api/actions/caldav_probe_via_well_known.ts \
|
||||||
|
${dir_source}/api/actions/caldav_projects.ts \
|
||||||
${dir_source}/api/actions/caldav_get.ts \
|
${dir_source}/api/actions/caldav_get.ts \
|
||||||
${dir_source}/api/functions.ts \
|
${dir_source}/api/functions.ts \
|
||||||
${dir_source}/main.ts
|
${dir_source}/main.ts
|
||||||
|
|
Loading…
Add table
Reference in a new issue