fix: only host can disable cancel meeting#28051
fix: only host can disable cancel meeting#28051hackice20 wants to merge 1 commit intocalcom:mainfrom
Conversation
There was a problem hiding this comment.
5 issues found across 6 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/features/bookings/lib/handleCancelBooking.ts">
<violation number="1" location="packages/features/bookings/lib/handleCancelBooking.ts:216">
P2: Host check now treats any eventType host as cancellation-authorized, without verifying the host is assigned to the booking’s attendees. This can allow unassigned team hosts to cancel bookings even when disableCancelling is enabled, conflicting with the per-booking host assignment policy used elsewhere.</violation>
<violation number="2" location="packages/features/bookings/lib/handleCancelBooking.ts:225">
P2: Untrusted cancelledBy query param is now used to grant host status, allowing spoofed host cancellations to bypass disableCancelling when userId is absent.</violation>
</file>
<file name="apps/web/components/booking/actions/BookingActionsDropdown.tsx">
<violation number="1" location="apps/web/components/booking/actions/BookingActionsDropdown.tsx:202">
P2: Client-side isHost only checks booking owner; it omits assigned event type hosts (attendee-email match), so non-owner hosts will still be treated as guests and blocked from canceling.</violation>
</file>
<file name="apps/web/components/booking/actions/bookingActions.ts">
<violation number="1" location="apps/web/components/booking/actions/bookingActions.ts:277">
P2: The new cancel bypass trusts `isHost`, but `isHost` is computed only by userId equality with `booking.user.id` and does not verify attendee assignment. This can enable cancellation for non-assigned team members even when guest cancellation is disabled. Host detection should include the attendee-email/assignment check before using it to bypass cancel restrictions.</violation>
</file>
<file name="apps/web/components/booking/BookingListItem.tsx">
<violation number="1" location="apps/web/components/booking/BookingListItem.tsx:208">
P2: Host determination omits attendee-based assignment checks, which can incorrectly treat non-assigned team hosts/owners as hosts and allow cancellation despite disableCancelling.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| if (userId) { | ||
| if (bookingToDelete.userId === userId) { | ||
| isCancellationUserHost = true; | ||
| } else if (bookingToDelete.eventType?.hosts?.some((host) => host.user.id === userId)) { |
There was a problem hiding this comment.
P2: Host check now treats any eventType host as cancellation-authorized, without verifying the host is assigned to the booking’s attendees. This can allow unassigned team hosts to cancel bookings even when disableCancelling is enabled, conflicting with the per-booking host assignment policy used elsewhere.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/features/bookings/lib/handleCancelBooking.ts, line 216:
<comment>Host check now treats any eventType host as cancellation-authorized, without verifying the host is assigned to the booking’s attendees. This can allow unassigned team hosts to cancel bookings even when disableCancelling is enabled, conflicting with the per-booking host assignment policy used elsewhere.</comment>
<file context>
@@ -208,16 +208,33 @@ async function handler(input: CancelBookingInput, dependencies?: Dependencies) {
+ if (userId) {
+ if (bookingToDelete.userId === userId) {
+ isCancellationUserHost = true;
+ } else if (bookingToDelete.eventType?.hosts?.some((host) => host.user.id === userId)) {
+ isCancellationUserHost = true;
+ } else if (bookingToDelete.eventType?.owner?.id === userId) {
</file context>
| } else if (bookingToDelete.eventType?.hosts?.some((host) => host.user.id === userId)) { | |
| } else if ( | |
| bookingToDelete.eventType?.hosts?.some( | |
| (host) => | |
| host.user.id === userId && | |
| bookingToDelete.attendees.some((attendee) => attendee.email === host.user.email) | |
| ) | |
| ) { |
| ) { | ||
| isCancellationUserHost = true; | ||
| } | ||
| } else if (cancelledBy && bookingToDelete.user.email === cancelledBy) { |
There was a problem hiding this comment.
P2: Untrusted cancelledBy query param is now used to grant host status, allowing spoofed host cancellations to bypass disableCancelling when userId is absent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/features/bookings/lib/handleCancelBooking.ts, line 225:
<comment>Untrusted cancelledBy query param is now used to grant host status, allowing spoofed host cancellations to bypass disableCancelling when userId is absent.</comment>
<file context>
@@ -208,16 +208,33 @@ async function handler(input: CancelBookingInput, dependencies?: Dependencies) {
+ ) {
+ isCancellationUserHost = true;
+ }
+ } else if (cancelledBy && bookingToDelete.user.email === cancelledBy) {
+ // Also check if cancelledBy email matches the booking owner
+ isCancellationUserHost = true;
</file context>
| const isHost = | ||
| booking.user?.id != null && | ||
| booking.loggedInUser.userId != null && | ||
| booking.loggedInUser.userId === booking.user.id; |
There was a problem hiding this comment.
P2: Client-side isHost only checks booking owner; it omits assigned event type hosts (attendee-email match), so non-owner hosts will still be treated as guests and blocked from canceling.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/components/booking/actions/BookingActionsDropdown.tsx, line 202:
<comment>Client-side isHost only checks booking owner; it omits assigned event type hosts (attendee-email match), so non-owner hosts will still be treated as guests and blocked from canceling.</comment>
<file context>
@@ -195,7 +195,11 @@ export function BookingActionsDropdown({
+ const isHost =
+ booking.user?.id != null &&
+ booking.loggedInUser.userId != null &&
+ booking.loggedInUser.userId === booking.user.id;
const isCalVideoLocation =
</file context>
| } | ||
| case "cancel": | ||
| // Allow hosts to cancel even when cancellation is disabled for guests | ||
| if (isHost && !isBookingInPast && !isCancelled && !isRejected) { |
There was a problem hiding this comment.
P2: The new cancel bypass trusts isHost, but isHost is computed only by userId equality with booking.user.id and does not verify attendee assignment. This can enable cancellation for non-assigned team members even when guest cancellation is disabled. Host detection should include the attendee-email/assignment check before using it to bypass cancel restrictions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/components/booking/actions/bookingActions.ts, line 277:
<comment>The new cancel bypass trusts `isHost`, but `isHost` is computed only by userId equality with `booking.user.id` and does not verify attendee assignment. This can enable cancellation for non-assigned team members even when guest cancellation is disabled. Host detection should include the attendee-email/assignment check before using it to bypass cancel restrictions.</comment>
<file context>
@@ -270,7 +271,12 @@ export function isActionDisabled(actionId: string, context: BookingActionContext
+ }
case "cancel":
+ // Allow hosts to cancel even when cancellation is disabled for guests
+ if (isHost && !isBookingInPast && !isCancelled && !isRejected) {
+ return false;
+ }
</file context>
| const cardCharged = booking?.payment[0]?.success; | ||
|
|
||
| // Check if the logged-in user is the host/owner of the booking | ||
| const isHost = |
There was a problem hiding this comment.
P2: Host determination omits attendee-based assignment checks, which can incorrectly treat non-assigned team hosts/owners as hosts and allow cancellation despite disableCancelling.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/components/booking/BookingListItem.tsx, line 208:
<comment>Host determination omits attendee-based assignment checks, which can incorrectly treat non-assigned team hosts/owners as hosts and allow cancellation despite disableCancelling.</comment>
<file context>
@@ -207,6 +204,12 @@ function BookingListItem(booking: BookingItemProps) {
const cardCharged = booking?.payment[0]?.success;
+ // Check if the logged-in user is the host/owner of the booking
+ const isHost =
+ booking.user?.id != null &&
+ booking.loggedInUser.userId != null &&
</file context>
|
@sean-brydon @Udit-takkar can you guys please review my PR :) |
What does this PR do?
Allow hosts to cancel even when “Disable cancelling” is on
This PR updates booking actions and cancel logic so that hosts (organizers/event owners) can still cancel bookings even when the event type has
disableCancellingenabled, while guests are blocked. It wiresisHostthrough the booking UI, adjustsisActionDisabled("cancel", ...)to permit host cancellations, updateshandleCancelBookingto only enforce the “no cancellations” rule for non-hosts, and adds tests covering both host-allowed and guest-blocked scenarios.Visual Demo (For contributors especially)
Screencast.From.2026-02-18.19-09-22.mp4
Mandatory Tasks (DO NOT REMOVE)
Checklist