Skip to content
File

Blob: src/worker/objects/cal-dav/calendars.ts

typescript122 lines
1import { calendarHref } from "@/worker/caldav/paths";
2import type { CalDavDoDb } from "@/worker/db/cal-dav-do/client";
3import type { CalendarRow } from "@/worker/db/cal-dav-do/schema";
4import {
5 calendarById,
6 calendarByName,
7 calendarSyncToken,
8 createCalendar as createCalendarRow,
9 deleteCalendar as deleteCalendarRow,
10 ensureDefaultCalendar,
11 listCalendars as listCalendarRows,
12 updateCalendar as updateCalendarRow,
13 validCalendarName,
14} from "@/worker/db/cal-dav-do/repository";
15import {
16 calDavError as err,
17 type CalDavError,
18 type CalendarCreateInput,
19 type CalendarDeleteByNameInput,
20 type CalendarDeleteInput,
21 type CalendarGetInput,
22 type CalendarListInput,
23 type CalendarRecord,
24 type CalendarUpdateInput,
25} from "@/worker/objects/cal-dav/types";
26import {
27 createCollectionRecord,
28 deleteCollectionRecord,
29 deleteCollectionRecordByName,
30 getCollectionRecord,
31 listCollectionRecords,
32 updateCollectionRecord,
33 type CollectionCrudSpec,
34} from "@/worker/objects/common/collection-crud";
35 
36function recordCalendar(row: CalendarRow): CalendarRecord {
37 return {
38 id: row.id,
39 name: row.name,
40 displayName: row.displayName,
41 description: row.description,
42 href: calendarHref(row.name),
43 color: row.color,
44 orderIndex: row.orderIndex,
45 timezoneIcal: row.timezoneIcal,
46 createdAtMs: row.createdAtMs,
47 modifiedAtMs: row.modifiedAtMs,
48 syncToken: calendarSyncToken(row.syncSeq),
49 };
50}
51 
52export function listCalendars(db: CalDavDoDb, input: CalendarListInput) {
53 const result = listCollectionRecords(db, input, calendarCrudSpec);
54 return { ok: true as const, calendars: result.records };
55}
56 
57export function getCalendar(db: CalDavDoDb, input: CalendarGetInput) {
58 const result = getCollectionRecord(db, input, calendarCrudSpec);
59 return result.ok ? { ok: true as const, calendar: result.record } : result;
60}
61 
62export function createCalendar(db: CalDavDoDb, input: CalendarCreateInput) {
63 const result = createCollectionRecord(db, input, calendarCrudSpec);
64 return result.ok ? { ok: true as const, calendar: result.record } : result;
65}
66 
67export function updateCalendar(db: CalDavDoDb, input: CalendarUpdateInput) {
68 const result = updateCollectionRecord(db, input, calendarCrudSpec);
69 return result.ok ? { ok: true as const, calendar: result.record } : result;
70}
71 
72export function deleteCalendar(db: CalDavDoDb, input: CalendarDeleteInput) {
73 return deleteCollectionRecord(db, input, calendarCrudSpec);
74}
75 
76export function deleteCalendarByName(db: CalDavDoDb, input: CalendarDeleteByNameInput) {
77 return deleteCollectionRecordByName(db, input, calendarCrudSpec);
78}
79 
80const calendarCrudSpec = {
81 ensureDefaultCollection: ensureDefaultCalendar,
82 listCollections: listCalendarRows,
83 collectionById: calendarById,
84 collectionByName: calendarByName,
85 validName: validCalendarName,
86 deleteCollection: deleteCalendarRow,
87 record: recordCalendar,
88 createCollection: (db, input: CalendarCreateInput, displayName) =>
89 createCalendarRow(db, {
90 subjectId: input.subjectId,
91 name: input.name,
92 displayName,
93 description: input.description ?? null,
94 color: input.color ?? null,
95 orderIndex: input.orderIndex ?? 0,
96 timezoneIcal: input.timezoneIcal ?? null,
97 nowMs: input.nowMs,
98 }),
99 updateCollection: (db, input: CalendarUpdateInput, displayName) =>
100 updateCalendarRow(db, {
101 id: input.id,
102 displayName,
103 description: input.description,
104 color: input.color,
105 orderIndex: input.orderIndex,
106 timezoneIcal: input.timezoneIcal,
107 nowMs: input.nowMs,
108 }),
109 invalidName: () => err(400, "bad_request", "Calendar name must be a DAV path segment."),
110 nameConflict: () => err(409, "conflict", "Calendar name already exists"),
111 collectionNotFound: () => err(404, "not_found", "Calendar not found"),
112 emptyDisplayName: () => err(400, "bad_request", "Calendar display name cannot be empty."),
113 defaultDeleteForbidden: () => err(403, "forbidden", "Default calendar cannot be deleted."),
114} satisfies CollectionCrudSpec<CalDavDoDb, CalendarRow, CalendarRecord, CalDavError> & {
115 createCollection(db: CalDavDoDb, input: CalendarCreateInput, displayName: string): CalendarRow;
116 updateCollection(
117 db: CalDavDoDb,
118 input: CalendarUpdateInput,
119 displayName: string | undefined,
120 ): CalendarRow | undefined;
121};