Conversation
- Replace calculateHideBrandingForBooking with passed hideBranding value - Fix inconsistent branding logic in handleNewBooking.ts line 1297 - Fix inconsistent branding logic in confirm.handler.ts line 277 - Pass calculated hideBranding to handleConfirmation function - Remove unused calculateHideBrandingForBooking function Resolves CodeRabbit issues with incomplete comprehensive branding implementation.
…m/hackice20/cal.com into fix/branding-disabled-in-settings
- Renamed calculated hideBranding variable to avoid conflict with function parameter - Fixed ESLint warnings (removed any type, prefixed unused var) - Preserves all branding logic while fixing build error - No functional changes to branding behavior
|
Hey there and thank you for opening this pull request! 👋🏼 We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted. Details: |
|
@hackice20 is attempting to deploy a commit to the cal Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughAdds a new permission check canViewSensitiveBookingData and uses it server-side and in the bookings page props to gate exposure of sensitive booking responses. Introduces comprehensive hideBranding computation (shouldHideBrandingForEvent) and propagates hideBranding through booking flows (new booking, confirmation, cancellation, reschedule, add-guests, edit-location, payments, no-show, round-robin, reschedule-attendee/owner flows). Expands Prisma selects to include branding fields (owner, team, parent), extends CalendarEvent and CalendarEventBuilder with hideBranding, and adds hideLogo support to email templates. Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/features/ee/round-robin/roundRobinManualReassignment.ts (1)
547-568: Use the computed branding flag instead of hard-codingtrue.We correctly compute
hideBrandingviashouldHideBrandingForEvent, but the reminder scheduling path still hard-codeshideBranding: true. That forces all manual-reassignment workflow emails to hide Cal.com branding even when the appearance setting says it should be shown. Replace this literal with the computed flag so reminders honor the branding preference.- hideBranding: true, + hideBranding,packages/features/bookings/lib/handleConfirmation.ts (1)
441-446: Propagate the computed branding flag to workflows
scheduleWorkflowsForNewBookingstill receives the defaulthideBrandingargument (which is alwaysfalseunless callers override it), so confirmation workflows never get the newly computedcalculatedHideBranding. This regresses the branding toggle for any confirmation-triggered workflow. Please wire the computed value through instead.- hideBranding: hideBranding, + hideBranding: calculatedHideBranding,packages/features/bookings/lib/payment/getBooking.ts (1)
156-163: Limit Prisma profile fields (select only what’s needed)You only use organizationId and username; fetch just those to reduce PII and payload.
As per coding guidelines
- const organizerOrganizationProfile = await prisma.profile.findFirst({ - where: { - userId: booking.userId ?? undefined, - }, - }); + const organizerOrganizationProfile = await prisma.profile.findFirst({ + where: { userId: booking.userId ?? undefined }, + select: { organizationId: true, username: true }, + });
🧹 Nitpick comments (11)
packages/emails/src/templates/BaseScheduledEmail.tsx (1)
67-67: LGTM: Branding logic correctly extended.The OR condition properly hides the logo when either
platformClientIdorhideBrandingis truthy, which aligns with the PR objective to respect the "Disable Cal.com branding" setting.Consider simplifying the Boolean conversion for better readability:
- hideLogo={Boolean(props.calEvent.platformClientId) || Boolean(props.calEvent.hideBranding)} + hideLogo={Boolean(props.calEvent.platformClientId || props.calEvent.hideBranding)}This achieves the same result with a single Boolean conversion while maintaining the same defensive type coercion.
packages/features/bookings/lib/handleCancelBooking.ts (4)
85-99: Consolidate profile reads; avoid duplicate DB query.You fetch Profile twice (here and again at Lines 267-271). Collapse into one query and reuse to cut a DB roundtrip.
Apply within this segment:
- // For user events, we need to fetch the user's profile to get the organization ID - const userOrganizationId = !bookingToDelete.eventType?.team - ? ( - await prisma.profile.findFirst({ - where: { - userId: bookingToDelete.userId, - }, - select: { - organizationId: true, - }, - }) - )?.organizationId - : null; + // For user events, fetch once and reuse (org + username) + const ownerProfileLite = !bookingToDelete.eventType?.team + ? await prisma.profile.findFirst({ + where: { userId: bookingToDelete.userId }, + select: { organizationId: true, username: true }, + }) + : null; + + const userOrganizationId = ownerProfileLite?.organizationId ?? null;Outside this range, replace the second fetch:
// Remove the prisma.profile.findFirst at Lines 267-271 and reuse: const ownerProfile = ownerProfileLite;As per coding guidelines.
100-106: Avoid sentinel 0 for eventTypeId.Passing 0 can skew logs/metrics. Guard and skip compute if missing.
- const hideBranding = await shouldHideBrandingForEvent({ - eventTypeId: bookingToDelete.eventTypeId ?? 0, - team: bookingToDelete.eventType?.team ?? null, - owner: bookingToDelete.user ?? null, - organizationId: bookingToDelete.eventType?.team?.parentId ?? userOrganizationId ?? null, - }); + const hideBranding = + bookingToDelete.eventTypeId + ? await shouldHideBrandingForEvent({ + eventTypeId: bookingToDelete.eventTypeId, + team: bookingToDelete.eventType?.team ?? null, + owner: bookingToDelete.user ?? null, + organizationId: bookingToDelete.eventType?.team?.parentId ?? userOrganizationId ?? null, + }) + : false;
107-118: Include booking identifiers in branding debug log.Helps correlate logs quickly.
log.debug("Branding configuration", { hideBranding, eventTypeId: bookingToDelete.eventTypeId, + bookingId: bookingToDelete.id, + bookingUid: bookingToDelete.uid, teamHideBranding: bookingToDelete.eventType?.team?.hideBranding, teamParentHideBranding: bookingToDelete.eventType?.team?.parent?.hideBranding, ownerHideBranding: bookingToDelete.user?.hideBranding, teamParentId: bookingToDelete.eventType?.team?.parentId, userOrganizationId, finalOrganizationId: bookingToDelete.eventType?.team?.parentId ?? userOrganizationId, isTeamEvent: !!bookingToDelete.eventType?.team, });
633-633: Prefer named export over default.Improves tree-shaking and refactoring.
As per coding guidelines.
packages/lib/builders/CalendarEvent/class.ts (1)
38-38: Addition aligns with PR intenthideBranding on CalendarEvent is appropriate and non-breaking.
Consider adding a short doc comment to clarify semantics (e.g., “when true, suppress Cal.com logo/footer in emails”).
packages/features/bookings/lib/handleNewBooking.ts (1)
2459-2459: Prefer named export over default for handlerSwitch to named export for tree-shaking and clearer imports. As per coding guidelines.
-export default handler; +export { handler };packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)
74-106: Minimize owner selection to only required fieldsAvoid fetching unnecessary owner data. Use a selective owner projection.
- owner: true, + owner: { select: { id: true, hideBranding: true } },packages/trpc/server/routers/viewer/bookings/get.handler.ts (1)
14-14: LGTM: robust hidden-fields sanitization with batched field loading
- Batches eventType.bookingFields and filters hidden fields when user lacks permission.
- Safely handles stringified JSON and unknown schemas.
Consider reducing potential N+1 DB calls from canViewSensitiveBookingData by memoizing membership/host checks per request or extending the API to accept precomputed context.
Also applies to: 72-76, 703-736, 748-787, 804-808
packages/features/bookings/lib/payment/getBooking.ts (1)
164-186: Standardize organizationId derivation for brandingUse a single, predictable fallback order to avoid divergent branding results across flows (e.g., prefer org profile id, then team.parentId). Also consider extracting a helper for reuse.
- const hideBranding = booking.eventType?.id + // Prefer organizer org context, then team parent org + const organizationId = + organizerOrganizationId ?? booking.eventType?.team?.parentId ?? null; + const hideBranding = booking.eventType?.id ? await shouldHideBrandingForEvent({ eventTypeId: booking.eventType.id, team: booking.eventType.team ? { hideBranding: booking.eventType.team.hideBranding, parent: booking.eventType.team.parent ? { hideBranding: booking.eventType.team.parent.hideBranding, } : null, } : null, owner: booking.eventType.owner ? { id: booking.eventType.owner.id, hideBranding: booking.eventType.owner.hideBranding, } : null, - organizationId: organizerOrganizationId ?? booking.eventType.team?.parentId ?? null, + organizationId, }).catch(() => !!booking.eventType?.owner?.hideBranding) : false;packages/app-store/wipemycalother/lib/reschedule.ts (1)
227-227: Prefer named export over default exportNamed exports improve tree-shaking and refactoring.
As per coding guidelines
-export default Reschedule; +export { Reschedule };
📜 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 (26)
apps/web/modules/bookings/views/bookings-single-view.getServerSideProps.tsx(4 hunks)apps/web/modules/bookings/views/bookings-single-view.tsx(2 hunks)packages/app-store/vital/lib/reschedule.ts(3 hunks)packages/app-store/wipemycalother/lib/reschedule.ts(3 hunks)packages/emails/src/components/V2BaseEmailHtml.tsx(2 hunks)packages/emails/src/templates/BaseScheduledEmail.tsx(1 hunks)packages/features/CalendarEventBuilder.ts(1 hunks)packages/features/bookings/lib/getBookingToDelete.ts(3 hunks)packages/features/bookings/lib/handleBookingRequested.ts(4 hunks)packages/features/bookings/lib/handleCancelBooking.ts(6 hunks)packages/features/bookings/lib/handleConfirmation.ts(16 hunks)packages/features/bookings/lib/handleNewBooking.ts(6 hunks)packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts(2 hunks)packages/features/bookings/lib/payment/getBooking.ts(5 hunks)packages/features/credentials/handleDeleteCredential.ts(5 hunks)packages/features/ee/round-robin/roundRobinManualReassignment.ts(3 hunks)packages/features/handleMarkNoShow.ts(4 hunks)packages/lib/builders/CalendarEvent/class.ts(1 hunks)packages/lib/server/queries/bookings/canViewSensitiveBookingData.ts(1 hunks)packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts(4 hunks)packages/trpc/server/routers/viewer/bookings/confirm.handler.ts(6 hunks)packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts(3 hunks)packages/trpc/server/routers/viewer/bookings/get.handler.ts(11 hunks)packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts(3 hunks)packages/trpc/server/routers/viewer/bookings/util.ts(2 hunks)packages/types/Calendar.d.ts(1 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:
packages/types/Calendar.d.tspackages/lib/builders/CalendarEvent/class.tspackages/app-store/vital/lib/reschedule.tspackages/features/bookings/lib/payment/getBooking.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/features/credentials/handleDeleteCredential.tspackages/lib/server/queries/bookings/canViewSensitiveBookingData.tspackages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.tspackages/features/CalendarEventBuilder.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/bookings/lib/getBookingToDelete.tspackages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/get.handler.tspackages/trpc/server/routers/viewer/bookings/confirm.handler.tspackages/features/handleMarkNoShow.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleNewBooking.tspackages/features/ee/round-robin/roundRobinManualReassignment.tspackages/trpc/server/routers/viewer/bookings/editLocation.handler.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/features/bookings/lib/handleCancelBooking.tspackages/features/bookings/lib/handleBookingRequested.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:
packages/types/Calendar.d.tspackages/emails/src/templates/BaseScheduledEmail.tsxpackages/lib/builders/CalendarEvent/class.tspackages/emails/src/components/V2BaseEmailHtml.tsxpackages/app-store/vital/lib/reschedule.tspackages/features/bookings/lib/payment/getBooking.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tsapps/web/modules/bookings/views/bookings-single-view.tsxpackages/features/credentials/handleDeleteCredential.tspackages/lib/server/queries/bookings/canViewSensitiveBookingData.tspackages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.tspackages/features/CalendarEventBuilder.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/bookings/lib/getBookingToDelete.tspackages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/get.handler.tspackages/trpc/server/routers/viewer/bookings/confirm.handler.tspackages/features/handleMarkNoShow.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleNewBooking.tsapps/web/modules/bookings/views/bookings-single-view.getServerSideProps.tsxpackages/features/ee/round-robin/roundRobinManualReassignment.tspackages/trpc/server/routers/viewer/bookings/editLocation.handler.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/features/bookings/lib/handleCancelBooking.tspackages/features/bookings/lib/handleBookingRequested.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:
packages/types/Calendar.d.tspackages/emails/src/templates/BaseScheduledEmail.tsxpackages/lib/builders/CalendarEvent/class.tspackages/emails/src/components/V2BaseEmailHtml.tsxpackages/app-store/vital/lib/reschedule.tspackages/features/bookings/lib/payment/getBooking.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tsapps/web/modules/bookings/views/bookings-single-view.tsxpackages/features/credentials/handleDeleteCredential.tspackages/lib/server/queries/bookings/canViewSensitiveBookingData.tspackages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.tspackages/features/CalendarEventBuilder.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/bookings/lib/getBookingToDelete.tspackages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/get.handler.tspackages/trpc/server/routers/viewer/bookings/confirm.handler.tspackages/features/handleMarkNoShow.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleNewBooking.tsapps/web/modules/bookings/views/bookings-single-view.getServerSideProps.tsxpackages/features/ee/round-robin/roundRobinManualReassignment.tspackages/trpc/server/routers/viewer/bookings/editLocation.handler.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/features/bookings/lib/handleCancelBooking.tspackages/features/bookings/lib/handleBookingRequested.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Always use
t()for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/emails/src/templates/BaseScheduledEmail.tsxpackages/emails/src/components/V2BaseEmailHtml.tsxapps/web/modules/bookings/views/bookings-single-view.tsxapps/web/modules/bookings/views/bookings-single-view.getServerSideProps.tsx
🧠 Learnings (4)
📚 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:
packages/app-store/vital/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/features/credentials/handleDeleteCredential.tspackages/features/bookings/lib/handleConfirmation.tspackages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.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:
packages/app-store/vital/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/features/credentials/handleDeleteCredential.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/bookings/lib/getBookingToDelete.tspackages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/get.handler.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.ts
📚 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:
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.tspackages/features/bookings/lib/handleConfirmation.tspackages/trpc/server/routers/viewer/bookings/get.handler.tspackages/features/ee/round-robin/roundRobinManualReassignment.ts
📚 Learning: 2025-08-21T13:55:23.470Z
Learnt from: alishaz-polymath
PR: calcom/cal.com#23247
File: packages/features/webhooks/lib/service/FormWebhookService.ts:0-0
Timestamp: 2025-08-21T13:55:23.470Z
Learning: In the new webhook architecture for Cal.com, schedulePayload is considered legacy code that doesn't fit the clean architecture. The new architecture keeps webhook scheduling logic within the Service layer, specifically through a new method WebhookService.scheduleDelayedWebhooks, rather than using the old centralized schedulePayload helper.
Applied to files:
packages/features/bookings/lib/handleConfirmation.ts
🧬 Code graph analysis (17)
packages/app-store/vital/lib/reschedule.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/payment/getBooking.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
apps/web/modules/bookings/views/bookings-single-view.tsx (1)
packages/lib/server/queries/bookings/canViewSensitiveBookingData.ts (1)
canViewSensitiveBookingData(44-87)
packages/features/credentials/handleDeleteCredential.ts (2)
packages/lib/getOrgIdFromMemberOrTeamId.ts (1)
getOrgIdFromMemberOrTeamId(47-58)packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleConfirmation.ts (3)
packages/lib/getTeamIdFromEventType.ts (1)
getTeamIdFromEventType(3-29)packages/lib/getOrgIdFromMemberOrTeamId.ts (1)
getOrgIdFromMemberOrTeamId(47-58)packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/app-store/wipemycalother/lib/reschedule.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/trpc/server/routers/viewer/bookings/get.handler.ts (1)
packages/lib/server/queries/bookings/canViewSensitiveBookingData.ts (1)
canViewSensitiveBookingData(44-87)
packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/handleMarkNoShow.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleNewBooking.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
apps/web/modules/bookings/views/bookings-single-view.getServerSideProps.tsx (1)
packages/lib/server/queries/bookings/canViewSensitiveBookingData.ts (1)
canViewSensitiveBookingData(44-87)
packages/features/ee/round-robin/roundRobinManualReassignment.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts (4)
packages/lib/getOrgIdFromMemberOrTeamId.ts (1)
getOrgIdFromMemberOrTeamId(47-58)packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)packages/types/Calendar.d.ts (1)
CalendarEvent(164-228)packages/emails/email-manager.ts (1)
sendLocationChangeEmailsAndSMS(640-671)
packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts (2)
packages/lib/getOrgIdFromMemberOrTeamId.ts (1)
getOrgIdFromMemberOrTeamId(47-58)packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleCancelBooking.ts (2)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)packages/emails/email-manager.ts (1)
sendCancelledEmailsAndSMS(476-534)
packages/features/bookings/lib/handleBookingRequested.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
🔇 Additional comments (40)
packages/emails/src/components/V2BaseEmailHtml.tsx (2)
24-24: LGTM! Clear prop addition for branding control.The optional
hideLogoprop is well-named and appropriately typed. Making it optional ensures backward compatibility with existing usage.
185-185: LGTM! Conditional rendering logic is correct.The logo will be hidden when
hideLogoistrueand displayed otherwise (including whenundefined), which aligns with the PR's goal to respect the branding settings.packages/features/credentials/handleDeleteCredential.ts (3)
16-17: LGTM: Necessary imports for branding logic.The imports for
getOrgIdFromMemberOrTeamIdandshouldHideBrandingForEventare required to compute and propagate thehideBrandingflag through the cancellation flow.
254-283: LGTM: Expanded select for hideBranding computation.The Prisma select correctly fetches the additional fields (
eventType.id, team/ownerhideBranding,parentId, parenthideBranding) needed to compute thehideBrandingflag viashouldHideBrandingForEvent. The use ofselectadheres to the coding guidelines.
403-403: LGTM: hideBranding correctly propagated to cancellation emails.The computed
hideBrandingflag is properly passed tosendCancelledEmailsAndSMS, ensuring that emails respect the branding preferences when a payment credential is removed.packages/features/bookings/lib/handleNewBooking/getEventTypesFromDB.ts (2)
46-51: LGTM! Branding hierarchy properly captured.The addition of
hideBrandingfor both team and team.parent correctly supports the hierarchical branding logic needed for this feature. The shallow nesting and minimal field selection keep the query efficient.
115-115: owner.id is required by branding logic and downstream handlers
The field is consumed in shouldHideBrandingForEvent (via ProfileRepository.findByUserIdAndOrgSlug) and in various booking/payment flows (e.g., processPaymentRefund), so it should remain selected.packages/features/bookings/lib/getBookingToDelete.ts (3)
26-26: LGTM! User-level branding flag added.The
hideBrandingfield on the user is correctly added to support user-level branding preferences for deletion workflows.
44-44: Approve selecting eventType.id
VerifiedeventType.idis passed intoshouldHideBrandingForEventacross booking handlers.
58-63: Parent.hideBranding is correctly consumed by hideBranding logic. VerifiedshouldHideBrandingForEventUsingProfilepassesteam.parent.hideBrandingintoresolveHideBranding, which governs organization-level branding. No changes needed.packages/features/handleMarkNoShow.ts (2)
186-191: LGTM: Branding fields appropriately selected.The additions of
team.hideBrandingandteam.parent.hideBrandingcorrectly support the branding computation logic added later in the file.
330-330: LGTM: Correctly propagates comprehensive branding decision.The computed
hideBrandingflag is appropriately passed to workflow scheduling, replacing the simpler owner-only check with the comprehensive logic that considers team and organization settings.packages/features/bookings/lib/handleCancelBooking.ts (3)
327-335: LGTM: hideBranding propagated on evt.This ensures branding flows to webhooks and emails via CalendarEvent.
608-614: LGTM: email gating + branding-aware log.Conditional send and logged branding config look correct.
376-394: No changes required for hideBranding support. sendCancelledReminders accepts the hideBranding arg and passes it through to processWorkflowStep.apps/web/modules/bookings/views/bookings-single-view.tsx (2)
107-107: Prop plumbing looks goodcanViewSensitiveBookingData added to props and consumed in component.
705-744: UTM params correctly gated by permissionReplacing isHost with canViewSensitiveBookingData tightens access to sensitive tracking data.
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (2)
21-21: Import is appropriateBranding helper correctly imported here.
63-91: Prisma select is minimal and sufficientOnly required fields are selected (owner/team hideBranding, email-related flags, metadata). This aligns with “select only what you need” guidance.
apps/web/modules/bookings/views/bookings-single-view.getServerSideProps.tsx (4)
15-15: Import OKPermission helper correctly pulled from server queries.
229-240: Gating internal notes by permissionEarly-return when no teamId or no permission prevents leaking presets.
278-279: Prop exposed for client gatingPlumbing canViewSensitiveBookingData to client enables consistent UI decisions.
198-215: Server-side permission check is soundgetEventTypesFromDB already selects hosts, team, parent, and schedulingType needed by canViewSensitiveBookingData; no further changes.
packages/app-store/vital/lib/reschedule.ts (2)
8-8: Import OKBranding helper correctly introduced.
37-63: Prisma select is lean and relevantSelected fields cover email + branding needs without overfetching.
packages/features/bookings/lib/handleNewBooking.ts (2)
1318-1319: Good: hideBranding propagated to CalendarEventBuilderPassing the computed flag into the builder centralizes branding in downstream emails/workflows.
2199-2200: Verify downstream API signatures accept hideBranding
Confirm thatscheduleMandatoryReminderandWorkflowService.schedule*methods include ahideBrandingparameter in their signatures and that it’s propagated through to the email rendering.packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts (2)
7-9: LGTM: centralized branding utilities importedConsistent with other flows.
170-197: Branding logic and data selection are correct
The Prisma select oneventTypeincludesowner.hideBranding,team.hideBranding, andteam.parent.hideBrandingrequired byshouldHideBrandingForEvent.packages/trpc/server/routers/viewer/bookings/editLocation.handler.ts (1)
10-12: LGTM: consistent branding computation and propagation across update location flow
- orgId resolved via getOrgIdFromMemberOrTeamId; fallback to owner.hideBranding on error is safe.
- evt.hideBranding set and passed to connected apps, DB update, and emails.
Also applies to: 269-297, 298-302, 311-312, 316-325, 328-329, 334-335
packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)
278-280: LGTM: hideBranding propagated to downstream flows
Evt includeshideBrandingand it flows through tohandleConfirmation(which supports it) and workflow scheduling.packages/features/bookings/lib/payment/getBooking.ts (3)
90-96: Team.branding fields selection looks goodSelecting team.hideBranding and parent.hideBranding is appropriate for branding decisions.
41-43: Owner.id selection is necessaryAdding owner.id enables user-event branding resolution. LGTM.
229-230: evt.hideBranding propagationCarrying hideBranding on CalendarEvent is correct and keeps downstream consumers consistent.
packages/app-store/wipemycalother/lib/reschedule.ts (2)
38-61: Branding-related selects look goodSelecting eventType.id/team/owner branding fields is appropriate and minimal.
208-209: Applying hideBranding to the email payloadSetting builder.calendarEvent.hideBranding ensures reschedule emails honor the setting. LGTM.
packages/trpc/server/routers/viewer/bookings/util.ts (2)
117-125: Context typing updates look correctAugmenting eventType shape with branding fields matches the new selects.
52-56: Remove outdated credential leak warning
This query only selectsdestinationCalendar; there is nocredentialsinclude here, so there’s no risk of exposingcredential.key.Likely an incorrect or invalid review comment.
packages/types/Calendar.d.ts (1)
227-228: CalendarEvent.hideBranding addition LGTMThe new flag is appropriately optional and aligns with email/template usage.
packages/features/CalendarEventBuilder.ts (1)
271-277: withHideBranding builder method looks goodFluent setter is consistent with existing API and type-safe.
| const hideBranding = bookingToReschedule.eventType?.id | ||
| ? await shouldHideBrandingForEvent({ | ||
| eventTypeId: bookingToReschedule.eventType.id, | ||
| team: bookingToReschedule.eventType.team | ||
| ? { | ||
| hideBranding: bookingToReschedule.eventType.team.hideBranding, | ||
| parent: bookingToReschedule.eventType.team.parent | ||
| ? { | ||
| hideBranding: bookingToReschedule.eventType.team.parent.hideBranding, | ||
| } | ||
| : null, | ||
| } | ||
| : null, | ||
| owner: bookingToReschedule.eventType.owner | ||
| ? { | ||
| id: bookingToReschedule.eventType.owner.id, | ||
| hideBranding: bookingToReschedule.eventType.owner.hideBranding, | ||
| } | ||
| : null, | ||
| organizationId: bookingToReschedule.eventType.team?.parentId || null, | ||
| }).catch(() => !!bookingToReschedule.eventType?.owner?.hideBranding) | ||
| : false; | ||
|
|
||
| builder.calendarEvent.hideBranding = hideBranding; | ||
|
|
There was a problem hiding this comment.
Pass correct organizationId for user events and use builder API
For user events (no team), organizationId is currently null, which can miss org-level branding settings. Use the current user’s org when team is absent. Prefer builder.withHideBranding if available and log the catch for observability.
Apply:
- const hideBranding = bookingToReschedule.eventType?.id
+ const orgIdForBranding =
+ bookingToReschedule.eventType?.team?.parentId ??
+ (user.profile?.organizationId ?? null);
+
+ const hideBranding = bookingToReschedule.eventType?.id
? await shouldHideBrandingForEvent({
eventTypeId: bookingToReschedule.eventType.id,
team: bookingToReschedule.eventType.team
? {
hideBranding: bookingToReschedule.eventType.team.hideBranding,
parent: bookingToReschedule.eventType.team.parent
? {
hideBranding: bookingToReschedule.eventType.team.parent.hideBranding,
}
: null,
}
: null,
owner: bookingToReschedule.eventType.owner
? {
id: bookingToReschedule.eventType.owner.id,
hideBranding: bookingToReschedule.eventType.owner.hideBranding,
}
: null,
- organizationId: bookingToReschedule.eventType.team?.parentId || null,
- }).catch(() => !!bookingToReschedule.eventType?.owner?.hideBranding)
+ organizationId: orgIdForBranding,
+ }).catch((e) => {
+ log.warn(
+ "shouldHideBrandingForEvent failed; falling back to owner.hideBranding",
+ safeStringify({ bookingUid: bookingToReschedule.uid, error: e instanceof Error ? e.message : String(e) })
+ );
+ return !!bookingToReschedule.eventType?.owner?.hideBranding;
+ })
: false;
- builder.calendarEvent.hideBranding = hideBranding;
+ if (typeof (builder as any).withHideBranding === "function") {
+ (builder as any).withHideBranding(hideBranding);
+ } else {
+ builder.calendarEvent.hideBranding = hideBranding;
+ }As per coding guidelines
📝 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.
| const hideBranding = bookingToReschedule.eventType?.id | |
| ? await shouldHideBrandingForEvent({ | |
| eventTypeId: bookingToReschedule.eventType.id, | |
| team: bookingToReschedule.eventType.team | |
| ? { | |
| hideBranding: bookingToReschedule.eventType.team.hideBranding, | |
| parent: bookingToReschedule.eventType.team.parent | |
| ? { | |
| hideBranding: bookingToReschedule.eventType.team.parent.hideBranding, | |
| } | |
| : null, | |
| } | |
| : null, | |
| owner: bookingToReschedule.eventType.owner | |
| ? { | |
| id: bookingToReschedule.eventType.owner.id, | |
| hideBranding: bookingToReschedule.eventType.owner.hideBranding, | |
| } | |
| : null, | |
| organizationId: bookingToReschedule.eventType.team?.parentId || null, | |
| }).catch(() => !!bookingToReschedule.eventType?.owner?.hideBranding) | |
| : false; | |
| builder.calendarEvent.hideBranding = hideBranding; | |
| const orgIdForBranding = | |
| bookingToReschedule.eventType?.team?.parentId ?? | |
| (user.profile?.organizationId ?? null); | |
| const hideBranding = bookingToReschedule.eventType?.id | |
| ? await shouldHideBrandingForEvent({ | |
| eventTypeId: bookingToReschedule.eventType.id, | |
| team: bookingToReschedule.eventType.team | |
| ? { | |
| hideBranding: bookingToReschedule.eventType.team.hideBranding, | |
| parent: bookingToReschedule.eventType.team.parent | |
| ? { | |
| hideBranding: bookingToReschedule.eventType.team.parent.hideBranding, | |
| } | |
| : null, | |
| } | |
| : null, | |
| owner: bookingToReschedule.eventType.owner | |
| ? { | |
| id: bookingToReschedule.eventType.owner.id, | |
| hideBranding: bookingToReschedule.eventType.owner.hideBranding, | |
| } | |
| : null, | |
| organizationId: orgIdForBranding, | |
| }).catch((e) => { | |
| log.warn( | |
| "shouldHideBrandingForEvent failed; falling back to owner.hideBranding", | |
| safeStringify({ | |
| bookingUid: bookingToReschedule.uid, | |
| error: e instanceof Error ? e.message : String(e), | |
| }) | |
| ); | |
| return !!bookingToReschedule.eventType?.owner?.hideBranding; | |
| }) | |
| : false; | |
| if (typeof (builder as any).withHideBranding === "function") { | |
| (builder as any).withHideBranding(hideBranding); | |
| } else { | |
| builder.calendarEvent.hideBranding = hideBranding; | |
| } |
🤖 Prompt for AI Agents
In packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts
around lines 295 to 319, the code sets organizationId to null for user-owned
events and directly assigns builder.calendarEvent.hideBranding; change this to
pass the current user's organizationId when eventType.team is absent (e.g., use
bookingToReschedule.eventType.owner?.organizationId or the request user org),
call the builder API method withHideBranding (builder.withHideBranding or
equivalent) instead of setting calendarEvent.hideBranding directly, and replace
the silent .catch(() => !!...) with a catch that logs the error for
observability while falling back to the owner/team hideBranding value; ensure
the resolved boolean from shouldHideBrandingForEvent is applied to the
builder.withHideBranding call.
- Fix organizationId resolution to properly handle user events in organizations - Add comprehensive branding logic across all booking lifecycle handlers - Implement profile lookup fallback for user organization ID - Add hideBranding property to CalendarEvent interface - Add withBranding method to CalendarEventBuilder - Update email templates to conditionally hide logo based on branding - Improve error handling and logging for branding computation - Optimize Prisma queries by replacing include with select - Remove credentials exposure in booking handlers - Ensure consistent branding across reschedule, cancel, and confirmation flows
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/features/ee/round-robin/roundRobinManualReassignment.ts (1)
557-588: Inconsistent branding flag—line 580 hardcodestrueinstead of using computedhideBranding.At line 580,
hideBranding: trueis hardcoded when rescheduling existing workflow reminders for the new host. Meanwhile, line 645 correctly uses the computedhideBrandingvalue for new event workflows. This inconsistency means:
- Existing workflow reminders always hide branding (line 580).
- New event workflows respect the computed branding setting (line 645).
For consistency, line 580 should reference the computed
hideBrandingvariable (available since line 488).Apply this diff to use the computed value:
await scheduleEmailReminder({ evt: { ...evt, metadata: workflowEventMetadata, eventType, bookerUrl, }, action: WorkflowActions.EMAIL_HOST, triggerEvent: workflow.trigger, timeSpan: { time: workflow.time, timeUnit: workflow.timeUnit, }, sendTo: [newUser.email], template: workflowStep.template, emailSubject: workflowStep.emailSubject || undefined, emailBody: workflowStep.reminderBody || undefined, sender: workflowStep.sender || SENDER_NAME, - hideBranding: true, + hideBranding: hideBranding, includeCalendarEvent: workflowStep.includeCalendarEvent, workflowStepId: workflowStep.id, verifiedAt: workflowStep.verifiedAt, });packages/trpc/server/routers/viewer/bookings/util.ts (1)
140-143: Critical type mismatch: user type includes credentials, but they're not selected.The type declares
User & { destinationCalendar, credentials }, implying allUserfields plus those extras are present. However, theselectat lines 60–66 only fetchesname,timeZone,locale, anddestinationCalendar—credentials are not selected, and many User fields are omitted. Code accessingbooking.user.credentialswill compile but fail at runtime.Replace the intersection with an explicit type matching the selected fields:
user: - | (User & { - destinationCalendar: DestinationCalendar | null; - credentials: Credential[]; - }) + | { + name: string | null; + email: string; + timeZone: string; + locale: string | null; + destinationCalendar: DestinationCalendar | null; + } | null;
♻️ Duplicate comments (3)
packages/features/handleMarkNoShow.ts (1)
174-181: Branding computation fixes look solid.Owner id added, team/parent branding selected, and branding calc wrapped in try/catch with safe default. Passing hideBranding to workflow scheduling is correct.
Also applies to: 187-193, 221-266, 350-356
packages/features/bookings/lib/handleNewBooking.ts (1)
464-501: Resolve orgId via helper to avoid miscomputed branding for personal/org-managed eventsDeriving organizationId via team.parentId/profile is brittle. Use getOrgIdFromMemberOrTeamId to cover both team and personal events consistently. This was flagged earlier.
Apply this diff:
- // Calculate hide branding setting using comprehensive logic that considers team and organization settings - // For user events, fetch the user's profile to get the organization ID - const userOrganizationId = !eventType.team - ? ( - await prisma.profile.findFirst({ - where: { - userId: eventType.owner?.id, - }, - select: { - organizationId: true, - }, - }) - )?.organizationId - : null; - - const orgIdForBranding = eventType.team?.parentId ?? userOrganizationId ?? null; - + // Calculate hide branding using consistent org resolution + const orgIdForBranding = await getOrgIdFromMemberOrTeamId({ + memberId: eventType.owner?.id ?? null, + teamId: eventType.team?.id ?? null, + }); + const hideBranding = await shouldHideBrandingForEvent({ eventTypeId: eventType.id, team: eventType.team ? { hideBranding: eventType.team.hideBranding, parent: eventType.team.parent ? { hideBranding: eventType.team.parent.hideBranding, } : null, } : null, owner: eventType.owner ? { id: eventType.owner.id, hideBranding: eventType.owner.hideBranding, } : null, - organizationId: orgIdForBranding, + organizationId: orgIdForBranding ?? null, });packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)
148-185: Use getOrgIdFromMemberOrTeamId for branding orgId (consistency + correctness)Replace manual profile/parentId logic with the helper to correctly derive org for user events and org-managed users. This aligns with other handlers and prior feedback.
-// For user events, fetch the user's profile to get the organization ID -const userOrganizationId = !booking.eventType?.team - ? ( - await prisma.profile.findFirst({ - where: { - userId: booking.userId, - }, - select: { - organizationId: true, - }, - }) - )?.organizationId - : null; - -const orgIdForBranding = booking.eventType?.team?.parentId ?? userOrganizationId ?? null; +const orgIdForBranding = await getOrgIdFromMemberOrTeamId({ + memberId: booking.userId ?? null, + teamId: booking.eventType?.team?.id ?? booking.eventType?.teamId ?? null, +}); const hideBranding = await shouldHideBrandingForEvent({ eventTypeId: booking.eventType?.id || 0, team: booking.eventType?.team ? { hideBranding: booking.eventType.team.hideBranding, parent: booking.eventType.team.parent ? { hideBranding: booking.eventType.team.parent.hideBranding, } : null, } : null, owner: booking.eventType?.owner ? { id: booking.eventType.owner.id, hideBranding: booking.eventType.owner.hideBranding, } : null, - organizationId: orgIdForBranding, + organizationId: orgIdForBranding ?? null, });
🧹 Nitpick comments (16)
packages/features/ee/round-robin/roundRobinManualReassignment.ts (1)
471-507: Profile fetch is redundant—shouldHideBrandingForEventfetches it again.The code queries
prisma.profileat lines 475‑483 to retrieveuserOrganizationId, then passes thatorganizationIdtoshouldHideBrandingForEvent. Based on the relevant code snippet frompackages/lib/hideBranding.ts, that function internally callsProfileRepository.findByUserIdAndOrgSlug(lines 91‑95 in the snippet) to fetch the profile again whenorganizationIdis provided.This double fetch is inefficient. Consider one of the following:
- Fetch the full profile once and pass the organizationId without a second fetch inside
shouldHideBrandingForEvent.- Skip the profile fetch here if
shouldHideBrandingForEventcan derive organizationId internally (requires refactoring the utility function).If refactoring
shouldHideBrandingForEventis out of scope for this PR, document this as a known inefficiency and track it in a follow-up issue.packages/features/credentials/handleDeleteCredential.ts (1)
268-268: Remove unused field selection.The
parentIdfield is selected but never used in the subsequent code. Theparentrelation object is used instead (lines 349-353).As per coding guidelines, Prisma queries should only select data you need.
Apply this diff to remove the unused field:
select: { id: true, name: true, - parentId: true, hideBranding: true,packages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.ts (2)
139-167: Harden branding computation: add try/catch, null-safety, and parallelize team/profile fetches.
- Risk: organizerUser is assumed; organizerUser.id access can throw if undefined.
- Resilience: shouldHideBrandingForEvent errors would currently bubble and break reschedule email flow.
- Type-safety: avoid
(teamForBranding as any)by shaping a minimal typed object.- Perf: fetch team and organizer profile concurrently.
Apply this refactor:
- const teamForBranding = eventType.team?.id - ? await prisma.team.findUnique({ - where: { id: eventType.team.id }, - select: { - id: true, - hideBranding: true, - parentId: true, - parent: { - select: { - hideBranding: true, - }, - }, - }, - }) - : null; - - const hideBranding = await shouldHideBrandingForEvent({ - eventTypeId: eventType.id, - team: (teamForBranding as any) ?? null, - owner: organizerUser ?? null, - organizationId: (await (async () => { - if (teamForBranding?.parentId) return teamForBranding.parentId; - const organizerProfile = await prisma.profile.findFirst({ - where: { userId: organizerUser.id }, - select: { organizationId: true }, - }); - return organizerProfile?.organizationId ?? null; - })()), - }); + if (!organizerUser) { + loggerWithEventDetails.warn("organizerUser missing; defaulting hideBranding=false"); + } + const [teamForBranding, organizerProfile] = await Promise.all([ + eventType.team?.id + ? prisma.team.findUnique({ + where: { id: eventType.team.id }, + select: { + id: true, + hideBranding: true, + parentId: true, + parent: { select: { hideBranding: true } }, + }, + }) + : Promise.resolve(null), + organizerUser + ? prisma.profile.findFirst({ + where: { userId: organizerUser.id }, + select: { organizationId: true }, + }) + : Promise.resolve(null), + ]); + const orgIdForBranding = teamForBranding?.parentId ?? organizerProfile?.organizationId ?? null; + let hideBranding = false; + try { + hideBranding = await shouldHideBrandingForEvent({ + eventTypeId: eventType.id, + team: teamForBranding ?? null, + owner: organizerUser ?? null, + organizationId: orgIdForBranding, + }); + } catch (e) { + loggerWithEventDetails.error("Failed to compute hideBranding (reschedule owner combine)", e); + hideBranding = false; + }
176-183: Removeas anyand pass a typed CalendarEvent with hideBranding.CalendarEvent now supports hideBranding in this PR. Avoid unsafe casts.
- ( - { - ...copyEvent, - additionalNotes, - cancellationReason: `$RCH$${rescheduleReason ? rescheduleReason : ""}`, - hideBranding, - } as any - ), + { + ...copyEvent, + additionalNotes, + cancellationReason: `$RCH$${rescheduleReason ? rescheduleReason : ""}`, + hideBranding, + },packages/features/bookings/lib/handleCancelBooking.ts (2)
100-106: Guard branding computation with try/catch to avoid blocking cancellations.If shouldHideBrandingForEvent throws (DB hiccup, etc.), the whole cancellation fails. Default to false and log.
- const hideBranding = await shouldHideBrandingForEvent({ - eventTypeId: bookingToDelete.eventTypeId ?? 0, - team: bookingToDelete.eventType?.team ?? null, - owner: bookingToDelete.user ?? null, - organizationId: bookingToDelete.eventType?.team?.parentId ?? userOrganizationId ?? null, - }); + let hideBranding = false; + try { + hideBranding = await shouldHideBrandingForEvent({ + eventTypeId: bookingToDelete.eventTypeId ?? 0, + team: bookingToDelete.eventType?.team ?? null, + owner: bookingToDelete.user ?? null, + organizationId: bookingToDelete.eventType?.team?.parentId ?? userOrganizationId ?? null, + }); + } catch (e) { + log.error("Failed to compute hideBranding for cancellation", e); + hideBranding = false; + }
606-621: Simplify condition; keep behavior identical.Use simpler logic for readability.
- if (!platformClientId || (platformClientId && arePlatformEmailsEnabled)) { + if (!platformClientId || arePlatformEmailsEnabled) {packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts (2)
26-55: Add resilience + parallelism for branding; avoid brittle null access.
- organizerUser.id access can throw if organizerUser missing.
- Compute team/profile in parallel and guard shouldHideBrandingForEvent.
- const teamForBranding = eventType.team?.id - ? await prisma.team.findUnique({ - where: { id: eventType.team.id }, - select: { - id: true, - hideBranding: true, - parentId: true, - parent: { - select: { - hideBranding: true, - }, - }, - }, - }) - : null; - - const hideBranding = await shouldHideBrandingForEvent({ - eventTypeId: eventType.id, - team: (teamForBranding as any) ?? null, - owner: organizerUser ?? null, - organizationId: (await (async () => { - if (teamForBranding?.parentId) return teamForBranding.parentId; - const organizerProfile = await prisma.profile.findFirst({ - where: { userId: organizerUser.id }, - select: { organizationId: true }, - }); - return organizerProfile?.organizationId ?? null; - })()), - }); + if (!organizerUser) { + // Non-blocking default; we still proceed with emails if branding can't be computed + // eslint-disable-next-line no-console + console.warn("organizerUser missing; defaulting hideBranding=false"); + } + const [teamForBranding, organizerProfile] = await Promise.all([ + eventType.team?.id + ? prisma.team.findUnique({ + where: { id: eventType.team.id }, + select: { + id: true, + hideBranding: true, + parentId: true, + parent: { select: { hideBranding: true } }, + }, + }) + : Promise.resolve(null), + organizerUser + ? prisma.profile.findFirst({ + where: { userId: organizerUser.id }, + select: { organizationId: true }, + }) + : Promise.resolve(null), + ]); + const orgIdForBranding = teamForBranding?.parentId ?? organizerProfile?.organizationId ?? null; + let hideBranding = false; + try { + hideBranding = await shouldHideBrandingForEvent({ + eventTypeId: eventType.id, + team: teamForBranding ?? null, + owner: organizerUser ?? null, + organizationId: orgIdForBranding, + }); + } catch (e) { + // eslint-disable-next-line no-console + console.error("Failed to compute hideBranding (attendee reschedule); defaulting to false", e); + hideBranding = false; + }
86-86: Removeas anywhen sending emails; pass typed CalendarEvent with hideBranding.- await sendRescheduledSeatEmailAndSMS({ ...evt, hideBranding } as any, seatAttendee as Person, eventType.metadata); + await sendRescheduledSeatEmailAndSMS({ ...evt, hideBranding }, seatAttendee as Person, eventType.metadata);- await sendRescheduledSeatEmailAndSMS({ ...copyEvent, hideBranding } as any, seatAttendee as Person, eventType.metadata); + await sendRescheduledSeatEmailAndSMS({ ...copyEvent, hideBranding }, seatAttendee as Person, eventType.metadata);Also applies to: 128-128
packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts (2)
34-62: Make branding calc robust; perform team/profile queries in parallel.Guard computation and avoid
(teamForBranding as any).- const teamForBranding = eventType.team?.id - ? await prisma.team.findUnique({ - where: { id: eventType.team.id }, - select: { - id: true, - hideBranding: true, - parentId: true, - parent: { - select: { - hideBranding: true, - }, - }, - }, - }) - : null; - - const hideBranding = await shouldHideBrandingForEvent({ - eventTypeId: eventType.id, - team: (teamForBranding as any) ?? null, - owner: organizerUser ?? null, - organizationId: (await (async () => { - if (teamForBranding?.parentId) return teamForBranding.parentId; - const organizerProfile = await prisma.profile.findFirst({ - where: { userId: organizerUser.id }, - select: { organizationId: true }, - }); - return organizerProfile?.organizationId ?? null; - })()), - }); + const [teamForBranding, organizerProfile] = await Promise.all([ + eventType.team?.id + ? prisma.team.findUnique({ + where: { id: eventType.team.id }, + select: { + id: true, + hideBranding: true, + parentId: true, + parent: { select: { hideBranding: true } }, + }, + }) + : Promise.resolve(null), + prisma.profile.findFirst({ + where: { userId: organizerUser.id }, + select: { organizationId: true }, + }), + ]); + const orgIdForBranding = teamForBranding?.parentId ?? organizerProfile?.organizationId ?? null; + let hideBranding = false; + try { + hideBranding = await shouldHideBrandingForEvent({ + eventTypeId: eventType.id, + team: teamForBranding ?? null, + owner: organizerUser ?? null, + organizationId: orgIdForBranding, + }); + } catch (e) { + loggerWithEventDetails.error("Failed to compute hideBranding (owner reschedule move)", e); + hideBranding = false; + }
131-138: Avoidas anywhen passing to reschedule emails; use typed CalendarEvent.- ( - { - ...copyEvent, - additionalNotes, - cancellationReason: `$RCH$${rescheduleReason ? rescheduleReason : ""}`, - hideBranding, - } as any - ), + { + ...copyEvent, + additionalNotes, + cancellationReason: `$RCH$${rescheduleReason ? rescheduleReason : ""}`, + hideBranding, + },packages/app-store/vital/lib/reschedule.ts (1)
227-227: Prefer the builder API for brandingWe now have
CalendarEventBuilder.withBranding; please call it instead of mutatingbuilder.calendarEventdirectly so future builder invariants stay centralized.packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts (1)
198-218: Log branding resolution failuresIf
shouldHideBrandingForEventthrows we silently swallow the exception. Please log the failure (as done in other flows) before falling back so we can trace branding issues in prod.packages/app-store/wipemycalother/lib/reschedule.ts (1)
227-227: Use withBranding helperPlease switch to
builder.withBranding(hideBranding)rather than pokingbuilder.calendarEvent—keeps all builder mutations going through the public API.packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (1)
339-339: Route branding through the builderNow that
CalendarEventBuilderexposeswithBranding, please call it here instead of assigning tobuilder.calendarEventso the builder remains the single point of truth for event mutations.packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)
99-104: Prisma select scope: minimize to needed fields (owner)Avoid
owner: true. Select only fields used for branding (id, hideBranding).As per coding guidelines
Example (outside exact range):
owner: { select: { id: true, hideBranding: true, }, },packages/features/bookings/lib/handleBookingRequested.ts (1)
85-93: Use getOrgIdFromMemberOrTeamId for org derivationUnify org resolution across handlers; avoids extra queries and edge-case misses.
-const organizationIdForBranding = teamForBranding?.parentId - ? teamForBranding.parentId - : ( - await prisma.profile.findFirst({ - where: { userId: booking.userId ?? undefined }, - select: { organizationId: true }, - }) - )?.organizationId ?? null; +const organizationIdForBranding = + (await getOrgIdFromMemberOrTeamId({ + memberId: booking.userId ?? null, + teamId: booking.eventType?.teamId ?? null, + })) ?? null;
📜 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 (19)
packages/app-store/vital/lib/reschedule.ts(3 hunks)packages/app-store/wipemycalother/lib/reschedule.ts(3 hunks)packages/emails/src/templates/BaseScheduledEmail.tsx(1 hunks)packages/features/CalendarEventBuilder.ts(1 hunks)packages/features/bookings/lib/handleBookingRequested.ts(4 hunks)packages/features/bookings/lib/handleCancelBooking.ts(6 hunks)packages/features/bookings/lib/handleConfirmation.ts(17 hunks)packages/features/bookings/lib/handleNewBooking.ts(6 hunks)packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts(4 hunks)packages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.ts(4 hunks)packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts(3 hunks)packages/features/credentials/handleDeleteCredential.ts(5 hunks)packages/features/ee/round-robin/roundRobinManualReassignment.ts(5 hunks)packages/features/handleMarkNoShow.ts(6 hunks)packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts(5 hunks)packages/trpc/server/routers/viewer/bookings/confirm.handler.ts(10 hunks)packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts(5 hunks)packages/trpc/server/routers/viewer/bookings/util.ts(2 hunks)packages/types/Calendar.d.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/emails/src/templates/BaseScheduledEmail.tsx
- packages/types/Calendar.d.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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:
packages/app-store/vital/lib/reschedule.tspackages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.tspackages/trpc/server/routers/viewer/bookings/confirm.handler.tspackages/features/bookings/lib/handleCancelBooking.tspackages/features/credentials/handleDeleteCredential.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/features/bookings/lib/handleNewBooking.tspackages/features/handleMarkNoShow.tspackages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.tspackages/features/CalendarEventBuilder.tspackages/features/ee/round-robin/roundRobinManualReassignment.tspackages/features/bookings/lib/handleBookingRequested.tspackages/app-store/wipemycalother/lib/reschedule.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:
packages/app-store/vital/lib/reschedule.tspackages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.tspackages/trpc/server/routers/viewer/bookings/confirm.handler.tspackages/features/bookings/lib/handleCancelBooking.tspackages/features/credentials/handleDeleteCredential.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/features/bookings/lib/handleNewBooking.tspackages/features/handleMarkNoShow.tspackages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.tspackages/features/CalendarEventBuilder.tspackages/features/ee/round-robin/roundRobinManualReassignment.tspackages/features/bookings/lib/handleBookingRequested.tspackages/app-store/wipemycalother/lib/reschedule.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:
packages/app-store/vital/lib/reschedule.tspackages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.tspackages/trpc/server/routers/viewer/bookings/confirm.handler.tspackages/features/bookings/lib/handleCancelBooking.tspackages/features/credentials/handleDeleteCredential.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/features/bookings/lib/handleNewBooking.tspackages/features/handleMarkNoShow.tspackages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.tspackages/features/CalendarEventBuilder.tspackages/features/ee/round-robin/roundRobinManualReassignment.tspackages/features/bookings/lib/handleBookingRequested.tspackages/app-store/wipemycalother/lib/reschedule.ts
🧠 Learnings (6)
📚 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:
packages/app-store/vital/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/credentials/handleDeleteCredential.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/app-store/wipemycalother/lib/reschedule.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:
packages/app-store/vital/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleConfirmation.tspackages/features/credentials/handleDeleteCredential.tspackages/trpc/server/routers/viewer/bookings/addGuests.handler.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/app-store/wipemycalother/lib/reschedule.ts
📚 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:
packages/trpc/server/routers/viewer/bookings/util.tspackages/features/bookings/lib/handleConfirmation.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts
📚 Learning: 2025-08-21T13:55:23.470Z
Learnt from: alishaz-polymath
PR: calcom/cal.com#23247
File: packages/features/webhooks/lib/service/FormWebhookService.ts:0-0
Timestamp: 2025-08-21T13:55:23.470Z
Learning: In the new webhook architecture for Cal.com, schedulePayload is considered legacy code that doesn't fit the clean architecture. The new architecture keeps webhook scheduling logic within the Service layer, specifically through a new method WebhookService.scheduleDelayedWebhooks, rather than using the old centralized schedulePayload helper.
Applied to files:
packages/features/bookings/lib/handleConfirmation.ts
📚 Learning: 2025-08-21T12:28:42.018Z
Learnt from: alishaz-polymath
PR: calcom/cal.com#23247
File: packages/features/webhooks/lib/factory/WebhookPayloadFactory.ts:274-282
Timestamp: 2025-08-21T12:28:42.018Z
Learning: In webhook DTOs in packages/features/webhooks/lib/dto/types.ts, the booking fields are restricted structures containing only specific fields (id, eventTypeId, userId, and sometimes additional fields like startTime or smsReminderNumber) rather than full database booking objects, so there are no security or PII leakage concerns when using these booking objects in webhook payloads.
Applied to files:
packages/trpc/server/routers/viewer/bookings/confirm.handler.ts
📚 Learning: 2025-08-21T12:28:42.018Z
Learnt from: alishaz-polymath
PR: calcom/cal.com#23247
File: packages/features/webhooks/lib/factory/WebhookPayloadFactory.ts:274-282
Timestamp: 2025-08-21T12:28:42.018Z
Learning: In BookingPaymentInitiatedDTO and other webhook DTOs in packages/features/webhooks/lib/dto/types.ts, the booking field is a restricted structure containing only specific fields (id, eventTypeId, userId) rather than the full database booking object, so there are no security or PII leakage concerns when passing the booking object to buildEventPayload.
Applied to files:
packages/trpc/server/routers/viewer/bookings/confirm.handler.ts
🧬 Code graph analysis (15)
packages/app-store/vital/lib/reschedule.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleSeats/reschedule/owner/combineTwoSeatedBookings.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleConfirmation.ts (4)
packages/lib/getTeamIdFromEventType.ts (1)
getTeamIdFromEventType(3-29)packages/lib/getOrgIdFromMemberOrTeamId.ts (1)
getOrgIdFromMemberOrTeamId(47-58)packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)packages/lib/server/service/workflows.ts (1)
WorkflowService(10-131)
packages/features/bookings/lib/handleSeats/reschedule/attendee/attendeeRescheduleSeatedBooking.ts (3)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)packages/emails/email-manager.ts (1)
sendRescheduledSeatEmailAndSMS(323-342)packages/types/Calendar.d.ts (1)
Person(33-46)
packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleCancelBooking.ts (2)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)packages/emails/email-manager.ts (1)
sendCancelledEmailsAndSMS(476-534)
packages/features/credentials/handleDeleteCredential.ts (2)
packages/lib/getOrgIdFromMemberOrTeamId.ts (1)
getOrgIdFromMemberOrTeamId(47-58)packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts (2)
packages/lib/getOrgIdFromMemberOrTeamId.ts (1)
getOrgIdFromMemberOrTeamId(47-58)packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleNewBooking.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/handleMarkNoShow.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleSeats/reschedule/owner/moveSeatedBookingToNewTimeSlot.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/ee/round-robin/roundRobinManualReassignment.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/features/bookings/lib/handleBookingRequested.ts (3)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)packages/emails/email-manager.ts (2)
sendOrganizerRequestEmail(433-436)sendAttendeeRequestEmailAndSMS(451-454)packages/lib/server/service/workflows.ts (1)
WorkflowService(10-131)
packages/app-store/wipemycalother/lib/reschedule.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
🔇 Additional comments (18)
packages/features/ee/round-robin/roundRobinManualReassignment.ts (2)
382-382: LGTM—Correctly strips cancellationReason from scheduled/updated emails.The destructuring removes
cancellationReasonfrom events passed tosendRoundRobinScheduledEmailsAndSMS(line 387) andsendRoundRobinUpdatedEmailsAndSMS(line 436), while preserving it for the cancellation email (line 407) and workflow handling (line 445). This ensures cancellation reasons appear only in cancellation emails, not in new-booking notifications.
645-645: LGTM—Correctly applies computedhideBrandingto new event workflows.The computed branding flag is properly passed to
scheduleWorkflowReminders, ensuring new event workflows respect the organization/team branding settings.packages/trpc/server/routers/viewer/bookings/util.ts (1)
27-56: LGTM on eventType select with branding fields.The switch from
includetoselectwith explicit field enumeration correctly addresses the previous review feedback and aligns with the coding guideline to always useselectfor Prisma queries. The addition ofhideBrandingflags onteam,parent, andownerproperly supports the PR's branding-control objective.packages/features/credentials/handleDeleteCredential.ts (3)
16-19: LGTM! Imports are used appropriately.The new imports are correctly utilized in the branding logic and error handling below.
338-367: Excellent error handling improvement!The error handling for
shouldHideBrandingForEventnow logs failures before falling back to the owner's branding preference. This addresses the concern from the previous review and ensures unexpected errors are visible for debugging while maintaining a safe fallback.
407-407: LGTM! Branding flag correctly propagated.The computed
hideBrandingvalue is correctly passed to the email function, ensuring cancellation emails respect the branding preference.packages/features/bookings/lib/handleCancelBooking.ts (1)
86-99: Upstream select includes required branding fields Selections for getBookingToDelete include team.hideBranding, team.parent.hideBranding, team.parentId, and user.hideBranding; shouldHideBrandingForEvent will compute correctly.packages/features/CalendarEventBuilder.ts (1)
263-274: Nice builder extensions
withOneTimePasswordand the newwithBrandinghelper look solid—this will make downstream updates cleaner.packages/features/bookings/lib/handleNewBooking.ts (4)
1346-1347: Good: centralized branding applied to event buildwithBranding(hideBranding) is the right place; ensures consistent downstream usage.
2227-2231: Good: pass hideBranding into workflow scheduling (payment initiated)Propagation is consistent.
2408-2412: Good: include hideBranding in mandatory remindersMatches expected behavior.
2421-2426: Good: include hideBranding in workflows for new bookingPropagation looks correct.
packages/trpc/server/routers/viewer/bookings/confirm.handler.ts (1)
295-296: Good: propagate hideBranding to evt and handleConfirmationConsistent with the branding model.
Also applies to: 357-358
packages/features/bookings/lib/handleBookingRequested.ts (1)
116-120: Good: hideBranding applied to emails and workflowsPropagation looks correct.
Also applies to: 162-179
packages/features/bookings/lib/handleConfirmation.ts (4)
3-5: LGTM: EventManager imports/typesImports look correct.
75-76: LGTM: hideBranding plumbed through handleConfirmation signatureNon-breaking default and explicit propagation.
Also applies to: 87-88
99-108: LGTM: compute org/team context and calculated branding onceGood use of getOrgIdFromMemberOrTeamId + shouldHideBrandingForEvent.
Also applies to: 109-151
189-195: LGTM: hideBranding forwarded to emails and workflow schedulingPropagation is consistent across confirmation, reminders, and paid workflows.
Also applies to: 442-449, 451-459, 659-665
| import prisma from "@calcom/prisma"; | ||
| import type { Prisma } from "@calcom/prisma/client"; |
There was a problem hiding this comment.
Fix prisma import (build blocker)
@calcom/prisma exports a named prisma. Default import will fail.
Apply this diff:
-import prisma from "@calcom/prisma";
+import { prisma } from "@calcom/prisma";🤖 Prompt for AI Agents
In packages/features/bookings/lib/handleBookingRequested.ts around lines 11 to
12, the file currently uses a default import from "@calcom/prisma" which fails
because the package exports a named prisma; replace the default import with the
named export (e.g., import { prisma } from "@calcom/prisma") and keep the Prisma
types import as-is or adjust to import type if needed so the code references the
exported named prisma instead of a default.
| //Workflows - set reminders for confirmed events | ||
| try { | ||
| if (workflows.length > 0) { | ||
| const _isFirstBooking = !recurringEvent || !recurringEvent.count; | ||
|
|
There was a problem hiding this comment.
Undefined identifier recurringEvent (compile error)
recurringEvent is not defined in this scope. You already compute _isFirstBooking per iteration. Remove the stray declaration.
- if (workflows.length > 0) {
- const _isFirstBooking = !recurringEvent || !recurringEvent.count;
+ if (workflows.length > 0) {🤖 Prompt for AI Agents
In packages/features/bookings/lib/handleConfirmation.ts around lines 418 to 421,
there is a reference to an undefined identifier `recurringEvent` when computing
_isFirstBooking; remove the stray `recurringEvent` usage and instead rely on the
per-iteration value already computed for _isFirstBooking (or compute it from the
current loop's recurring info). Edit the conditional to use existing variables
in scope (e.g., the iteration's recurring object or its count) so the compiler
error is resolved and no undefined identifier remains.
| team?: { | ||
| id: number; | ||
| name: string; | ||
| parentId?: number | null; | ||
| hideBranding?: boolean | null; | ||
| parent?: { hideBranding?: boolean | null } | null; | ||
| } | null; | ||
| owner?: { id: number; hideBranding?: boolean | null } | null; | ||
| }) |
There was a problem hiding this comment.
Critical type mismatch: eventType type is too broad.
The type declares EventType & { team?: ..., owner?: ... }, which implies all EventType fields are present. However, the actual select at lines 27–56 only fetches specific fields (id, title, teamId, hideOrganizerEmail, customReplyToEmail, seatsPerTimeSlot, seatsShowAttendees, recurringEvent). Code that accesses booking.eventType.someOtherField will compile but fail at runtime.
Replace the intersection with an explicit type matching the selected fields:
export type BookingsProcedureContext = {
booking: Booking & {
eventType:
- | (EventType & {
+ | ({
+ id: number;
+ title: string;
+ teamId: number | null;
+ hideOrganizerEmail: boolean;
+ customReplyToEmail: string | null;
+ seatsPerTimeSlot: number | null;
+ seatsShowAttendees: boolean | null;
+ recurringEvent: Prisma.JsonValue | null;
team?: {
id: number;
name: string;
parentId?: number | null;
hideBranding?: boolean | null;
parent?: { hideBranding?: boolean | null } | null;
} | null;
owner?: { id: number; hideBranding?: boolean | null } | null;
})
| null;📝 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.
| team?: { | |
| id: number; | |
| name: string; | |
| parentId?: number | null; | |
| hideBranding?: boolean | null; | |
| parent?: { hideBranding?: boolean | null } | null; | |
| } | null; | |
| owner?: { id: number; hideBranding?: boolean | null } | null; | |
| }) | |
| export type BookingsProcedureContext = { | |
| booking: Booking & { | |
| eventType: | |
| | ({ | |
| id: number; | |
| title: string; | |
| teamId: number | null; | |
| hideOrganizerEmail: boolean; | |
| customReplyToEmail: string | null; | |
| seatsPerTimeSlot: number | null; | |
| seatsShowAttendees: boolean | null; | |
| recurringEvent: Prisma.JsonValue | null; | |
| team?: { | |
| id: number; | |
| name: string; | |
| parentId?: number | null; | |
| hideBranding?: boolean | null; | |
| parent?: { hideBranding?: boolean | null } | null; | |
| } | null; | |
| owner?: { id: number; hideBranding?: boolean | null } | null; | |
| }) | |
| | null; | |
| }; | |
| }; |
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (1)
339-340: Use builder.withHideBranding when present.Prefer the builder API over direct property mutation.
- builder.calendarEvent.hideBranding = hideBranding; + if (typeof (builder as any).withHideBranding === "function") { + (builder as any).withHideBranding(hideBranding); + } else { + builder.calendarEvent.hideBranding = hideBranding; + }packages/app-store/vital/lib/reschedule.ts (1)
227-227: Use builder.withHideBranding when present.Prefer the builder API; fall back to direct assignment.
- builder.calendarEvent.hideBranding = hideBranding; + if (typeof (builder as any).withHideBranding === "function") { + (builder as any).withHideBranding(hideBranding); + } else { + builder.calendarEvent.hideBranding = hideBranding; + }
🧹 Nitpick comments (5)
packages/app-store/wipemycalother/lib/reschedule.ts (2)
37-63: Trim Prisma select to only needed fields (customReplyToEmail appears unused here).Drop unused fields to keep payload minimal.
As per coding guidelines
select: { id: true, teamId: true, parentId: true, metadata: true, hideOrganizerEmail: true, - customReplyToEmail: true, owner: { select: { id: true, hideBranding: true, }, },
227-227: Prefer builder API to set hideBranding if available.Use withHideBranding when present; fall back to direct assignment.
- builder.calendarEvent.hideBranding = hideBranding; + if (typeof (builder as any).withHideBranding === "function") { + (builder as any).withHideBranding(hideBranding); + } else { + builder.calendarEvent.hideBranding = hideBranding; + }packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (1)
297-312: Use existing helper to compute organizationId; avoid extra DB query.getOrgIdFromMemberOrTeamId is imported; prefer it over fetching profile.
As per coding guidelines
- // For user events, fetch the user's profile to get the organization ID - const userOrganizationId = !bookingToReschedule.eventType?.team - ? ( - await prisma.profile.findFirst({ - where: { - userId: bookingToReschedule.userId, - }, - select: { - organizationId: true, - }, - }) - )?.organizationId - : null; - - const computedOrgId = bookingToReschedule.eventType?.team?.parentId ?? userOrganizationId ?? null; + const computedOrgId = + bookingToReschedule.eventType?.team?.parentId ?? + (await getOrgIdFromMemberOrTeamId({ + memberId: bookingToReschedule.userId, + teamId: bookingToReschedule.eventType?.team?.id ?? null, + })) ?? + null;packages/app-store/vital/lib/reschedule.ts (2)
37-63: Trim Prisma select to only needed fields (customReplyToEmail appears unused here).Keep selects minimal.
As per coding guidelines
select: { id: true, teamId: true, parentId: true, metadata: true, hideOrganizerEmail: true, - customReplyToEmail: true, owner: { select: { id: true, hideBranding: true, }, },
201-225: Consider extracting a shared helper for branding computation.This logic repeats across modules; a util would reduce duplication and drift.
📜 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)
packages/app-store/vital/lib/reschedule.ts(3 hunks)packages/app-store/wipemycalother/lib/reschedule.ts(3 hunks)packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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:
packages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/app-store/vital/lib/reschedule.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:
packages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/app-store/vital/lib/reschedule.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:
packages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/app-store/vital/lib/reschedule.ts
🧠 Learnings (3)
📚 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:
packages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/app-store/vital/lib/reschedule.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:
packages/app-store/wipemycalother/lib/reschedule.tspackages/trpc/server/routers/viewer/bookings/requestReschedule.handler.tspackages/app-store/vital/lib/reschedule.ts
📚 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:
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts
🧬 Code graph analysis (3)
packages/app-store/wipemycalother/lib/reschedule.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
packages/app-store/vital/lib/reschedule.ts (1)
packages/lib/hideBranding.ts (1)
shouldHideBrandingForEvent(76-113)
⏰ 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 (4)
packages/app-store/wipemycalother/lib/reschedule.ts (2)
185-200: Org context derivation LGTM.Using team.parentId with user’s org fallback is correct for user events.
201-225: Branding decision logic and logged fallback look solid.Good inputs to shouldHideBrandingForEvent and sane fallback to owner.hideBranding with warn log.
packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts (1)
63-90: EventType select looks appropriate.Selected fields are used (bookingFields, hideOrganizerEmail, customReplyToEmail, metadata, branding flags).
packages/app-store/vital/lib/reschedule.ts (1)
185-200: Org context derivation LGTM.team.parentId with user org fallback is correct for user events.
What does this PR do?
Fixes: Cal.com branding disabled in settings: Cal.com branding still occurs in emails #23850
I ensure emails respect the "Disable Cal.com branding" setting by:
hideBranding?: booleantoCalendarEventhideBrandingwhen building/assembling events (new booking, confirm, payment, cancellation, reschedule)BaseScheduledEmailto hide the footer/logo whenhideBrandingis trueshouldHideBrandingForEventfunctioncanViewSensitiveBookingDataScope: Comprehensive branding control across all email flows and booking operations, plus merge conflict resolution.
Visual Demo
Screencast.From.2025-10-09.21-57-39.mp4
Before: Emails always showed Cal.com footer/logo regardless of the branding setting.
After: With branding disabled, emails render without Cal.com footer/logo; with branding enabled, footer/logo appears as usual.
Tip: Use MailHog to view emails in dev.
How should this be tested?
Environment:
EMAIL_SERVER_HOST=localhost,EMAIL_SERVER_PORT=1025E2E_TEST_MAILHOG_ENABLED=1Minimal data:
Steps:
Expected:
Additional Changes in This Update
hideBrandingvariable name conflictsMandatory Tasks (DO NOT REMOVE)
Checklist