feat(caldav): enhance eventToICS function to include join links and organizer details
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m24s
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m24s
This commit is contained in:
@@ -89,7 +89,12 @@ function getICSProp(ics, key) {
|
|||||||
return v.trim();
|
return v.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventToICS(event) {
|
function eventToICS(event, base, user) {
|
||||||
|
// Determine the most useful join URL
|
||||||
|
const joinUrl = event.federated_join_url
|
||||||
|
|| (event.room_uid ? `${base}/join/${event.room_uid}` : null);
|
||||||
|
const roomUrl = event.room_uid ? `${base}/rooms/${event.room_uid}` : null;
|
||||||
|
|
||||||
const lines = [
|
const lines = [
|
||||||
'BEGIN:VCALENDAR',
|
'BEGIN:VCALENDAR',
|
||||||
'VERSION:2.0',
|
'VERSION:2.0',
|
||||||
@@ -103,14 +108,40 @@ function eventToICS(event) {
|
|||||||
`DTSTAMP:${toICSDate(event.updated_at || event.created_at)}`,
|
`DTSTAMP:${toICSDate(event.updated_at || event.created_at)}`,
|
||||||
`LAST-MODIFIED:${toICSDate(event.updated_at || event.created_at)}`,
|
`LAST-MODIFIED:${toICSDate(event.updated_at || event.created_at)}`,
|
||||||
];
|
];
|
||||||
if (event.description) {
|
|
||||||
lines.push(`DESCRIPTION:${escapeICS(event.description)}`);
|
// LOCATION: show join link so calendar apps display "where" the meeting is
|
||||||
|
if (joinUrl) {
|
||||||
|
lines.push(`LOCATION:${escapeICS(joinUrl)}`);
|
||||||
|
lines.push(`URL:${joinUrl}`);
|
||||||
|
} else if (roomUrl) {
|
||||||
|
lines.push(`LOCATION:${escapeICS(roomUrl)}`);
|
||||||
|
lines.push(`URL:${roomUrl}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DESCRIPTION: combine user description + join link hint
|
||||||
|
const descParts = [];
|
||||||
|
if (event.description) descParts.push(event.description);
|
||||||
|
if (joinUrl) {
|
||||||
|
descParts.push(`Join meeting: ${joinUrl}`);
|
||||||
|
}
|
||||||
|
if (roomUrl && roomUrl !== joinUrl) {
|
||||||
|
descParts.push(`Room page: ${roomUrl}`);
|
||||||
|
}
|
||||||
|
if (descParts.length > 0) {
|
||||||
|
lines.push(`DESCRIPTION:${escapeICS(descParts.join('\n'))}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ORGANIZER
|
||||||
|
if (user) {
|
||||||
|
const cn = user.display_name || user.name || user.email;
|
||||||
|
lines.push(`ORGANIZER;CN=${escapeICS(cn)}:mailto:${user.email}`);
|
||||||
|
}
|
||||||
|
|
||||||
if (event.room_uid) {
|
if (event.room_uid) {
|
||||||
lines.push(`X-REDLIGHT-ROOM-UID:${event.room_uid}`);
|
lines.push(`X-REDLIGHT-ROOM-UID:${event.room_uid}`);
|
||||||
}
|
}
|
||||||
if (event.federated_join_url) {
|
if (joinUrl) {
|
||||||
lines.push(`X-REDLIGHT-JOIN-URL:${escapeICS(event.federated_join_url)}`);
|
lines.push(`X-REDLIGHT-JOIN-URL:${escapeICS(joinUrl)}`);
|
||||||
}
|
}
|
||||||
lines.push('END:VEVENT', 'END:VCALENDAR');
|
lines.push('END:VEVENT', 'END:VCALENDAR');
|
||||||
return lines.map(foldICSLine).join('\r\n');
|
return lines.map(foldICSLine).join('\r\n');
|
||||||
@@ -340,7 +371,7 @@ router.all('/:username/calendar/', caldavAuth, async (req, res) => {
|
|||||||
responses.push(
|
responses.push(
|
||||||
propResponse(`${calendarHref}${ev.uid}.ics`, {
|
propResponse(`${calendarHref}${ev.uid}.ics`, {
|
||||||
'd:getetag': escapeXml(etag(ev)),
|
'd:getetag': escapeXml(etag(ev)),
|
||||||
'c:calendar-data': escapeXml(ics),
|
'c:calendar-data': escapeXml(eventToICS(ev, baseUrl(req), req.caldavUser)),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -368,7 +399,7 @@ router.all('/:username/calendar/', caldavAuth, async (req, res) => {
|
|||||||
const responses = events.map(ev =>
|
const responses = events.map(ev =>
|
||||||
propResponse(`${calendarHref}${ev.uid}.ics`, {
|
propResponse(`${calendarHref}${ev.uid}.ics`, {
|
||||||
'd:getetag': escapeXml(etag(ev)),
|
'd:getetag': escapeXml(etag(ev)),
|
||||||
'c:calendar-data': escapeXml(eventToICS(ev)),
|
'c:calendar-data': escapeXml(eventToICS(ev, baseUrl(req), req.caldavUser)),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
setDAVHeaders(res);
|
setDAVHeaders(res);
|
||||||
@@ -391,7 +422,7 @@ router.get('/:username/calendar/:filename', caldavAuth, async (req, res) => {
|
|||||||
setDAVHeaders(res);
|
setDAVHeaders(res);
|
||||||
res.set('ETag', etag(ev));
|
res.set('ETag', etag(ev));
|
||||||
res.set('Content-Type', 'text/calendar; charset=utf-8');
|
res.set('Content-Type', 'text/calendar; charset=utf-8');
|
||||||
res.send(eventToICS(ev));
|
res.send(eventToICS(ev, baseUrl(req), req.caldavUser));
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── PUT /{username}/calendar/{uid}.ics — create or update ─────────────────
|
// ── PUT /{username}/calendar/{uid}.ics — create or update ─────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user