fix: Outlook update/delete fallback to non-calendar-scoped endpoint
When the calendar-scoped Graph API endpoint returns 404 for series
master or instance IDs, fall back to /me/events/{id} which handles
these cases. Fixes ErrorItemNotFound on delete/update of recurring
Outlook events.
v1.63.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c718aa584a
commit
18c2fc1a92
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "my-weekly-todo-list",
|
"name": "my-weekly-todo-list",
|
||||||
"version": "1.63.4",
|
"version": "1.63.5",
|
||||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -341,44 +341,54 @@ export const updateEvent = async (
|
|||||||
eventId: string,
|
eventId: string,
|
||||||
event: any
|
event: any
|
||||||
) => {
|
) => {
|
||||||
const response = await fetch(`${GRAPH_ENDPOINT}/me/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`, {
|
const body = JSON.stringify({
|
||||||
method: 'PATCH',
|
subject: event.summary,
|
||||||
headers: {
|
body: {
|
||||||
'Authorization': `Bearer ${accessToken}`,
|
contentType: 'HTML',
|
||||||
'Content-Type': 'application/json'
|
content: event.description || ''
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
start: ensureTimeZone(event.start),
|
||||||
subject: event.summary,
|
end: ensureTimeZone(event.end),
|
||||||
body: {
|
isAllDay: event.allDay !== undefined ? !!event.allDay : undefined,
|
||||||
contentType: 'HTML',
|
location: {
|
||||||
content: event.description || ''
|
displayName: event.location || ''
|
||||||
},
|
},
|
||||||
start: ensureTimeZone(event.start),
|
...(event.recurrence ? { recurrence: event.recurrence } : {}),
|
||||||
end: ensureTimeZone(event.end),
|
...(event.reminders?.length ? {
|
||||||
isAllDay: event.allDay !== undefined ? !!event.allDay : undefined,
|
isReminderOn: true,
|
||||||
location: {
|
reminderMinutesBeforeStart: event.reminders[0].minutes,
|
||||||
displayName: event.location || ''
|
} : {}),
|
||||||
},
|
...(event.busyStatus ? { showAs: event.busyStatus === 'oof' ? 'oof' : event.busyStatus } : {}),
|
||||||
...(event.recurrence ? { recurrence: event.recurrence } : {}),
|
...(event.visibility ? {
|
||||||
...(event.reminders?.length ? {
|
sensitivity: event.visibility === 'private' ? 'private'
|
||||||
isReminderOn: true,
|
: event.visibility === 'confidential' ? 'confidential'
|
||||||
reminderMinutesBeforeStart: event.reminders[0].minutes,
|
: 'normal'
|
||||||
} : {}),
|
} : {}),
|
||||||
...(event.busyStatus ? { showAs: event.busyStatus === 'oof' ? 'oof' : event.busyStatus } : {}),
|
...(event.attendees?.length ? {
|
||||||
...(event.visibility ? {
|
attendees: event.attendees.map((a: any) => ({
|
||||||
sensitivity: event.visibility === 'private' ? 'private'
|
emailAddress: { address: a.email, name: a.displayName || a.email },
|
||||||
: event.visibility === 'confidential' ? 'confidential'
|
type: 'required',
|
||||||
: 'normal'
|
})),
|
||||||
} : {}),
|
} : {}),
|
||||||
...(event.attendees?.length ? {
|
|
||||||
attendees: event.attendees.map((a: any) => ({
|
|
||||||
emailAddress: { address: a.email, name: a.displayName || a.email },
|
|
||||||
type: 'required',
|
|
||||||
})),
|
|
||||||
} : {}),
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const patchHeaders = {
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try calendar-scoped endpoint first
|
||||||
|
let response = await fetch(`${GRAPH_ENDPOINT}/me/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`, {
|
||||||
|
method: 'PATCH', headers: patchHeaders, body
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok && response.status === 404) {
|
||||||
|
// Fallback: try non-calendar-scoped endpoint
|
||||||
|
response = await fetch(`${GRAPH_ENDPOINT}/me/events/${encodeURIComponent(eventId)}`, {
|
||||||
|
method: 'PATCH', headers: patchHeaders, body
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const err = await response.text();
|
const err = await response.text();
|
||||||
throw new Error(`Failed to update Outlook event: ${err}`);
|
throw new Error(`Failed to update Outlook event: ${err}`);
|
||||||
@ -404,13 +414,24 @@ export const deleteEvent = async (
|
|||||||
calendarId: string,
|
calendarId: string,
|
||||||
eventId: string
|
eventId: string
|
||||||
) => {
|
) => {
|
||||||
const response = await fetch(`${GRAPH_ENDPOINT}/me/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`, {
|
// Try calendar-scoped endpoint first
|
||||||
|
let response = await fetch(`${GRAPH_ENDPOINT}/me/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${accessToken}`
|
'Authorization': `Bearer ${accessToken}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!response.ok && response.status === 404) {
|
||||||
|
// Fallback: try non-calendar-scoped endpoint (works better for series master IDs)
|
||||||
|
response = await fetch(`${GRAPH_ENDPOINT}/me/events/${encodeURIComponent(eventId)}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const err = await response.text();
|
const err = await response.text();
|
||||||
throw new Error(`Failed to delete Outlook event: ${err}`);
|
throw new Error(`Failed to delete Outlook event: ${err}`);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user