some ICS fixes, handle empty calendar list

This commit is contained in:
Stefan Bühler 2024-12-18 15:23:37 +01:00
parent d7d86601f0
commit 6bf9758605

View File

@ -102,31 +102,43 @@ function display_event_date(item) {
} }
} }
function escapeICSField(text) { function format_ICS_text(text) {
return text.replace(/\\/g, "\\\\") return text.replace(/[\\,;]/g, "\\$&") // escape backslash and separators
.replace(/[,;]/g, "\\$&") .replace(/\n/g, "\\n") // escape newline
.replace(/\n/g, "\\n"); .replace(/[\x00-\x1f]+/g, " ") // replace control characters with whitespace
;
}
function format_ICS_date(date) {
if (date) {
date = new Date(date);
} else {
date = new Date(); // default to "now"
}
// remove "-" and ":" separators (but keep "T"), and drop microseconds
return date.toISOString().replace(/-|:|\.\d+/g, "");
} }
function createICSLink(item, settings) { function createICSLink(item, settings) {
const start = new Date(item.calculated.startDate).toISOString().replace(/-|:|\.\d+/g, ''); const start = format_ICS_date(item.calculated.startDate);
const end = new Date(item.calculated.endDate).toISOString().replace(/-|:|\.\d+/g, ''); const end = format_ICS_date(item.calculated.endDate);
const summary = item.base.caption; const summary = item.base.caption;
const description = item.base.information || ""; const description = item.base.information || "";
const location = item.base.address?.meetingAt || ""; const location = item.base.address?.meetingAt || "";
// Escape special characters for ICS fields // Escape special characters for ICS fields
const escapedSummary = escapeICSField(summary /* .replace(/['"]/g, "") */); const escapedSummary = format_ICS_text(summary /* .replace(/['"]/g, "") */);
const escapedDescription = escapeICSField(description /* .replace(/['"]/g, "") */); const escapedDescription = format_ICS_text(description /* .replace(/['"]/g, "") */);
const escapedLocation = escapeICSField(location); const escapedLocation = format_ICS_text(location);
const icsContent = `BEGIN:VCALENDAR const icsContent = `BEGIN:VCALENDAR
VERSION:2.0 VERSION:2.0
PRODID:-//Evang Kirchengemeinde Malmsheim//Gottesdienste//EN PRODID:-//churchtools-next-events//EN
BEGIN:VEVENT BEGIN:VEVENT
UID:${crypto.randomUUID()}@malmsheim-evangelisch.de UID:appointment-${item.base.id}@${window.location.hostname}
DTSTAMP:${new Date().toISOString().replace(/-|:|\.\d+/g, '')} CREATED:${format_ICS_date(item.base.meta?.createdDate)}
LAST-MODIFIED:${format_ICS_date(item.base.meta?.modifiedDate)}
DTSTART:${start} DTSTART:${start}
DTEND:${end} DTEND:${end}
SUMMARY:${escapedSummary} SUMMARY:${escapedSummary}
@ -396,6 +408,9 @@ async function load_events(dom_node, defaults) {
const calendars = all_calendars.filter((calendar) => r_cal_regex.exec(calendar.name)); const calendars = all_calendars.filter((calendar) => r_cal_regex.exec(calendar.name));
const calendar_ids = calendars.map((calendar) => calendar.id); const calendar_ids = calendars.map((calendar) => calendar.id);
let appointments;
if (calendar_ids.length) {
const filters = calendar_ids.map((cal_id) => `calendar_ids[]=${cal_id}`); const filters = calendar_ids.map((cal_id) => `calendar_ids[]=${cal_id}`);
const from = new Date(); const from = new Date();
filters.push(`from=${format_date(from)}`); filters.push(`from=${format_date(from)}`);
@ -403,11 +418,14 @@ async function load_events(dom_node, defaults) {
filters.push(`to=${format_date(to)}`); filters.push(`to=${format_date(to)}`);
const query = filters.join("&"); const query = filters.join("&");
const all_appointments = (await (await fetch(settings.instance + `/api/calendars/appointments?${query}`, req_config)).json()).data; const all_appointments = (await (await fetch(settings.instance + `/api/calendars/appointments?${query}`, req_config)).json()).data;
const appointments = all_appointments.filter((appointment) => r_event_regex.exec(appointment.base.title)); appointments = all_appointments.filter((appointment) => r_event_regex.exec(appointment.base.title));
if (appointments.length > settings.limit) { if (appointments.length > settings.limit) {
appointments.length = settings.limit; appointments.length = settings.limit;
} }
} else {
appointments = [];
}
const Appointments = { const Appointments = {
view: function(vnode) { view: function(vnode) {