fix: Allow seat UID access for private seated events#23859
fix: Allow seat UID access for private seated events#23859Anshumancanrock wants to merge 7 commits intocalcom:mainfrom
Conversation
WalkthroughThe GET "/:bookingUid" controller route now uses OptionalApiAuthGuard alongside BookingUidGuard and accepts an optional AuthOptionalUser passed into bookingsService.getBooking. BookingsService.getBooking(uid, authUser?) was added and a private shouldShowAttendees helper computes showAttendees from eventType.seatsShowAttendees and the auth context (viewer membership, event owner, team admin). That showAttendees value is propagated into output generation and service flows for seated and recurring bookings (create, createRecurring, reschedule, cancel, confirm, decline, markAbsent, list/get). OutputBookingsService methods gained showAttendees parameters with fallback to eventType.seatsShowAttendees. Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@Anshumancanrock is attempting to deploy a commit to the cal Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
726-737: getBookings should always include attendees (endpoint requires auth).Per PR objectives, “When fetching all bookings (already requires authentication), always include attendees.” Replace eventType gating with a constant
trueso seat UIDs are always present for seated bookings.Apply this diff:
- this.outputService.getOutputRecurringSeatedBooking( - formatted, - !!formatted.eventType?.seatsShowAttendees - ) + this.outputService.getOutputRecurringSeatedBooking( + formatted, + true + ) ... - await this.outputService.getOutputSeatedBooking( - formatted, - !!formatted.eventType?.seatsShowAttendees - ) + await this.outputService.getOutputSeatedBooking( + formatted, + true + )
🧹 Nitpick comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts (1)
175-180: Propagate optional user to service — good; consider clarifying docs that Authorization is optional.Handler correctly forwards AuthOptionalUser. Suggest noting in the route description that Authorization is optional to surface seat UIDs for authorized viewers.
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
606-666: Make attendee email comparison case-insensitive to avoid false negatives.Some systems store mixed‑case emails; normalize before comparing.
Apply this diff:
- const isAttendee = booking.attendees.some(attendee => attendee.email === authUser.email); + const isAttendee = booking.attendees.some( + (attendee) => attendee.email?.toLowerCase() === authUser.email?.toLowerCase() + );If your platform uses managed/aliased attendee emails (OAuth client suffixes), consider normalizing the auth user email to the managed form before comparison.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts(2 hunks)apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts(6 hunks)apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{service,repository}.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Avoid dot-suffixes like
.service.tsor.repository.tsfor new files; reserve.test.ts,.spec.ts,.types.tsfor their specific purposes
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: ShashwatPS
PR: calcom/cal.com#23638
File: packages/trpc/server/routers/viewer/calendars/setDestinationReminder.handler.test.ts:198-199
Timestamp: 2025-09-06T11:00:34.372Z
Learning: In calcom/cal.com PR #23638, the maintainer ShashwatPS determined that authorization checks in the setDestinationReminder handler are "not applicable" when CodeRabbit suggested adding user-scoped WHERE clauses to prevent users from modifying other users' destination calendar reminder settings.
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma select uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma include uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
📚 Learning: 2025-08-19T09:47:49.478Z
Learnt from: eunjae-lee
PR: calcom/cal.com#23166
File: packages/prisma/migrations/20250818151914_routing_form_response_denormalized_backfill2/migration.sql:65-66
Timestamp: 2025-08-19T09:47:49.478Z
Learning: The Booking table has a unique constraint and index on the uid column (defined as `uid String unique` in schema.prisma), so JOINs on Booking.uid have optimal performance and don't require additional indexing.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧬 Code graph analysis (3)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts (2)
apps/api/v2/src/modules/auth/guards/optional-api-auth/optional-api-auth.guard.ts (1)
OptionalApiAuthGuard(7-23)apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (2)
GetOptionalUser(7-32)AuthOptionalUser(5-5)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (1)
packages/platform/types/bookings/2024-08-13/outputs/booking.output.ts (2)
CreateSeatedBookingOutput_2024_08_13(349-360)CreateRecurringSeatedBookingOutput_2024_08_13(365-381)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
AuthOptionalUser(5-5)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (7)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts (1)
164-164: Guard order LGTM; optional auth enables attendee visibility without breaking UID checks.Using OptionalApiAuthGuard before BookingUidGuard is appropriate so invalid creds still fail while no-creds requests proceed as anonymous.
Please confirm BookingUidGuard does not rely on request.user; if it does, keep this guard order, but ensure it gracefully handles null users.
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (3)
270-279: showAttendees override is correctly plumbed.Using
showAttendees ?? !!databaseBooking.eventType?.seatsShowAttendeespreserves legacy behavior while enabling auth-aware overrides.
329-360: Conditional attendee rendering preserves privacy; seatUid surfaced when allowed.Good use of safeParse and explicit email redaction from bookingFieldsResponses.
390-394: Recurring seated create: defaulting to show attendees is consistent with creator expectations.Signature and call-site updates look correct.
Also applies to: 396-406
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)
557-557: Always showing attendees on seated creation paths makes sense.Passing
trueensures the creator immediately gets seat UIDs.
700-717: Order preservation via Map lookup is fine.This restores input order without N+1 queries — good compromise.
816-827: Reschedule flows: passingtrueensures seat UIDs are returned immediately.Correctly aligns with the cancellation/reschedule UX needs.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
700-717: Respect auth-aware attendee visibility in getBookings — use shouldShowAttendeesgetBookings currently passes eventType.seatsShowAttendees directly; compute showAttendees via this.shouldShowAttendees(formatted, user) and pass that to the outputService for seated/recurring‑seated bookings.
@@ - for (const booking of orderedBookings) { + for (const booking of orderedBookings) { const bookingCasted = booking as any; const formatted = { ...bookingCasted, eventType: bookingCasted.eventType, eventTypeId: bookingCasted.eventTypeId, startTime: new Date(bookingCasted.startTime), endTime: new Date(bookingCasted.endTime), absentHost: !!bookingCasted.noShowHost, }; const isRecurring = !!formatted.recurringEventId; const isSeated = !!formatted.eventType?.seatsPerTimeSlot; if (isRecurring && !isSeated) { formattedBookings.push(this.outputService.getOutputRecurringBooking(formatted)); } else if (isRecurring && isSeated) { - formattedBookings.push( - this.outputService.getOutputRecurringSeatedBooking( - formatted, - !!formatted.eventType?.seatsShowAttendees - ) - ); + const showAttendees = await this.shouldShowAttendees(formatted, user as any); + formattedBookings.push( + this.outputService.getOutputRecurringSeatedBooking(formatted, showAttendees) + ); } else if (isSeated) { - formattedBookings.push( - await this.outputService.getOutputSeatedBooking( - formatted, - !!formatted.eventType?.seatsShowAttendees - ) - ); + const showAttendees = await this.shouldShowAttendees(formatted, user as any); + formattedBookings.push(await this.outputService.getOutputSeatedBooking(formatted, showAttendees)); } else { formattedBookings.push(await this.outputService.getOutputBooking(formatted)); } }Optional: type the user param as ApiAuthGuardUser in getBookings to avoid the
as anycast.
Also applies to the similar block around lines ~724–737.
♻️ Duplicate comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)
598-601: Recurring-UID branch now honors auth-aware attendee visibility.This addresses the earlier review feedback for recurring seated bookings.
885-891: Forwarding request.user into getBooking is correct.This ensures auth-aware attendee visibility post-cancel.
🧹 Nitpick comments (3)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)
558-558: Avoid hardcoding showAttendees=true on create.If the creator isn’t always entitled to view other attendees (e.g., managed/embedded flows), this could over‑expose. Consider deriving via shouldShowAttendees or clearly document the intentional exposure.
606-666: Make attendee email comparison case-insensitive to avoid false negatives.Email addresses should be compared case-insensitively.
Apply this diff:
- const isAttendee = booking.attendees.some(attendee => attendee.email === authUser.email); + const isAttendee = booking.attendees.some( + (attendee) => attendee.email?.toLowerCase() === authUser.email?.toLowerCase() + );
818-827: Confirm intent of showAttendees=true during reschedule outputs.Same concern as create: if the acting user isn’t guaranteed to be authorized to view all attendees, consider deriving via shouldShowAttendees.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts(12 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{service,repository}.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Avoid dot-suffixes like
.service.tsor.repository.tsfor new files; reserve.test.ts,.spec.ts,.types.tsfor their specific purposes
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧠 Learnings (2)
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-19T09:47:49.478Z
Learnt from: eunjae-lee
PR: calcom/cal.com#23166
File: packages/prisma/migrations/20250818151914_routing_form_response_denormalized_backfill2/migration.sql:65-66
Timestamp: 2025-08-19T09:47:49.478Z
Learning: The Booking table has a unique constraint and index on the uid column (defined as `uid String unique` in schema.prisma), so JOINs on Booking.uid have optimal performance and don't require additional indexing.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧬 Code graph analysis (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
AuthOptionalUser(5-5)apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts (1)
ApiAuthGuardUser(25-25)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Tests / Unit
- GitHub Check: Type check / check-types
- GitHub Check: Linters / lint
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (3)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)
10-10: Import of ApiAuthGuardUser is appropriate and scoped to typing.No issues. Keeps types explicit where needed.
569-587: Optional-auth GET path correctly computes auth-aware attendee visibility.Good use of shouldShowAttendees for both seated and recurring+seated branches.
893-903: LGTM: recurring-by-individual UID now threads auth to the unified getter.Matches the new optional-auth flow.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)
735-747: getBookings should include attendees for seated bookings on this authenticated endpoint.
Per PR objectives, authenticated listing should show attendees; currently it still obeys seatsShowAttendees.Apply this diff:
- formattedBookings.push( - this.outputService.getOutputRecurringSeatedBooking( - formatted, - !!formatted.eventType?.seatsShowAttendees - ) - ); + formattedBookings.push( + this.outputService.getOutputRecurringSeatedBooking(formatted, true) + ); @@ - formattedBookings.push( - await this.outputService.getOutputSeatedBooking( - formatted, - !!formatted.eventType?.seatsShowAttendees - ) - ); + formattedBookings.push( + await this.outputService.getOutputSeatedBooking(formatted, true) + );If stricter auth-awareness is preferred, fetch the full user once and call shouldShowAttendees per booking instead of hardcoding true.
1166-1169: Replace Prismaincludewith explicitselectin event-types repositorygetEventTypeByIdIncludeUsersAndTeam uses include: { users: true, team: true } (apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts:96–99). The same file has multiple other
includeusages (hosts, users, schedule, destinationCalendar, calVideoSettings, owner, team) at ~lines 56, 66, 75, 85, 92, 99, 115, 127, 139. Call site: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:1166–1169. Refactor these Prisma queries to use explicitselectand request only the nested fields actually needed.
♻️ Duplicate comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)
598-601: Recurring‑UID branch now auth‑aware — nice fix.
This addresses earlier feedback to respect auth for recurring seated bookings.
950-964: Type/contract mismatch: use findByIdWithProfile before toApiAuthGuardUser.
toApiAuthGuardUser expects UserWithProfile; findById returns plain User. Fetch the profile variant.Apply this diff:
- const bookingOwner = await this.usersRepository.findById(bookingOwnerId); + const bookingOwner = await this.usersRepository.findByIdWithProfile(bookingOwnerId); if (!bookingOwner) { throw new NotFoundException(`Booking owner with id=${bookingOwnerId} not found.`); } @@ - const authUser = this.toApiAuthGuardUser(bookingOwner); + const authUser = this.toApiAuthGuardUser(bookingOwner);Also ensure isSystemAdmin derives correctly from role. Add a unit test covering this path.
🧹 Nitpick comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)
606-666: Normalize emails when checking attendee membership.
Email comparison should be case‑insensitive to avoid false negatives.Apply this diff:
- // Check if user is an attendee of this booking - const isAttendee = booking.attendees.some(attendee => attendee.email === authUser.email); + // Check if user is an attendee of this booking (case-insensitive) + const authEmail = (authUser.email || "").toLowerCase(); + const isAttendee = booking.attendees.some( + (attendee) => (attendee.email || "").toLowerCase() === authEmail + );
710-712: Avoid any in bookingMap.
Tighten typing to reduce accidental misuse.Apply this diff:
- const bookingMap = new Map(bookings.map((booking: any) => [booking.id, booking])); + const bookingMap = new Map<number, (typeof bookings)[number]>( + bookings.map((b) => [b.id, b]) + );
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts(12 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{service,repository}.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Avoid dot-suffixes like
.service.tsor.repository.tsfor new files; reserve.test.ts,.spec.ts,.types.tsfor their specific purposes
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧠 Learnings (4)
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-27T12:15:43.830Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts:41-44
Timestamp: 2025-08-27T12:15:43.830Z
Learning: In calcom/cal.com, the AgentService.getAgent() method in packages/features/calAIPhone/providers/retellAI/services/AgentService.ts does NOT include authorization checks - it only validates the agentId parameter and directly calls the repository without verifying user/team access. This contrasts with other methods like getAgentWithDetails() which properly use findByIdWithUserAccessAndDetails() for authorization. When reviewing updateToolsFromAgentId() calls, always verify both agent ownership and eventType ownership are checked.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-08T09:29:11.681Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts:118-143
Timestamp: 2025-08-08T09:29:11.681Z
Learning: In calcom/cal.com PR #22919, packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts (TypeScript), the AIPhoneServiceAgentListItem is required to include user.email in listAgents responses (per maintainer Udit-takkar). Future reviews should not flag this as unnecessary PII unless requirements change.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-19T09:47:49.478Z
Learnt from: eunjae-lee
PR: calcom/cal.com#23166
File: packages/prisma/migrations/20250818151914_routing_form_response_denormalized_backfill2/migration.sql:65-66
Timestamp: 2025-08-19T09:47:49.478Z
Learning: The Booking table has a unique constraint and index on the uid column (defined as `uid String unique` in schema.prisma), so JOINs on Booking.uid have optimal performance and don't require additional indexing.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧬 Code graph analysis (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
AuthOptionalUser(5-5)apps/api/v2/src/modules/users/users.repository.ts (1)
UserWithProfile(10-13)apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts (1)
ApiAuthGuardUser(25-25)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Install dependencies / Yarn install & cache
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (7)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (7)
10-10: Import is appropriate.
No action needed.
569-587: Auth‑aware attendee visibility in getBooking — LGTM.
Good split across seated/recurring and forwarding showAttendees.
668-676: toApiAuthGuardUser helper — LGTM.
Simple, correct mapping of isSystemAdmin.
898-901: Forwarding auth to getBooking — LGTM.
Type‑safe cast and pass‑through looks fine.
903-914: Helper getAllRecurringBookingsByIndividualUid passes auth — LGTM.
Good reuse of getBooking to centralize attendee visibility.
1117-1119: Confirm flow returns auth‑aware booking — LGTM.
Good use of toApiAuthGuardUser.
1151-1153: Decline flow returns auth‑aware booking — LGTM.
Consistent with confirm.
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)
477-504: Compute showAttendees using auth, not only event setting (breaks objective).Current code derives
showAttendeessolely fromeventType.seatsShowAttendees, ignoring authorized viewers (creator/host/admin). This fails the objective to reveal attendees to authorized users on creation.Apply this diff to compute auth-aware visibility once using the first created booking (minimal extra query):
const bookings = await handleNewRecurringBooking({ bookingData: bookingRequest.body, userId: bookingRequest.userId, hostname: bookingRequest.headers?.host || "", platformClientId: bookingRequest.platformClientId, platformRescheduleUrl: bookingRequest.platformRescheduleUrl, platformCancelUrl: bookingRequest.platformCancelUrl, platformBookingUrl: bookingRequest.platformBookingUrl, platformBookingLocation: bookingRequest.platformBookingLocation, areCalendarEventsEnabled: bookingRequest.areCalendarEventsEnabled, }); - - // Compute proper attendee visibility based on event type and authentication - // For recurring bookings, use the event type settings to determine authorization - const showAttendees = eventType.seatsShowAttendees || false; // Default to secure for recurring bookings - + // Compute attendee visibility based on event settings and viewer authorization + let showAttendees = !!eventType.seatsShowAttendees; + if (!showAttendees && bookings[0]?.uid) { + const firstDbBooking = + await this.bookingsRepository.getByUidWithAttendeesWithBookingSeatAndUserAndEvent(bookings[0]!.uid!); + if (firstDbBooking) { + showAttendees = await this.shouldShowAttendees(firstDbBooking, authUser); + } + } return this.outputService.getOutputCreateRecurringSeatedBookings( bookings.map((booking) => ({ uid: booking.uid || "", seatUid: booking.seatReferenceUid || "" })), showAttendees );
720-761: Type/logic issue: building ApiAuthGuardUser from a partial user in getBookings.
this.toApiAuthGuardUser(user)expectsUserWithProfile, butuserhere is{ id; email; orgId? }. This will fail typing and may mis-evaluate admin checks.Fetch the full user once and reuse:
- const bookingMap = new Map(bookings.map((booking: any) => [booking.id, booking])); - const orderedBookings = ids.map((id) => bookingMap.get(id)).filter(Boolean); + const bookingMap = new Map(bookings.map((booking: any) => [booking.id, booking])); + const orderedBookings = ids.map((id) => bookingMap.get(id)).filter(Boolean); + const fullUser = await this.usersRepository.findByIdWithProfile(user.id); + const authUser = fullUser ? this.toApiAuthGuardUser(fullUser) : undefined; @@ - // Compute proper attendee visibility instead of just using event setting - const showAttendees = isSeated ? await this.shouldShowAttendees(formatted, this.toApiAuthGuardUser(user)) : true; + // Compute proper attendee visibility instead of just using event setting + const showAttendees = isSeated ? await this.shouldShowAttendees(formatted, authUser) : true;
♻️ Duplicate comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (2)
608-611: Recurring-UID branch fixed to be auth‑aware (thank you).This addresses the earlier review note to apply the same logic here.
968-982: Build guard user from full profile in markAbsent (typing/consistency).
findByIdreturns a plainUser, buttoApiAuthGuardUserexpectsUserWithProfile. Fetch the profile variant.- const bookingOwner = await this.usersRepository.findById(bookingOwnerId); + const bookingOwner = await this.usersRepository.findByIdWithProfile(bookingOwnerId); @@ - const authUser = this.toApiAuthGuardUser(bookingOwner); + const authUser = this.toApiAuthGuardUser(bookingOwner);
🧹 Nitpick comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (1)
328-361: DRY: factor attendee-mapping into a helper used by both seated paths.The attendee transformation logic is duplicated in seated and recurring seated outputs. Extract to a private helper to reduce divergence risk.
Apply this minimal change at the call sites:
- parsed.attendees = showAttendees - ? databaseBooking.attendees.map((attendee) => { - const { responses } = safeParse( - seatedBookingDataSchema, - attendee.bookingSeat?.data, - defaultSeatedBookingData, - false - ); - const attendeeData = { ... }; - const attendeeParsed = plainToClass(SeatedAttendee, attendeeData, { strategy: "excludeAll" }); - attendeeParsed.bookingFieldsResponses = responses || {}; - attendeeParsed.metadata = safeParse( - seatedBookingMetadataSchema, - attendee.bookingSeat?.metadata, - defaultSeatedBookingMetadata, - false - ); - delete attendeeParsed.bookingFieldsResponses.email; - return attendeeParsed; - }) - : []; + parsed.attendees = showAttendees ? this.buildSeatedAttendees(databaseBooking.attendees) : [];Suggested helper (outside the shown ranges):
private buildSeatedAttendees(attendees: DatabaseBooking["attendees"]): SeatedAttendee[] { return attendees.map((attendee) => { const { responses } = safeParse( seatedBookingDataSchema, attendee.bookingSeat?.data, defaultSeatedBookingData, false ); const attendeeData = { name: attendee.name, email: attendee.email, timeZone: attendee.timeZone, language: attendee.locale, absent: !!attendee.noShow, seatUid: attendee.bookingSeat?.referenceUid, bookingFieldsResponses: {}, }; const attendeeParsed = plainToClass(SeatedAttendee, attendeeData, { strategy: "excludeAll" }); attendeeParsed.bookingFieldsResponses = responses || {}; attendeeParsed.metadata = safeParse(seatedBookingMetadataSchema, attendee.bookingSeat?.metadata, defaultSeatedBookingMetadata, false); delete attendeeParsed.bookingFieldsResponses.email; return attendeeParsed; }); }Also applies to: 447-477
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
616-676: Normalize emails for attendee check (reduce false negatives).Compare attendee emails case‑insensitively to handle mixed‑case inputs.
- const isAttendee = booking.attendees.some(attendee => attendee.email === authUser.email); + const toLower = (s?: string | null) => (s ?? "").toLowerCase(); + const isAttendee = booking.attendees.some( + (attendee) => toLower(attendee.email) === toLower(authUser.email) + );
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts(16 hunks)apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{service,repository}.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Avoid dot-suffixes like
.service.tsor.repository.tsfor new files; reserve.test.ts,.spec.ts,.types.tsfor their specific purposes
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
🧠 Learnings (6)
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
📚 Learning: 2025-08-27T12:15:43.830Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts:41-44
Timestamp: 2025-08-27T12:15:43.830Z
Learning: In calcom/cal.com, the AgentService.getAgent() method in packages/features/calAIPhone/providers/retellAI/services/AgentService.ts does NOT include authorization checks - it only validates the agentId parameter and directly calls the repository without verifying user/team access. This contrasts with other methods like getAgentWithDetails() which properly use findByIdWithUserAccessAndDetails() for authorization. When reviewing updateToolsFromAgentId() calls, always verify both agent ownership and eventType ownership are checked.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-08T09:29:11.681Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts:118-143
Timestamp: 2025-08-08T09:29:11.681Z
Learning: In calcom/cal.com PR #22919, packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts (TypeScript), the AIPhoneServiceAgentListItem is required to include user.email in listAgents responses (per maintainer Udit-takkar). Future reviews should not flag this as unnecessary PII unless requirements change.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma select uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma include uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
📚 Learning: 2025-08-19T09:47:49.478Z
Learnt from: eunjae-lee
PR: calcom/cal.com#23166
File: packages/prisma/migrations/20250818151914_routing_form_response_denormalized_backfill2/migration.sql:65-66
Timestamp: 2025-08-19T09:47:49.478Z
Learning: The Booking table has a unique constraint and index on the uid column (defined as `uid String unique` in schema.prisma), so JOINs on Booking.uid have optimal performance and don't require additional indexing.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧬 Code graph analysis (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
AuthOptionalUser(5-5)apps/api/v2/src/modules/users/users.repository.ts (1)
UserWithProfile(10-13)apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts (1)
ApiAuthGuardUser(25-25)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (1)
packages/platform/types/bookings/2024-08-13/outputs/booking.output.ts (2)
CreateSeatedBookingOutput_2024_08_13(349-360)CreateRecurringSeatedBookingOutput_2024_08_13(365-381)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (13)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (4)
270-279: Auth-aware attendee gating plumbed correctly (LGTM).Optional
showAttendeesparam with a safe fallback to!!databaseBooking.eventType?.seatsShowAttendeeslooks good.
282-363: Seated output respects visibility flag (LGTM).Conditional population of
parsed.attendeesbased onshowAttendeesaligns with privacy requirements. The email redaction from bookingFieldsResponses is also proper.
381-394: Batch create recurring seated output now controlled via flag (LGTM).Signature and forwarding of
showAttendeeslook good; sorting preserved.
396-405: Create recurring seated output respects visibility flag (LGTM).Fallback behavior to event setting when flag is undefined is appropriate here.
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (9)
144-151: Auth propagated to seated creation paths (LGTM).Passing
authUserinto the seated creation flows matches the PR objective.
539-541: Auth propagated to single seated creation (LGTM).Parameter threading is correct.
566-569: Auth-aware visibility on seated creation (LGTM).Using
shouldShowAttendees(databaseBooking, authUser)prevents leaks.
579-599: Auth-aware getBooking for seated and recurring seated (LGTM).Visibility computed once and passed to output service correctly.
681-686: Helper for guard user construction (LGTM).Keeps call sites tidy. Consider sourcing
isSystemAdminfrom profile/org roles if available.
912-919: Forwarding request user on cancel response (LGTM).Ensures consistent visibility after cancel operations.
921-931: Recurring fetch helper now auth‑aware (LGTM).Pass-through to
getBookingwithauthUseris correct.
835-855: Reschedule response uses auth-aware visibility (LGTM).Using
request.userto computeshowAttendeesprevents overexposure.
1135-1137: Confirm/decline responses routed through auth-aware getBooking (LGTM).Good consistency across post‑mutation responses.
Also applies to: 1169-1171
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (1)
382-395: Fix redeclaration and undefined symbol in CreateRecurringSeated output.
showAttendeesis both a parameter and aconstinside the function.userIsEventTypeAdminOrOwneris not defined in scope.
This currently fails lint/build and always shadows the input flag.Apply this diff:
getOutputCreateRecurringSeatedBooking( databaseBooking: DatabaseBooking, seatUid: string, showAttendees?: boolean ): CreateRecurringSeatedBookingOutput_2024_08_13 { - const showAttendees = userIsEventTypeAdminOrOwner || !!databaseBooking.eventType?.seatsShowAttendees; - const getRecurringSeatedBookingOutput = this.getOutputRecurringSeatedBooking( - databaseBooking, - showAttendees ?? !!databaseBooking.eventType?.seatsShowAttendees - ); + const show = showAttendees ?? !!databaseBooking.eventType?.seatsShowAttendees; + const getRecurringSeatedBookingOutput = this.getOutputRecurringSeatedBooking(databaseBooking, show); return { ...getRecurringSeatedBookingOutput, seatUid }; }Also applies to: 397-406
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (4)
487-514: Compute showAttendees using auth, not only event setting (recurring + seated create).Using only
eventType.seatsShowAttendeeshides attendees even for authorized creators (owner/admin). Derive it from auth or you’ll miss the PR objective.Apply this diff:
// Compute proper attendee visibility based on event type and authentication - // For recurring bookings, use the event type settings to determine authorization - const showAttendees = eventType.seatsShowAttendees || false; // Default to secure for recurring bookings + // Authorized users (owner/admin/host) or explicit event setting can see attendees + const isAdminOrOwner = authUser ? await this.userIsEventTypeAdminOrOwner(authUser, eventType) : false; + const showAttendees = isAdminOrOwner || !!eventType.seatsShowAttendees;
589-626: Fix mis-nested branching and wrong return for recurring seated in getBooking.Current structure opens
if (isRecurring && isSeated)then immediately checksif (isSeated)and returns non-recurring seated output. This is a functional bug and breaks the type/shape.Apply this diff:
if (isRecurring && !isSeated) { return this.outputService.getOutputRecurringBooking(booking); } - if (isRecurring && isSeated) { - if (isSeated) { - return this.outputService.getOutputSeatedBooking(booking, showAttendees); - } + if (isRecurring && isSeated) { + return this.outputService.getOutputRecurringSeatedBooking(booking, showAttendees); + } + if (isSeated) { + return this.outputService.getOutputSeatedBooking(booking, showAttendees); + } return this.outputService.getOutputBooking(booking);
732-774: Don’t call toApiAuthGuardUser with a minimal user; fetch profile once and reuse.
getBookingsreceives a minimal{id,email}; converting it toApiAuthGuardUserwithout profile/role will mis‑type and can mis-evaluate authorization.Apply this diff:
const bookings = await this.bookingsRepository.getByIdsWithAttendeesWithBookingSeatAndUserAndEvent(ids); + // Build proper auth context once for visibility checks + const requestUserWithProfile = await this.usersRepository.findByIdWithProfile(user.id); + const authCtx: ApiAuthGuardUser | null = requestUserWithProfile + ? this.toApiAuthGuardUser(requestUserWithProfile) + : null; @@ - // Compute proper attendee visibility instead of just using event setting - const showAttendees = isSeated ? await this.shouldShowAttendees(formatted, this.toApiAuthGuardUser(user)) : true; + // Compute proper attendee visibility using a valid ApiAuthGuardUser + const showAttendees = isSeated ? await this.shouldShowAttendees(formatted, authCtx) : true;
857-876: Avoid redeclaring authUser inside rescheduleBooking.Shadowing the parameter with
const authUser = request.user...is confusing and flagged by linters.Apply this diff:
- const authUser = request.user as ApiAuthGuardUser | undefined; - const showAttendees = isSeated ? await this.shouldShowAttendees(databaseBooking, authUser) : true; + const requestAuthUser = request.user as ApiAuthGuardUser | undefined; + const showAttendees = isSeated ? await this.shouldShowAttendees(databaseBooking, requestAuthUser) : true;
♻️ Duplicate comments (1)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
994-1008: Use findByIdWithProfile before toApiAuthGuardUser (type/logic).
toApiAuthGuardUserexpectsUserWithProfile;findByIdreturns a plainUser. Fetch the profile to avoid type errors and ensure correct admin flag computation.Apply this diff:
- const bookingOwner = await this.usersRepository.findById(bookingOwnerId); + const bookingOwner = await this.usersRepository.findByIdWithProfile(bookingOwnerId); if (!bookingOwner) { throw new NotFoundException(`Booking owner with id=${bookingOwnerId} not found.`); } @@ - const authUser = this.toApiAuthGuardUser(bookingOwner); + const authUser = this.toApiAuthGuardUser(bookingOwner); return this.getBooking(bookingUid, authUser);
🧹 Nitpick comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (1)
330-361: Confirm intended exposure of attendee email for seated bookings.You delete
bookingFieldsResponses.emailbut still populateattendeeParsed.email. If seated-attendee emails are meant to be hidden unless authorized, ensureshowAttendeesand product policy.apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
942-945: Avoid redeclaring authUser inside cancelBooking.Rename the local to avoid clobbering the function parameter.
Apply this diff:
- const authUser = request.user as ApiAuthGuardUser | undefined; - return this.getBooking(bookingUid, authUser); + const requestAuthUser = request.user as ApiAuthGuardUser | undefined; + return this.getBooking(bookingUid, requestAuthUser);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts(1 hunks)apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts(16 hunks)apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/api/v2/src/ee/bookings/2024-08-13/controllers/bookings.controller.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{service,repository}.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Avoid dot-suffixes like
.service.tsor.repository.tsfor new files; reserve.test.ts,.spec.ts,.types.tsfor their specific purposes
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: ShashwatPS
PR: calcom/cal.com#23638
File: packages/trpc/server/routers/viewer/calendars/setDestinationReminder.handler.test.ts:198-199
Timestamp: 2025-09-06T11:00:34.372Z
Learning: In calcom/cal.com PR #23638, the maintainer ShashwatPS determined that authorization checks in the setDestinationReminder handler are "not applicable" when CodeRabbit suggested adding user-scoped WHERE clauses to prevent users from modifying other users' destination calendar reminder settings.
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma include uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma select uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.tsapps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-27T12:15:43.830Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/testCall.handler.ts:41-44
Timestamp: 2025-08-27T12:15:43.830Z
Learning: In calcom/cal.com, the AgentService.getAgent() method in packages/features/calAIPhone/providers/retellAI/services/AgentService.ts does NOT include authorization checks - it only validates the agentId parameter and directly calls the repository without verifying user/team access. This contrasts with other methods like getAgentWithDetails() which properly use findByIdWithUserAccessAndDetails() for authorization. When reviewing updateToolsFromAgentId() calls, always verify both agent ownership and eventType ownership are checked.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-08T09:29:11.681Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22919
File: packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts:118-143
Timestamp: 2025-08-08T09:29:11.681Z
Learning: In calcom/cal.com PR #22919, packages/features/calAIPhone/interfaces/AIPhoneService.interface.ts (TypeScript), the AIPhoneServiceAgentListItem is required to include user.email in listAgents responses (per maintainer Udit-takkar). Future reviews should not flag this as unnecessary PII unless requirements change.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
📚 Learning: 2025-08-19T09:47:49.478Z
Learnt from: eunjae-lee
PR: calcom/cal.com#23166
File: packages/prisma/migrations/20250818151914_routing_form_response_denormalized_backfill2/migration.sql:65-66
Timestamp: 2025-08-19T09:47:49.478Z
Learning: The Booking table has a unique constraint and index on the uid column (defined as `uid String unique` in schema.prisma), so JOINs on Booking.uid have optimal performance and don't require additional indexing.
Applied to files:
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
🧬 Code graph analysis (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (2)
packages/platform/types/bookings/2024-08-13/outputs/booking.output.ts (2)
CreateSeatedBookingOutput_2024_08_13(349-360)CreateRecurringSeatedBookingOutput_2024_08_13(365-381)apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
userIsEventTypeAdminOrOwner(181-217)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (3)
apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts (1)
AuthOptionalUser(5-5)apps/api/v2/src/modules/users/users.repository.ts (1)
UserWithProfile(10-13)apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts (1)
ApiAuthGuardUser(25-25)
🪛 Biome (2.1.2)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts
[error] 402-402: Shouldn't redeclare 'showAttendees'. Consider to delete it or rename it.
'showAttendees' is defined here:
(lint/suspicious/noRedeclare)
apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts
[error] 637-637: Illegal use of reserved keyword private as an identifier in strict mode
(parse)
[error] 637-637: Expected a semicolon or an implicit semicolon after a statement, but found none
An explicit or implicit semicolon is expected here...
...Which is required to end this statement
(parse)
[error] 637-637: Expected a semicolon or an implicit semicolon after a statement, but found none
An explicit or implicit semicolon is expected here...
...Which is required to end this statement
(parse)
[error] 638-638: expected , but instead found :
Remove :
(parse)
[error] 639-639: expected , but instead found attendees
Remove attendees
(parse)
[error] 639-639: expected , but instead found :
Remove :
(parse)
[error] 639-639: expected , but instead found [
Remove [
(parse)
[error] 639-639: expected , but instead found ;
Remove ;
(parse)
[error] 641-641: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 642-642: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 643-643: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 644-644: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 645-645: Expected a statement but instead found '| null'.
Expected a statement here.
(parse)
[error] 646-646: Expected an identifier, a string literal, a number literal, a private field name, or a computed name but instead found ','.
Expected an identifier, a string literal, a number literal, a private field name, or a computed name here.
(parse)
[error] 648-648: Expected an identifier, a string literal, a number literal, a private field name, or a computed name but instead found ')'.
Expected an identifier, a string literal, a number literal, a private field name, or a computed name here.
(parse)
[error] 648-648: Expected a class parameters but instead found '{'.
Expected a class parameters here.
(parse)
[error] 680-680: await is only allowed within async functions and at the top levels of modules.
(parse)
[error] 943-943: Shouldn't redeclare 'authUser'. Consider to delete it or rename it.
'authUser' is defined here:
(lint/suspicious/noRedeclare)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (2)
apps/api/v2/src/ee/bookings/2024-08-13/services/output.service.ts (1)
271-280: Good: auth-aware fallback for attendee visibility is correctly plumbed.Passing an optional
showAttendeeswith a sane fallback toeventType?.seatsShowAttendeesis aligned with the PR objectives.apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts (1)
1161-1163: LGTM: returning via getBooking ensures visibility is consistently computed.Good reuse; once the helper issues above are fixed, these paths will honor auth-aware attendee visibility.
Also applies to: 1195-1197
| /** | ||
| * Determines whether attendees should be shown based on privacy settings and user authorization. | ||
| * Returns true if: | ||
| * 1. Event type allows showing attendees (seatsShowAttendees), OR | ||
| * 2. User is authenticated and is either: | ||
| * - An attendee of the booking, OR | ||
| * - The event organizer/host, OR | ||
| * - Has admin privileges for the event | ||
| */ | ||
| private async shouldShowAttendees( | ||
| booking: { | ||
| attendees: { email: string }[]; | ||
| eventType: { | ||
| seatsShowAttendees?: boolean | null; | ||
| id?: number; | ||
| teamId?: number | null; | ||
| owner?: { id: number } | null | ||
| } | null | ||
| }, | ||
| authUser?: AuthOptionalUser | ||
| ): Promise<boolean> { | ||
| // If event type allows showing attendees, always show them | ||
| if (booking.eventType?.seatsShowAttendees) { | ||
| return true; | ||
| } | ||
|
|
||
| // If no authentication provided, respect the privacy setting | ||
| if (!authUser || !booking.eventType) { | ||
| return false; | ||
| } | ||
|
|
||
| // Check if user is an attendee of this booking | ||
| const isAttendee = booking.attendees.some(attendee => attendee.email === authUser.email); | ||
| if (isAttendee) { | ||
| return true; | ||
| } | ||
|
|
||
| // Check if user is the event organizer/host | ||
| if (booking.eventType.owner?.id === authUser.id) { | ||
| return true; | ||
| } | ||
|
|
||
| // For team events, check if user has admin access | ||
| if (booking.eventType.teamId) { | ||
| try { | ||
| const eventType = { | ||
| id: booking.eventType.id || 0, | ||
| teamId: booking.eventType.teamId, | ||
| owner: booking.eventType.owner, | ||
| bookingRequiresAuthentication: true, // Force authentication check for team access validation | ||
| } as EventTypeWithOwnerAndTeam; | ||
|
|
||
| await this.checkBookingRequiresAuthenticationSetting(eventType, authUser); | ||
| return true; // If no exception thrown, user has team admin access | ||
| } catch { | ||
| // User doesn't have team admin access | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Convert UserWithProfile to ApiAuthGuardUser format for proper authorization | ||
| */ | ||
| private toApiAuthGuardUser(user: UserWithProfile): ApiAuthGuardUser { | ||
| return { | ||
| ...user, | ||
| isSystemAdmin: user.role === "ADMIN", | ||
| }; | ||
| } | ||
|
|
There was a problem hiding this comment.
Rewrite shouldShowAttendees: incorrect eventType fields and throwing helper usage.
- Uses
eventType.owner?.idwhich is not guaranteed; the model exposesuserId. - Calls
checkBookingRequiresAuthenticationSetting(...)with a mismatched signature and a throwing contract; inappropriate for a boolean helper. - Logic can be simplified to: event setting OR attendee OR admin/owner/host.
Apply this diff:
- private async shouldShowAttendees(
- booking: {
- attendees: { email: string }[];
- eventType: {
- seatsShowAttendees?: boolean | null;
- id?: number;
- teamId?: number | null;
- owner?: { id: number } | null
- } | null
- },
- authUser?: AuthOptionalUser
- ): Promise<boolean> {
- // If event type allows showing attendees, always show them
- if (booking.eventType?.seatsShowAttendees) {
- return true;
- }
-
- // If no authentication provided, respect the privacy setting
- if (!authUser || !booking.eventType) {
- return false;
- }
-
- // Check if user is an attendee of this booking
- const isAttendee = booking.attendees.some(attendee => attendee.email === authUser.email);
- if (isAttendee) {
- return true;
- }
-
- // Check if user is the event organizer/host
- if (booking.eventType.owner?.id === authUser.id) {
- return true;
- }
-
- // For team events, check if user has admin access
- if (booking.eventType.teamId) {
- try {
- const eventType = {
- id: booking.eventType.id || 0,
- teamId: booking.eventType.teamId,
- owner: booking.eventType.owner,
- bookingRequiresAuthentication: true, // Force authentication check for team access validation
- } as EventTypeWithOwnerAndTeam;
-
- await this.checkBookingRequiresAuthenticationSetting(eventType, authUser);
- return true; // If no exception thrown, user has team admin access
- } catch {
- // User doesn't have team admin access
- }
- }
-
- return false;
- }
+ private async shouldShowAttendees(
+ booking: {
+ attendees: { email: string }[];
+ eventType: Pick<EventType, "id" | "userId" | "teamId" | "seatsShowAttendees"> | null;
+ },
+ authUser?: AuthOptionalUser
+ ): Promise<boolean> {
+ // 1) Event setting
+ if (booking.eventType?.seatsShowAttendees) return true;
+ // 2) No auth -> hide
+ if (!authUser || !booking.eventType) return false;
+ // 3) Attendee of the booking
+ if (booking.attendees.some((a) => a.email === authUser.email)) return true;
+ // 4) Owner/host/admin via existing helper (covers ownerId, host/assigned, team/org admin, system admin)
+ return this.userIsEventTypeAdminOrOwner(authUser, booking.eventType as EventType);
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** | |
| * Determines whether attendees should be shown based on privacy settings and user authorization. | |
| * Returns true if: | |
| * 1. Event type allows showing attendees (seatsShowAttendees), OR | |
| * 2. User is authenticated and is either: | |
| * - An attendee of the booking, OR | |
| * - The event organizer/host, OR | |
| * - Has admin privileges for the event | |
| */ | |
| private async shouldShowAttendees( | |
| booking: { | |
| attendees: { email: string }[]; | |
| eventType: { | |
| seatsShowAttendees?: boolean | null; | |
| id?: number; | |
| teamId?: number | null; | |
| owner?: { id: number } | null | |
| } | null | |
| }, | |
| authUser?: AuthOptionalUser | |
| ): Promise<boolean> { | |
| // If event type allows showing attendees, always show them | |
| if (booking.eventType?.seatsShowAttendees) { | |
| return true; | |
| } | |
| // If no authentication provided, respect the privacy setting | |
| if (!authUser || !booking.eventType) { | |
| return false; | |
| } | |
| // Check if user is an attendee of this booking | |
| const isAttendee = booking.attendees.some(attendee => attendee.email === authUser.email); | |
| if (isAttendee) { | |
| return true; | |
| } | |
| // Check if user is the event organizer/host | |
| if (booking.eventType.owner?.id === authUser.id) { | |
| return true; | |
| } | |
| // For team events, check if user has admin access | |
| if (booking.eventType.teamId) { | |
| try { | |
| const eventType = { | |
| id: booking.eventType.id || 0, | |
| teamId: booking.eventType.teamId, | |
| owner: booking.eventType.owner, | |
| bookingRequiresAuthentication: true, // Force authentication check for team access validation | |
| } as EventTypeWithOwnerAndTeam; | |
| await this.checkBookingRequiresAuthenticationSetting(eventType, authUser); | |
| return true; // If no exception thrown, user has team admin access | |
| } catch { | |
| // User doesn't have team admin access | |
| } | |
| } | |
| return false; | |
| } | |
| /** | |
| * Convert UserWithProfile to ApiAuthGuardUser format for proper authorization | |
| */ | |
| private toApiAuthGuardUser(user: UserWithProfile): ApiAuthGuardUser { | |
| return { | |
| ...user, | |
| isSystemAdmin: user.role === "ADMIN", | |
| }; | |
| } | |
| private async shouldShowAttendees( | |
| booking: { | |
| attendees: { email: string }[]; | |
| eventType: Pick<EventType, "id" | "userId" | "teamId" | "seatsShowAttendees"> | null; | |
| }, | |
| authUser?: AuthOptionalUser | |
| ): Promise<boolean> { | |
| // 1) Event setting | |
| if (booking.eventType?.seatsShowAttendees) return true; | |
| // 2) No auth -> hide | |
| if (!authUser || !booking.eventType) return false; | |
| // 3) Attendee of the booking | |
| if (booking.attendees.some((a) => a.email === authUser.email)) return true; | |
| // 4) Owner/host/admin via existing helper (covers ownerId, host/assigned, team/org admin, system admin) | |
| return this.userIsEventTypeAdminOrOwner(authUser, booking.eventType as EventType); | |
| } | |
| /** | |
| * Convert UserWithProfile to ApiAuthGuardUser format for proper authorization | |
| */ | |
| private toApiAuthGuardUser(user: UserWithProfile): ApiAuthGuardUser { | |
| return { | |
| ...user, | |
| isSystemAdmin: user.role === "ADMIN", | |
| }; | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 637-637: Illegal use of reserved keyword private as an identifier in strict mode
(parse)
[error] 637-637: Expected a semicolon or an implicit semicolon after a statement, but found none
An explicit or implicit semicolon is expected here...
...Which is required to end this statement
(parse)
[error] 637-637: Expected a semicolon or an implicit semicolon after a statement, but found none
An explicit or implicit semicolon is expected here...
...Which is required to end this statement
(parse)
[error] 638-638: expected , but instead found :
Remove :
(parse)
[error] 639-639: expected , but instead found attendees
Remove attendees
(parse)
[error] 639-639: expected , but instead found :
Remove :
(parse)
[error] 639-639: expected , but instead found [
Remove [
(parse)
[error] 639-639: expected , but instead found ;
Remove ;
(parse)
[error] 641-641: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 642-642: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 643-643: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 644-644: Expected an expression, or an assignment but instead found ':'.
Expected an expression, or an assignment here.
(parse)
[error] 645-645: Expected a statement but instead found '| null'.
Expected a statement here.
(parse)
[error] 646-646: Expected an identifier, a string literal, a number literal, a private field name, or a computed name but instead found ','.
Expected an identifier, a string literal, a number literal, a private field name, or a computed name here.
(parse)
[error] 648-648: Expected an identifier, a string literal, a number literal, a private field name, or a computed name but instead found ')'.
Expected an identifier, a string literal, a number literal, a private field name, or a computed name here.
(parse)
[error] 648-648: Expected a class parameters but instead found '{'.
Expected a class parameters here.
(parse)
[error] 680-680: await is only allowed within async functions and at the top levels of modules.
(parse)
🤖 Prompt for AI Agents
In apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts around
lines 628-699, shouldShowAttendees is using the wrong event owner field and an
inappropriate throwing helper: replace any use of booking.eventType.owner?.id
with booking.eventType.userId (or the correct userId field from the eventType
model), remove the try/catch around checkBookingRequiresAuthenticationSetting
and instead perform a non-throwing boolean team-admin check (either call an
existing userHasTeamAdminAccess/teamPermission helper that returns boolean or
implement a simple check that returns true only if authUser has admin access for
booking.eventType.teamId), and simplify the logic to return true when
seatsShowAttendees is true OR authUser is an attendee OR authUser.id ===
eventType.userId OR authUser is system admin OR the non-throwing team-admin
check passes; ensure proper null/undefined guards for eventType and types match
the signature.
|
Thank you for your contribution - we really appreciate it! I will close this issue though because a fix was merged already in #23868 |
What does this PR do?
Fixes a critical issue where users cannot cancel their individual seats in seated events when attendees are hidden. The GET booking endpoint now supports optional authentication to allow legitimate users to access seat UIDs while maintaining privacy controls.
Visual Demo (For contributors especially)
Mandatory Tasks (DO NOT REMOVE)
How should this be tested?
Cal.com development environment
Checklist