mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 16:05:39 +00:00
fix: edit or answer one occurrence of a series in the app on Stalwart 1.0
Stalwart 1.0 refuses series properties such as the organizer on a single occurrence unless they repeat the series' value, and refuses them inside a recurrence override on the base event. The event editor wrote the user's first address as organizerCalendarAddress on every save of an event with attendees, so editing one occurrence failed with "This property cannot be modified on a single occurrence." whenever the series was organized by someone else, under another alias or in another letter case. Removing every attendee from one occurrence failed the same way. - leave series keys and per-event metadata out of changes to one occurrence, as Stalwart's validate.rs lists them, and pointers at a participant's calendarAddress - write overrides on the base event as before (0.16.19 needs the organizer there) and, when the server refuses series keys inside them, repeat the write once without them and remember that - answer one occurrence through its synthetic id without the organizer - let the editor keep the organizer of an event: an invitation the user received is no longer rewritten with the user as organizer, and organizerCalendarAddress is only written for an event that has none - keep the SetError type on a refused event update 0.16.20 to 0.16.23 dropped these keys on synthetic ids anyway; the base-event override payload for older servers is unchanged.
This commit is contained in:
@@ -476,6 +476,25 @@ describe('calendar operations', () => {
|
||||
ev1: { recurrenceRule: null },
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps the SetError type and description of a refused update (Stalwart 1.0 override rule)', async () => {
|
||||
mockRequest.mockResolvedValue({
|
||||
methodResponses: [['CalendarEvent/set', {
|
||||
notUpdated: {
|
||||
ev1: {
|
||||
type: 'invalidProperties',
|
||||
description: 'organizerCalendarAddress cannot be set inside recurrenceOverrides.',
|
||||
properties: ['recurrenceOverrides'],
|
||||
},
|
||||
},
|
||||
}, '0']],
|
||||
});
|
||||
|
||||
await expect(updateEvent('ev1', { title: 'x' })).rejects.toMatchObject({
|
||||
type: 'invalidProperties',
|
||||
message: 'organizerCalendarAddress cannot be set inside recurrenceOverrides.',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('findEventsByUid', () => {
|
||||
|
||||
+4
-2
@@ -1,7 +1,7 @@
|
||||
import { jmapClient } from './jmap-client';
|
||||
import { CAPABILITIES } from './types';
|
||||
import type { Calendar, CalendarEvent, CalendarRights } from './types';
|
||||
import { assertSetResult, batched, jmapErrorType, requireMethodResult } from './jmap-result';
|
||||
import { JMAPMethodError, assertSetResult, batched, jmapErrorType, requireMethodResult } from './jmap-result';
|
||||
import { getEffectiveTimeZone } from '../lib/calendar-timezone';
|
||||
import { SCAN_PROPERTIES, type ScannedCalendarObject } from '../lib/calendar-component-detection';
|
||||
import {
|
||||
@@ -910,7 +910,9 @@ export async function updateEvent(
|
||||
);
|
||||
const result = methodResult<{ notUpdated?: Record<string, { description?: string; type?: string }> }>(res);
|
||||
const err = result.notUpdated?.[id];
|
||||
if (err) throw new Error(err.description || err.type || 'Failed to update event');
|
||||
// Keep the SetError type: the store retries some refusals differently
|
||||
// (isOverrideSeriesKeyRejection).
|
||||
if (err) throw new JMAPMethodError(err.type ?? 'setError', err.description || err.type || 'Failed to update event');
|
||||
}
|
||||
|
||||
export async function deleteEvents(
|
||||
|
||||
Reference in New Issue
Block a user