mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
The "This event only" edit path built nested JMAP patch pointers (recurrenceOverrides/<recurrenceId>/<field>). On the first edit of an occurrence the override object doesn't exist yet, and JMAP pointers can't create a missing intermediate object, so Stalwart returned notUpdated and the edit failed with two error toasts. Build the override as a single pointer recurrenceOverrides/<recurrenceId> whose value is the occurrence's field set (dropping identity/series keys), mirroring the working "delete this occurrence" path. Extracted as the pure, tested helper buildRecurrenceOverridePatch. Closes #774.
33 lines
1.0 KiB
TypeScript
33 lines
1.0 KiB
TypeScript
import type { CalendarEvent } from '@/lib/jmap/types';
|
|
|
|
/** Identity / whole-series keys that must never go into a single-occurrence override. */
|
|
export const RECURRENCE_OVERRIDE_IMMUTABLE_KEYS = [
|
|
'id',
|
|
'uid',
|
|
'@type',
|
|
'calendarIds',
|
|
'recurrenceRules',
|
|
'recurrenceOverrides',
|
|
'excludedRecurrenceRules',
|
|
] as const;
|
|
|
|
/**
|
|
* Build the "This event only" override patch for a recurring master.
|
|
*
|
|
* Why one pointer: a JMAP nested pointer can't create a missing intermediate,
|
|
* so the override object has to be set whole at `recurrenceOverrides/<id>`, not
|
|
* field-by-field (#774).
|
|
*/
|
|
export function buildRecurrenceOverridePatch(
|
|
updates: Partial<CalendarEvent>,
|
|
recurrenceId: string,
|
|
): Partial<CalendarEvent> {
|
|
const immutable = new Set<string>(RECURRENCE_OVERRIDE_IMMUTABLE_KEYS);
|
|
const override: Record<string, unknown> = {};
|
|
for (const [key, value] of Object.entries(updates)) {
|
|
if (immutable.has(key)) continue;
|
|
override[key] = value;
|
|
}
|
|
return { [`recurrenceOverrides/${recurrenceId}`]: override } as Partial<CalendarEvent>;
|
|
}
|