fix: answer an invitation whose event lies outside the calendar's loaded weeks

This commit is contained in:
Linus Rath
2026-11-02 23:29:43 +01:00
parent d3d150d2c4
commit 89df82adce
3 changed files with 14 additions and 1 deletions
+7
View File
@@ -60,6 +60,13 @@ describe('answerInvitation', () => {
expect(req.store.rsvpEvent).toHaveBeenCalledWith(req.client, 'new', 'p2', 'declined', { imip: 'mailto:alice@example.org' });
});
it('finds the new copy on the server when the store doesn’t hold it', async () => {
const base = request();
const req = request({ store: { ...base.store, events: () => [] }, findImported: async () => ({ id: 'srv', uid: 'u1', participants: { p2: me } } as never) } as never);
expect(await answerInvitation(req, 'accepted')).toBe('answered');
expect(req.store.rsvpEvent).toHaveBeenCalledWith(req.client, 'srv', 'p2', 'accepted', { imip: 'mailto:alice@example.org' });
});
it('says when a plugin stopped it, when it only added the event, and when it can\'t', async () => {
expect(await answerInvitation(request({ store: { ...request().store, importEvents: vi.fn(async () => null) } } as never), 'accepted')).toBe('stopped');
expect(await answerInvitation(request({ myParticipant: null, store: { ...request().store, events: () => [{ id: 'new', uid: 'u1', participants: {} } as never] } } as never), 'accepted')).toBe('added');
+6 -1
View File
@@ -44,6 +44,11 @@ export interface RsvpRequest {
answerOptions?: { sentBy: string };
/** The stored copy with its participants loaded (or the shared account's copy). */
resolveExisting: () => Promise<CalendarEvent | null | undefined>;
/**
* The copy an import just made, from the server, when the store doesn't
* hold it (an event outside the range the calendar has loaded).
*/
findImported?: (uid: string) => Promise<CalendarEvent | null>;
}
/**
@@ -113,7 +118,7 @@ export async function answerInvitation(req: RsvpRequest, status: RsvpStatus): Pr
if (imported <= 0) return 'failed';
const newEvent = store.events().find(
(e) => e.uid === parsedEvent.uid && (sharedMailAccount ? e.accountId === sharedMailAccount : !e.isShared),
);
) ?? (parsedEvent.uid && req.findImported ? await req.findImported(parsedEvent.uid) : null);
const participant = myParticipant || (newEvent ? findParticipantByEmails(newEvent, actingEmails) : null);
if (!newEvent || !participant) return 'added';
return (await rsvp(newEvent.id, participant.id)) ? 'answered' : 'stopped';
@@ -100,6 +100,7 @@ export async function doCalendarRespond(emailIdArg: unknown, statusArg: unknown)
actingEmails: emails,
calendarId,
sharedMailAccount: null,
findImported: (uid) => ownCopy(client, uid),
resolveExisting: async () => {
if (!existing) return null;
if (existing.participants && Object.keys(existing.participants).length > 0) return existing;