Skip to content

fix: handle collective multiple host on destinationCalendar#9

Open
ShashankFC wants to merge 1 commit into
enhance-collective-scheduling-foundationfrom
fix/handle-collective-multiple-host-destinations
Open

fix: handle collective multiple host on destinationCalendar#9
ShashankFC wants to merge 1 commit into
enhance-collective-scheduling-foundationfrom
fix/handle-collective-multiple-host-destinations

Conversation

@ShashankFC

@ShashankFC ShashankFC commented Jan 22, 2026

Copy link
Copy Markdown

Test 4nn

Summary by CodeRabbit

Release Notes

  • New Features

    • Events can now be synced to multiple destination calendars for greater scheduling flexibility
    • Team scheduling now supports per-member calendar configurations for collective events
  • Improvements

    • Enhanced calendar credential resolution and management across integrations
    • Better handling of calendar references during booking operations and updates

✏️ Tip: You can customize this high-level summary in your review settings.

nn---n*Replicated from [ai-code-review-evaluation/cal.com-coderabbit#4](https://github.com/ai-code-review-evaluation/cal.com-coderabbit/pull/4)*

Note

Medium Risk
Touches core booking-to-calendar sync paths (create/update/cancel) across multiple integrations and changes a widely used event shape, so regressions could impact calendar writes and webhook payload compatibility.

Overview
Enables syncing a single booking to multiple destination calendars by changing CalendarEvent.destinationCalendar from a single value to an array and updating all event builders/webhooks/emails to emit []/[calendar] consistently.

Updates core calendar orchestration (EventManager, CalendarManager) to create/update/delete events for each destination calendar reference, including credential lookups from DB when missing locally, and extends EventResult to carry externalId/credentialId for correct reference persistence.

Adjusts calendar providers (notably Google) to select the target calendar by credentialId when creating events, and updates cancellation/payment/reminder handlers and e2e webhook expectations to match the new destination calendar shape and collective-host behavior.

Written by Cursor Bugbot for commit bd797c1. Configure here.

@ShashankFC

Copy link
Copy Markdown
Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 7 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

if (evt.location === MeetLocationType && evt.destinationCalendar?.integration !== "google_calendar") {
// @NOTE: destinationCalendar it's an array now so as a fallback we will only check the first one
const [mainHostDestinationCalendar] = evt.destinationCalendar ?? [];
if (evt.location === MeetLocationType && mainHostDestinationCalendar.integration !== "google_calendar") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing optional chaining causes crash on empty array

High Severity

When evt.destinationCalendar is null, undefined, or an empty array, mainHostDestinationCalendar will be undefined. Accessing .integration on undefined without optional chaining throws a TypeError at runtime. The original code used evt.destinationCalendar?.integration, which was safe. The new code drops the optional chaining on mainHostDestinationCalendar.

Fix in Cursor Fix in Web

const selectedCalendar = externalCalendarId
? externalCalendarId
: event.destinationCalendar?.externalId;
: event.destinationCalendar?.find((cal) => cal.externalId === externalCalendarId)?.externalId;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fallback calendar lookup always returns undefined in updateEvent

High Severity

In updateEvent, the ternary checks externalCalendarId ? externalCalendarId : event.destinationCalendar?.find(cal => cal.externalId === externalCalendarId). The else branch only executes when externalCalendarId is falsy, so find compares against a falsy value and will never match, always returning undefined. The same bug exists in deleteEvent. The original code simply returned the single destination calendar's externalId as a fallback.

Additional Locations (1)

Fix in Cursor Fix in Web

create: {
name,
...(!IS_TEAM_BILLING_ENABLED && { slug }),
...(IS_TEAM_BILLING_ENABLED ? { slug } : {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Organization slug logic is inverted from original

High Severity

The original code ...(!IS_TEAM_BILLING_ENABLED && { slug }) set slug directly when billing was disabled. The new code ...(IS_TEAM_BILLING_ENABLED ? { slug } : {}) sets slug when billing is enabled — the exact opposite. This means organizations will get a slug set in the wrong billing scenario, breaking the intended billing/approval flow.

Fix in Cursor Fix in Web

};

if (isTeamEventType && eventType.schedulingType === "COLLECTIVE") {
evt.destinationCalendar?.push(...teamDestinationCalendars);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collective team calendars silently dropped when destinationCalendar null

Medium Severity

When neither eventType.destinationCalendar nor organizerUser.destinationCalendar is set, evt.destinationCalendar is null. The subsequent evt.destinationCalendar?.push(...teamDestinationCalendars) silently no-ops due to optional chaining, discarding all collected team member calendars for COLLECTIVE events. This defeats the PR's purpose of supporting per-member calendar configurations.

Fix in Cursor Fix in Web

})
: eventType.hosts?.length
? eventType.hosts.map(({ user, isFixed }) => ({
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadUsers removed organization select breaking downstream usage

Medium Severity

The refactored loadUsers for the dynamic user list case (no eventTypeId) removed organization: { select: { slug: true } } from the Prisma query. The userSelect used in ...userSelect.select does not include an organization relationship (only organizationId), so any downstream code that relied on user.organization.slug will now get undefined.

Fix in Cursor Fix in Web

externalCalendarId: isCalendarType ? evt.destinationCalendar?.externalId : undefined,
credentialId: isCalendarType ? evt.destinationCalendar?.credentialId : result.credentialId,
externalCalendarId: isCalendarType ? result.externalId : undefined,
credentialId: isCalendarType ? result.credentialId : undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Video reference credentialId dropped during booking creation

High Severity

For non-calendar results (video events), credentialId is now set to undefined instead of result.credentialId. The createMeeting function returns a credentialId on video results, and downstream code in handleCancelBooking relies on bookingVideoReference.credentialId to find the specific video credential for deletion. Storing undefined means video booking references lose their credential association.

Fix in Cursor Fix in Web

externalCalendarId: evt.destinationCalendar?.externalId,
credentialId: result.credentialId ?? evt.destinationCalendar?.credentialId,
externalCalendarId: result.externalId,
credentialId: result.credentialId ?? undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Location update references lose credentialId and externalCalendarId

Medium Severity

In updateLocation, the old code fell back to evt.destinationCalendar?.externalId and evt.destinationCalendar?.credentialId when result didn't contain those fields. Since CalendarManager.updateEvent never returns externalId or credentialId, result.externalId and result.credentialId are always undefined for calendar results. The old fallback compensated for this, but the new code replaces it with bare undefined. These references are persisted to the database via editLocation.handler.ts, so subsequent cancel or reschedule operations won't be able to identify the correct calendar or credential.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants