Merge branch 'main' into feat/api-keys
commit
d158c18b9d
|
@ -1,6 +1,7 @@
|
|||
/// <reference path="../types/ical.d.ts"/>
|
||||
import { Credential, Prisma } from "@prisma/client";
|
||||
import dayjs from "dayjs";
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import timezone from "dayjs/plugin/timezone";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import ICAL from "ical.js";
|
||||
|
@ -36,6 +37,7 @@ const DEFAULT_CALENDAR_TYPE = "caldav";
|
|||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
dayjs.extend(isBetween);
|
||||
|
||||
const CALENDSO_ENCRYPTION_KEY = process.env.CALENDSO_ENCRYPTION_KEY || "";
|
||||
|
||||
|
@ -241,24 +243,63 @@ export default abstract class BaseCalendarService implements Calendar {
|
|||
)
|
||||
).flat();
|
||||
|
||||
const events = objects
|
||||
.filter((e) => !!e.data)
|
||||
.map((object) => {
|
||||
const events: { start: string; end: string }[] = [];
|
||||
|
||||
objects.forEach((object) => {
|
||||
if (object.data == null) return;
|
||||
|
||||
const jcalData = ICAL.parse(object.data);
|
||||
const vcalendar = new ICAL.Component(jcalData);
|
||||
const vevent = vcalendar.getFirstSubcomponent("vevent");
|
||||
const event = new ICAL.Event(vevent);
|
||||
const vtimezone = vcalendar.getFirstSubcomponent("vtimezone");
|
||||
|
||||
if (event.isRecurring()) {
|
||||
let maxIterations = 365;
|
||||
if (["HOURLY", "SECONDLY", "MINUTELY"].includes(event.getRecurrenceTypes())) {
|
||||
console.error(`Won't handle [${event.getRecurrenceTypes()}] recurrence`);
|
||||
return;
|
||||
}
|
||||
|
||||
const start = dayjs(dateFrom);
|
||||
const end = dayjs(dateTo);
|
||||
|
||||
const iterator = event.iterator();
|
||||
let current;
|
||||
let currentEvent;
|
||||
let currentStart;
|
||||
|
||||
do {
|
||||
maxIterations -= 1;
|
||||
current = iterator.next();
|
||||
currentEvent = event.getOccurrenceDetails(current);
|
||||
// as pointed out in https://datatracker.ietf.org/doc/html/rfc4791#section-9.6.5
|
||||
// recurring events are always in utc
|
||||
currentStart = dayjs(currentEvent.startDate.toJSDate());
|
||||
|
||||
if (currentStart.isBetween(start, end) === true) {
|
||||
return events.push({
|
||||
start: currentStart.toISOString(),
|
||||
end: dayjs(currentEvent.endDate.toJSDate()).toISOString(),
|
||||
});
|
||||
}
|
||||
} while (maxIterations > 0 && currentStart.isAfter(end) === false);
|
||||
if (maxIterations <= 0) {
|
||||
console.warn("could not find any occurrence for recurring event in 365 iterations");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (vtimezone) {
|
||||
const zone = new ICAL.Timezone(vtimezone);
|
||||
event.startDate = event.startDate.convertToZone(zone);
|
||||
event.endDate = event.endDate.convertToZone(zone);
|
||||
}
|
||||
|
||||
return {
|
||||
return events.push({
|
||||
start: dayjs(event.startDate.toJSDate()).toISOString(),
|
||||
end: dayjs(event.endDate.toJSDate()).toISOString(),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.resolve(events);
|
||||
|
|
|
@ -80,6 +80,16 @@ declare module "ical.js" {
|
|||
|
||||
public isRecurring(): boolean;
|
||||
public iterator(startTime?: Time): RecurExpansion;
|
||||
public getOccurrenceDetails(occurrence: Time): OccurrenceDetails;
|
||||
public getRecurrenceTypes(): FrequencyValues;
|
||||
}
|
||||
|
||||
// https://mozilla-comm.github.io/ical.js/api/ICAL.Event.html#.occurrenceDetails
|
||||
interface OccurrenceDetails {
|
||||
recurrenceId: Time;
|
||||
item: Event;
|
||||
startDate: Time;
|
||||
endDate: Time;
|
||||
}
|
||||
|
||||
export class Property {
|
||||
|
@ -108,9 +118,9 @@ declare module "ical.js" {
|
|||
}
|
||||
|
||||
export class Time {
|
||||
public fromString(str: string): Time;
|
||||
public fromJSDate(aDate: Date | null, useUTC: boolean): Time;
|
||||
public fromData(aData: TimeJsonData): Time;
|
||||
public static fromString(str: string): Time;
|
||||
public static fromJSDate(aDate: Date | null, useUTC: boolean): Time;
|
||||
public static fromData(aData: TimeJsonData): Time;
|
||||
|
||||
public now(): Time;
|
||||
|
||||
|
|
Loading…
Reference in New Issue