Skip to content

Commit e19ed2d

Browse files
authored
Merge branch 'main' into security-audit-fix/fast-xml-parser
2 parents b7a8a25 + 17af50b commit e19ed2d

File tree

7 files changed

+1981
-42
lines changed

7 files changed

+1981
-42
lines changed

packages/features/bookings/lib/handleCancelBooking.ts

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ async function handler(input: CancelBookingInput, dependencies?: Dependencies) {
166166
cancelSubsequentBookings,
167167
internalNote,
168168
skipCancellationReasonValidation = false,
169+
skipCalendarSyncTaskCancellation = false,
169170
} = bookingCancelInput.parse(body);
170171
const bookingToDelete = await getBookingToDelete(id, uid);
171172
const {
@@ -630,36 +631,46 @@ async function handler(input: CancelBookingInput, dependencies?: Dependencies) {
630631
allRemainingBookings
631632
);
632633

633-
try {
634-
const bookingToDeleteEventTypeMetadataParsed = eventTypeMetaDataSchemaWithTypedApps.safeParse(
635-
bookingToDelete.eventType?.metadata || null
636-
);
637-
638-
if (!bookingToDeleteEventTypeMetadataParsed.success) {
639-
log.error(
640-
`Error parsing metadata`,
641-
safeStringify({ error: bookingToDeleteEventTypeMetadataParsed?.error })
634+
// Skip calendar event deletion when cancellation comes from a calendar subscription webhook
635+
// to avoid infinite loops (Google/Office365 → Cal.com → Google/Office365 → ...)
636+
if (!skipCalendarSyncTaskCancellation) {
637+
try {
638+
const bookingToDeleteEventTypeMetadataParsed = eventTypeMetaDataSchemaWithTypedApps.safeParse(
639+
bookingToDelete.eventType?.metadata || null
642640
);
643-
throw new Error("Error parsing metadata");
644-
}
645641

646-
const bookingToDeleteEventTypeMetadata = bookingToDeleteEventTypeMetadataParsed.data;
642+
if (!bookingToDeleteEventTypeMetadataParsed.success) {
643+
log.error(
644+
`Error parsing metadata`,
645+
safeStringify({ error: bookingToDeleteEventTypeMetadataParsed?.error })
646+
);
647+
throw new Error("Error parsing metadata");
648+
}
647649

648-
const credentials = await getAllCredentialsIncludeServiceAccountKey(bookingToDelete.user, {
649-
...bookingToDelete.eventType,
650-
metadata: bookingToDeleteEventTypeMetadata,
651-
});
650+
const bookingToDeleteEventTypeMetadata = bookingToDeleteEventTypeMetadataParsed.data;
652651

653-
const eventManager = new EventManager(
654-
{ ...bookingToDelete.user, credentials },
655-
bookingToDeleteEventTypeMetadata?.apps
656-
);
652+
const credentials = await getAllCredentialsIncludeServiceAccountKey(bookingToDelete.user, {
653+
...bookingToDelete.eventType,
654+
metadata: bookingToDeleteEventTypeMetadata,
655+
});
656+
657+
const eventManager = new EventManager(
658+
{ ...bookingToDelete.user, credentials },
659+
bookingToDeleteEventTypeMetadata?.apps
660+
);
657661

658-
await eventManager.cancelEvent(evt, bookingToDelete.references, isBookingInRecurringSeries);
662+
await eventManager.cancelEvent(evt, bookingToDelete.references, isBookingInRecurringSeries);
663+
} catch (error) {
664+
log.error(`Error deleting integrations`, safeStringify({ error }));
665+
}
666+
}
659667

668+
// Always mark booking references as deleted for data consistency
669+
// (even when skipCalendarSyncTaskCancellation is true, since the external event is already deleted)
670+
try {
660671
await bookingReferenceRepository.updateManyByBookingId(bookingToDelete.id, { deleted: true });
661672
} catch (error) {
662-
log.error(`Error deleting integrations`, safeStringify({ error }));
673+
log.error(`Error marking booking references as deleted`, safeStringify({ error }));
663674
}
664675

665676
try {

0 commit comments

Comments
 (0)