feat: basic caldav support (#14372)

fix #13531 

#### PR Dependency Tree


* **PR #14372** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* CalDAV calendar integration: link and sync CalDAV-compatible calendars
(discovery, listing, event sync).
* New UI flow and dialog to link CalDAV accounts with provider
selection, credentials, and display name.

* **API / Config**
* Server exposes CalDAV provider presets in config and new GraphQL
mutation to link CalDAV accounts.
  * New calendar config section for CalDAV with validation and defaults.

* **Tests**
  * Comprehensive CalDAV integration test suite added.

* **Chores**
* Removed analytics tokens from build configuration and reduced Cloud
E2E test shards.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-02-05 03:04:21 +08:00
committed by GitHub
parent 403f16b404
commit a655b79166
34 changed files with 2995 additions and 217 deletions
@@ -17,6 +17,12 @@ export interface UpsertCalendarAccountInput extends CalendarAccountTokens {
providerAccountId: string;
displayName?: string | null;
email?: string | null;
providerPresetId?: string | null;
serverUrl?: string | null;
principalUrl?: string | null;
calendarHomeUrl?: string | null;
username?: string | null;
authType?: string | null;
status?: string | null;
lastError?: string | null;
refreshIntervalMinutes?: number | null;
@@ -73,6 +79,12 @@ export class CalendarAccountModel extends BaseModel {
providerAccountId: input.providerAccountId,
displayName: input.displayName ?? null,
email: input.email ?? null,
providerPresetId: input.providerPresetId ?? null,
serverUrl: input.serverUrl ?? null,
principalUrl: input.principalUrl ?? null,
calendarHomeUrl: input.calendarHomeUrl ?? null,
username: input.username ?? null,
authType: input.authType ?? null,
accessToken: accessToken ?? null,
refreshToken: refreshToken ?? null,
expiresAt: input.expiresAt ?? null,
@@ -85,6 +97,12 @@ export class CalendarAccountModel extends BaseModel {
const updateData: Prisma.CalendarAccountUncheckedUpdateInput = {
displayName: data.displayName,
email: data.email,
providerPresetId: data.providerPresetId,
serverUrl: data.serverUrl,
principalUrl: data.principalUrl,
calendarHomeUrl: data.calendarHomeUrl,
username: data.username,
authType: data.authType,
expiresAt: data.expiresAt,
scope: data.scope,
status: data.status,