a9e7b1ac82
Co-authored-by: Camille Moussu <cmoussu@linagora.com>
217 lines
6.4 KiB
TypeScript
217 lines
6.4 KiB
TypeScript
import { convertEventDateTimeToISO } from "@/utils/timezone";
|
|
import moment from "moment-timezone";
|
|
import { Calendar } from "../../Calendars/CalendarTypes";
|
|
import {
|
|
RepetitionRule,
|
|
VCalComponent,
|
|
VObjectProperty,
|
|
} from "../../Calendars/types/CalendarData";
|
|
import { userAttendee } from "../../User/models/attendee";
|
|
import { createAttendee } from "../../User/models/attendee.mapper";
|
|
import { AlarmObject, CalendarEvent } from "../EventsTypes";
|
|
import { inferTimezoneFromValue } from "./inferTimezoneFromValue";
|
|
import { buildDelegatedEventURL } from "./buildDelegatedEventURL";
|
|
import { formatDateToICal } from "./formatDateToICal";
|
|
|
|
export function parseCalendarEvent(
|
|
data: VObjectProperty[],
|
|
color: Record<string, string>,
|
|
calendar: Calendar,
|
|
eventURL: string,
|
|
valarm?: VCalComponent
|
|
): CalendarEvent {
|
|
const event: Partial<CalendarEvent> = { color, attendee: [] };
|
|
let recurrenceId;
|
|
let duration;
|
|
const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
|
|
|
|
for (const [key, params, , value] of data) {
|
|
switch (key.toLowerCase()) {
|
|
case "uid":
|
|
event.uid = String(value);
|
|
break;
|
|
case "transp":
|
|
event.transp = String(value);
|
|
break;
|
|
case "dtstart": {
|
|
event.start = String(value);
|
|
const detectedTz = inferTimezoneFromValue(
|
|
params as Record<string, string>
|
|
);
|
|
if (detectedTz) {
|
|
event.timezone = detectedTz;
|
|
}
|
|
if (dateRegex.test(String(value))) {
|
|
event.allday = true;
|
|
} else {
|
|
event.allday = false;
|
|
}
|
|
break;
|
|
}
|
|
case "dtend": {
|
|
event.end = String(value);
|
|
if (!event.timezone) {
|
|
const detectedTz = inferTimezoneFromValue(
|
|
params as Record<string, string>
|
|
);
|
|
if (detectedTz) {
|
|
event.timezone = detectedTz;
|
|
}
|
|
}
|
|
if (dateRegex.test(String(value))) {
|
|
event.allday = true;
|
|
} else {
|
|
event.allday = false;
|
|
}
|
|
break;
|
|
}
|
|
case "class":
|
|
if (
|
|
["PRIVATE", "PUBLIC", "CONFIDENTIAL"].includes(
|
|
String(value).toUpperCase()
|
|
)
|
|
) {
|
|
event.class = String(value).toUpperCase() as CalendarEvent["class"];
|
|
}
|
|
break;
|
|
case "x-openpaas-videoconference":
|
|
event.x_openpass_videoconference = String(value);
|
|
break;
|
|
case "summary":
|
|
event.title = String(value);
|
|
break;
|
|
case "description":
|
|
event.description = String(value);
|
|
break;
|
|
case "location":
|
|
event.location = String(value);
|
|
break;
|
|
case "organizer": {
|
|
const paramsObj = params as Record<string, string>;
|
|
event.organizer = {
|
|
cn: paramsObj?.cn ?? "",
|
|
cal_address: String(value).replace(/^mailto:/i, ""),
|
|
};
|
|
break;
|
|
}
|
|
case "attendee": {
|
|
const paramsObj = params as Record<string, string>;
|
|
if (
|
|
!event.attendee?.find(
|
|
(attendee) =>
|
|
attendee.cal_address === String(value).replace(/^mailto:/i, "")
|
|
)
|
|
) {
|
|
(event.attendee as userAttendee[]).push(
|
|
createAttendee({
|
|
cn: paramsObj?.cn,
|
|
cal_address: String(value).replace(/^mailto:/i, ""),
|
|
partstat: paramsObj?.partstat as userAttendee["partstat"],
|
|
rsvp: paramsObj?.rsvp as userAttendee["rsvp"],
|
|
role: paramsObj?.role as userAttendee["role"],
|
|
cutype: paramsObj?.cutype as userAttendee["cutype"],
|
|
})
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
case "dtstamp":
|
|
event.stamp = String(value);
|
|
break;
|
|
case "sequence":
|
|
event.sequence = Number(value);
|
|
break;
|
|
case "recurrence-id":
|
|
recurrenceId = String(value);
|
|
break;
|
|
case "exdate":
|
|
if (!event.exdates) event.exdates = [];
|
|
event.exdates.push(String(value));
|
|
break;
|
|
case "status":
|
|
event.status = String(value);
|
|
break;
|
|
case "duration":
|
|
duration = String(value);
|
|
break;
|
|
case "rrule": {
|
|
const ruleValue = value as RepetitionRule;
|
|
event.repetition = { freq: ruleValue.freq.toLowerCase() };
|
|
if (ruleValue.byday) {
|
|
if (typeof ruleValue.byday === "string") {
|
|
event.repetition.byday = [ruleValue.byday];
|
|
} else {
|
|
event.repetition.byday = ruleValue.byday;
|
|
}
|
|
}
|
|
if (ruleValue.until) {
|
|
event.repetition.endDate = ruleValue.until;
|
|
}
|
|
if (ruleValue.count) {
|
|
event.repetition.occurrences = ruleValue.count;
|
|
}
|
|
if (ruleValue.interval) {
|
|
event.repetition.interval = ruleValue.interval;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (recurrenceId && event.uid) {
|
|
event.uid = `${event.uid}/${recurrenceId}`;
|
|
event.recurrenceId = recurrenceId;
|
|
}
|
|
|
|
if (valarm) {
|
|
event.alarm = {} as AlarmObject;
|
|
for (const [key, , , value] of valarm[1]) {
|
|
switch (key.toLowerCase()) {
|
|
case "action":
|
|
event.alarm.action = String(value);
|
|
break;
|
|
case "trigger":
|
|
event.alarm.trigger = String(value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
event.calId = calendar.id;
|
|
event.URL = calendar.delegated
|
|
? buildDelegatedEventURL(calendar, eventURL)
|
|
: eventURL;
|
|
if (!event.uid || !event.start) {
|
|
console.error(
|
|
`missing crucial event param in calendar ${calendar.id} `,
|
|
data
|
|
);
|
|
event.error = `missing crucial event param in calendar ${calendar.id} `;
|
|
}
|
|
|
|
const eventTimezone = event.timezone;
|
|
|
|
if (!event.end) {
|
|
const start = event.start ? new Date(event.start) : new Date();
|
|
const timeToAdd = duration
|
|
? moment.duration(duration).asMilliseconds()
|
|
: moment.duration(30, "minutes").asMilliseconds();
|
|
const artificialEnd = new Date(start.getTime() + timeToAdd);
|
|
event.end = formatDateToICal(artificialEnd, false, eventTimezone);
|
|
}
|
|
|
|
if (!event.allday && event.start && eventTimezone) {
|
|
const startISO = convertEventDateTimeToISO(event.start, eventTimezone);
|
|
if (startISO) {
|
|
event.start = startISO;
|
|
}
|
|
}
|
|
|
|
if (!event.allday && event.end && eventTimezone) {
|
|
const endISO = convertEventDateTimeToISO(event.end, eventTimezone);
|
|
if (endISO) {
|
|
event.end = endISO;
|
|
}
|
|
}
|
|
|
|
return event as CalendarEvent;
|
|
}
|