fix(calendar): recurring events not working (#4265)

This commit is contained in:
Meier Lukas
2025-10-11 22:54:51 +02:00
committed by GitHub
parent 0aede0dec3
commit 1b7e67dd97

View File

@@ -1,4 +1,7 @@
import type { Agent } from "https"; import type { Agent } from "https";
import dayjs from "dayjs";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";
import type { RequestInit as NodeFetchRequestInit } from "node-fetch"; import type { RequestInit as NodeFetchRequestInit } from "node-fetch";
import * as ical from "node-ical"; import * as ical from "node-ical";
import { DAVClient } from "tsdav"; import { DAVClient } from "tsdav";
@@ -14,6 +17,9 @@ import type { TestingResult } from "../base/test-connection/test-connection-serv
import type { ICalendarIntegration } from "../interfaces/calendar/calendar-integration"; import type { ICalendarIntegration } from "../interfaces/calendar/calendar-integration";
import type { CalendarEvent } from "../interfaces/calendar/calendar-types"; import type { CalendarEvent } from "../interfaces/calendar/calendar-types";
dayjs.extend(utc);
dayjs.extend(timezone);
@HandleIntegrationErrors([integrationTsdavHttpErrorHandler]) @HandleIntegrationErrors([integrationTsdavHttpErrorHandler])
export class NextcloudIntegration extends Integration implements ICalendarIntegration { export class NextcloudIntegration extends Integration implements ICalendarIntegration {
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> { protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
@@ -41,7 +47,8 @@ export class NextcloudIntegration extends Integration implements ICalendarIntegr
) )
).flat(); ).flat();
return calendarEvents.map((event): CalendarEvent => { return calendarEvents
.map((event) => {
// @ts-expect-error the typescript definitions for this package are wrong // @ts-expect-error the typescript definitions for this package are wrong
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
const icalData = ical.default.parseICS(event.data) as ical.CalendarResponse; const icalData = ical.default.parseICS(event.data) as ical.CalendarResponse;
@@ -53,27 +60,35 @@ export class NextcloudIntegration extends Integration implements ICalendarIntegr
logger.debug(`Converting VEVENT event to ${event.etag} from Nextcloud: ${JSON.stringify(veventObject)}`); logger.debug(`Converting VEVENT event to ${event.etag} from Nextcloud: ${JSON.stringify(veventObject)}`);
const date = veventObject.start;
const eventUrlWithoutHost = new URL(event.url).pathname; const eventUrlWithoutHost = new URL(event.url).pathname;
const dateInMillis = veventObject.start.valueOf(); const eventSlug = Buffer.from(eventUrlWithoutHost).toString("base64url");
const url = this.url( const startDates = veventObject.rrule ? veventObject.rrule.between(start, end) : [veventObject.start];
`/apps/calendar/timeGridWeek/now/edit/sidebar/${Buffer.from(eventUrlWithoutHost).toString("base64url")}/${dateInMillis / 1000}`,
); const durationMs = veventObject.end.getTime() - veventObject.start.getTime();
return startDates.map((startDate) => {
const timezoneOffsetMinutes = veventObject.rrule?.origOptions.tzid
? dayjs(startDate).tz(veventObject.rrule.origOptions.tzid).utcOffset()
: 0;
const utcStartDate = new Date(startDate.getTime() - timezoneOffsetMinutes * 60 * 1000);
const endDate = new Date(utcStartDate.getTime() + durationMs);
const dateInMillis = utcStartDate.valueOf();
return { return {
title: veventObject.summary, title: veventObject.summary,
subTitle: null, subTitle: null,
description: veventObject.description, description: veventObject.description,
startDate: date, startDate: utcStartDate,
endDate: veventObject.end, endDate,
image: null, image: null,
location: veventObject.location || null, location: veventObject.location || null,
indicatorColor: "#ff8600", indicatorColor: "#ff8600",
links: [ links: [
{ {
href: url.toString(), href: this.url(
`/apps/calendar/timeGridWeek/now/edit/sidebar/${eventSlug}/${dateInMillis / 1000}`,
).toString(),
name: "Nextcloud", name: "Nextcloud",
logo: "/images/apps/nextcloud.svg", logo: "/images/apps/nextcloud.svg",
color: undefined, color: undefined,
@@ -82,6 +97,8 @@ export class NextcloudIntegration extends Integration implements ICalendarIntegr
], ],
}; };
}); });
})
.flat();
} }
private async createCalendarClientAsync(agent?: Agent) { private async createCalendarClientAsync(agent?: Agent) {