Skip to content

feat: add toggle to disable recording download email for guests #22259

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Udit-takkar
Copy link
Contributor

@Udit-takkar Udit-takkar commented Jul 4, 2025

feat: add toggle to disable recording download email for guests

Fixes: https://linear.app/calcom/issue/CAL-4181/add-option-to-allow-disabling-recording-download-link-to-attendees

Summary

This PR adds a new toggle option "Disable recording download email for guests" to Cal Video settings in event types. When enabled, the system will skip sending recording download emails to attendees while still sending them to organizers.

Key Changes:

  • Added disableRecordingDownloadEmailForGuests field to CalVideoSettings database model
  • Created database migration for the new field
  • Added UI toggle in event type setup page alongside existing Cal Video options
  • Modified sendDailyVideoRecordingEmails function to conditionally skip attendee emails
  • Updated webhook handler to pass event type settings to email function
  • Added i18n translation and updated all TypeScript types/TRPC schemas

Pattern: Follows the established pattern from PR #21755 for transcription settings.

Review & Testing Checklist for Human

  • Database Migration Safety: Review the migration file to ensure it's safe for production deployment
  • Email Logic Correctness: Test end-to-end that when the toggle is enabled, attendee emails are skipped but organizer emails are still sent
  • UI Persistence: Verify the toggle saves correctly and persists across page reloads in the event type settings
  • Type Safety: Confirm TypeScript compilation passes and all type definitions are consistent
  • Full Flow Testing: Create a test event with Cal Video, enable the toggle, trigger a recording, and verify email behavior

Recommended Test Plan:

  1. Create/edit an event type with Cal Video location
  2. Enable the new "Disable recording download email for guests" toggle
  3. Save the event type and verify the setting persists
  4. Book a test meeting and generate a recording
  5. Verify organizer receives download email but attendees do not

Diagram

%%{ init : { "theme" : "default" }}%%
graph TD
    subgraph "Database Layer"
        Schema["packages/prisma/schema.prisma"]:::major-edit
        Migration["packages/prisma/migrations/..."]:::major-edit
    end
    
    subgraph "Repository Layer"
        CalVideoRepo["packages/lib/server/repository/calVideoSettings.ts"]:::major-edit
        EventTypeRepo["packages/lib/server/repository/eventType.ts"]:::minor-edit
        BookingRepo["packages/lib/server/repository/booking.ts"]:::minor-edit
    end
    
    subgraph "UI Layer"
        LocationsUI["packages/features/eventtypes/components/Locations.tsx"]:::major-edit
        i18n["apps/web/public/static/locales/en/common.json"]:::minor-edit
    end
    
    subgraph "Email System"
        EmailFunc["packages/emails/daily-video-emails.ts"]:::major-edit
        WebhookHandler["apps/web/app/api/recorded-daily-video/route.ts"]:::minor-edit
    end
    
    subgraph "Type System"
        TRPCTypes["packages/trpc/server/routers/viewer/eventTypes/types.ts"]:::minor-edit
        ZodSchemas["packages/prisma/zod/custom/eventtype.ts"]:::minor-edit
        EventTypeTypes["packages/features/eventtypes/lib/types.ts"]:::minor-edit
    end
    
    Schema --> CalVideoRepo
    CalVideoRepo --> LocationsUI
    LocationsUI --> EventTypeRepo
    EventTypeRepo --> WebhookHandler
    WebhookHandler --> EmailFunc
    
    subgraph Legend
        L1["Major Edit"]:::major-edit
        L2["Minor Edit"]:::minor-edit
        L3["Context/No Edit"]:::context
    end

classDef major-edit fill:#90EE90
classDef minor-edit fill:#87CEEB
classDef context fill:#FFFFFF
Loading

Notes

The implementation maintains backward compatibility and follows existing code patterns throughout the Cal.com codebase.

- Add disableRecordingDownloadEmailForGuests field to CalVideoSettings schema
- Update repository layer to handle new field with default false value
- Add UI toggle in event type setup page alongside other Cal Video settings
- Modify sendDailyVideoRecordingEmails to conditionally skip attendee emails
- Update webhook handler to pass calVideoSettings to email function
- Add i18n translation for new toggle option
- Update all TypeScript types and TRPC schemas
- Create database migration for new field

Follows pattern from PR #21755 for transcription settings.
Only attendee emails are skipped when enabled - organizer emails always sent.

Co-Authored-By: udit@cal.com <udit222001@gmail.com>
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@github-actions github-actions bot added the ❗️ migrations contains migration files label Jul 4, 2025
@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Jul 4, 2025
Copy link

vercel bot commented Jul 4, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
cal ⬜️ Ignored (Inspect) Jul 24, 2025 0:25am
cal-eu ⬜️ Ignored (Inspect) Jul 24, 2025 0:25am

Copy link

delve-auditor bot commented Jul 4, 2025

No security or compliance issues detected. Reviewed everything up to d30c996.

Security Overview
  • 🔎 Scanned files: 15 changed file(s)
Detected Code Changes
Change Type Relevant files
Enhancement ► route.ts
    Update webhook handler to include calVideoSettings
► getBooking.ts
    Add calVideoSettings to booking query
► daily-video-emails.ts
    Implement conditional email sending for guests
► Locations.tsx
    Add UI toggle for download email settings
► types.ts, schema.prisma
    Add new CalVideoSettings field
Configuration changes ► migration.sql
    Add disableRecordingDownloadEmailForGuests field
► common.json
    Add new translation string

Reply to this PR with @delve-auditor followed by a description of what change you want and we'll auto-submit a change to this PR to implement it.

Copy link
Contributor

This PR is being marked as stale due to inactivity.

@github-actions github-actions bot added the Stale label Jul 19, 2025
Copy link
Contributor

coderabbitai bot commented Jul 19, 2025

Walkthrough

This change introduces a new boolean setting, disableRecordingDownloadEmailForGuests, to the CalVideo settings across the application. The setting is added to the Prisma schema, database migration, server-side repositories, API handlers, and type definitions. The UI is updated to allow toggling this setting in the event type location settings. The email-sending logic for daily video recordings is updated to respect this flag, conditionally skipping download emails to guests if the setting is enabled. Additional related fields for transcription controls are also added in some backend schemas, though only the guest recording download email flag is fully integrated end-to-end.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15–20 minutes

  • Complexity: Moderate. The changes span schema, migration, backend, frontend, and email logic, but are focused on a single new setting with straightforward conditional logic and type propagation.
  • Reviewers should verify schema consistency, type propagation, UI integration, and the correct application of the new flag in email logic. No major refactors or high-complexity algorithms are introduced.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/web/app/api/recorded-daily-video/route.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

apps/web/lib/video/[uid]/getServerSideProps.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

packages/emails/daily-video-emails.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

  • 9 others

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/disable-guest-recording-emails-1751618469

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

- Merge disableRecordingDownloadEmailForGuests with enableAutomaticRecordingForOrganizer
- Use consistent .nullish() pattern in TypeScript schemas
- Maintain compatibility between both recording features

Co-Authored-By: udit@cal.com <udit222001@gmail.com>
@Udit-takkar Udit-takkar marked this pull request as ready for review July 24, 2025 12:27
@Udit-takkar Udit-takkar requested review from a team as code owners July 24, 2025 12:27
@Udit-takkar Udit-takkar added this to the v5.6 milestone Jul 24, 2025
@graphite-app graphite-app bot requested a review from a team July 24, 2025 12:27
@dosubot dosubot bot added the ✨ feature New feature or request label Jul 24, 2025
Copy link

graphite-app bot commented Jul 24, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (07/24/25)

1 reviewer was added to this PR based on Keith Williams's automation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (1)
packages/lib/server/repository/calVideoSettings.ts (1)

15-23: Missing field in createCalVideoSettings method.

The createCalVideoSettings method doesn't include the new disableRecordingDownloadEmailForGuests field in its type definition or implementation, while createOrUpdateCalVideoSettings does. This inconsistency could lead to issues if the create method is used elsewhere.

Consider adding the field to maintain consistency:

 calVideoSettings: {
   disableRecordingForGuests?: boolean | null;
   disableRecordingForOrganizer?: boolean | null;
+  disableRecordingDownloadEmailForGuests?: boolean | null;
   enableAutomaticTranscription?: boolean | null;
   enableAutomaticRecordingForOrganizer?: boolean | null;
   disableTranscriptionForGuests?: boolean | null;
   disableTranscriptionForOrganizer?: boolean | null;
   redirectUrlOnExit?: string | null;
 };

And in the create data object:

 data: {
   disableRecordingForGuests: calVideoSettings.disableRecordingForGuests ?? false,
   disableRecordingForOrganizer: calVideoSettings.disableRecordingForOrganizer ?? false,
+  disableRecordingDownloadEmailForGuests: calVideoSettings.disableRecordingDownloadEmailForGuests ?? false,
   enableAutomaticTranscription: calVideoSettings.enableAutomaticTranscription ?? false,
   enableAutomaticRecordingForOrganizer: calVideoSettings.enableAutomaticRecordingForOrganizer ?? false,
   disableTranscriptionForGuests: calVideoSettings.disableTranscriptionForGuests ?? false,
   disableTranscriptionForOrganizer: calVideoSettings.disableTranscriptionForOrganizer ?? false,
   redirectUrlOnExit: calVideoSettings.redirectUrlOnExit ?? null,
   eventTypeId,
 },
🧹 Nitpick comments (3)
packages/prisma/migrations/20250704084455_add_disable_recording_download_email_for_guests/migration.sql (1)

2-2: Consider using nullable Boolean field to align with team preferences.

While this migration is technically correct and uses a default value to avoid updating existing rows, the retrieved learning suggests Cal.com prefers nullable Boolean fields (Boolean?) with defaults rather than non-nullable fields (Boolean NOT NULL) to avoid expensive database migrations.

Consider this alternative approach:

-ALTER TABLE "CalVideoSettings" ADD COLUMN     "disableRecordingDownloadEmailForGuests" BOOLEAN NOT NULL DEFAULT false;
+ALTER TABLE "CalVideoSettings" ADD COLUMN     "disableRecordingDownloadEmailForGuests" BOOLEAN DEFAULT false;

This would align with the team's established pattern while maintaining the same functionality.

packages/prisma/schema.prisma (1)

79-79: Consider using nullable Boolean field to follow Cal.com's schema design patterns.

Based on the retrieved learnings, Cal.com typically prefers nullable Boolean fields (Boolean?) with defaults rather than non-nullable (Boolean) to avoid expensive database migrations that would update existing rows. Consider changing this to:

-  disableRecordingDownloadEmailForGuests Boolean  @default(false)
+  disableRecordingDownloadEmailForGuests Boolean? @default(false)

This approach aligns with the team's established pattern for Boolean schema fields.

packages/features/eventtypes/components/Locations.tsx (1)

399-412: Consider adding UpgradeTeamsBadge for consistency.

The new toggle follows the correct pattern but is missing the UpgradeTeamsBadge component that other recording-related toggles have (lines 359, 375, 392). This inconsistency might confuse users about feature availability.

Apply this diff to maintain consistency:

                            <SettingsToggle
                              title={t("disable_recording_download_email_for_guests")}
                              labelClassName="text-sm"
                              checked={value}
                              onCheckedChange={onChange}
+                             Badge={<UpgradeTeamsBadge checkForActiveStatus />}
                            />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ab6767 and 1cfbf2e.

📒 Files selected for processing (16)
  • apps/web/app/api/recorded-daily-video/route.ts (1 hunks)
  • apps/web/lib/daily-webhook/getBooking.ts (1 hunks)
  • apps/web/lib/video/[uid]/getServerSideProps.ts (1 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • packages/emails/daily-video-emails.ts (1 hunks)
  • packages/features/eventtypes/components/Locations.tsx (1 hunks)
  • packages/features/eventtypes/lib/types.ts (1 hunks)
  • packages/features/schedules/components/Schedule.tsx (0 hunks)
  • packages/lib/server/repository/booking.ts (1 hunks)
  • packages/lib/server/repository/calVideoSettings.ts (3 hunks)
  • packages/lib/server/repository/eventTypeRepository.ts (1 hunks)
  • packages/prisma/migrations/20250704084455_add_disable_recording_download_email_for_guests/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
  • packages/prisma/zod/custom/eventtype.ts (1 hunks)
  • packages/trpc/server/routers/viewer/eventTypes/create.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/eventTypes/types.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/features/schedules/components/Schedule.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code. Functions like .add, .diff, .isBefore, and .isAfter are slow, especially in timezone mode. Prefer .utc() for better performance. Where possible, replace with native Date and direct .valueOf() comparisons for faster execution. Recommend using native methods or Day.js .utc() consistently in hot paths like loops.

Files:

  • apps/web/lib/video/[uid]/getServerSideProps.ts
  • packages/features/eventtypes/lib/types.ts
  • apps/web/app/api/recorded-daily-video/route.ts
  • packages/lib/server/repository/eventTypeRepository.ts
  • packages/prisma/zod/custom/eventtype.ts
  • packages/lib/server/repository/booking.ts
  • apps/web/lib/daily-webhook/getBooking.ts
  • packages/lib/server/repository/calVideoSettings.ts
  • packages/trpc/server/routers/viewer/eventTypes/create.handler.ts
  • packages/features/eventtypes/components/Locations.tsx
  • packages/trpc/server/routers/viewer/eventTypes/types.ts
  • packages/emails/daily-video-emails.ts
🧠 Learnings (5)
packages/prisma/migrations/20250704084455_add_disable_recording_download_email_for_guests/migration.sql (1)

Learnt from: vijayraghav-io
PR: #16579
File: packages/prisma/schema.prisma:149-153
Timestamp: 2025-07-16T07:14:49.248Z
Learning: In Cal.com's schema design, the team prefers to keep Boolean fields nullable (Boolean?) with defaults rather than making them non-nullable (Boolean) to avoid expensive database migrations that would update existing rows.

apps/web/lib/daily-webhook/getBooking.ts (3)

Learnt from: eunjae-lee
PR: #22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.

Learnt from: CR
PR: calcom/cal.com#0
File: .cursor/rules/review.mdc:0-0
Timestamp: 2025-07-21T13:54:11.770Z
Learning: Applies to backend/**/*.{ts,tsx} : For Prisma queries: Select selects only the fields you specify explicitly.

Learnt from: vijayraghav-io
PR: #21072
File: packages/app-store/office365calendar/api/webhook.ts:120-123
Timestamp: 2025-07-18T17:57:16.395Z
Learning: The office365calendar webhook handler in packages/app-store/office365calendar/api/webhook.ts is specifically designed for Office365 calendar integration, not as a generic webhook handler. Therefore, it's safe to assume that fetchAvailabilityAndSetCache method will be implemented in the Office365CalendarService, making explicit validation checks unnecessary.

packages/features/eventtypes/components/Locations.tsx (2)

Learnt from: alishaz-polymath
PR: #22304
File: packages/features/eventtypes/components/MultiplePrivateLinksController.tsx:92-94
Timestamp: 2025-07-16T06:42:27.024Z
Learning: In the MultiplePrivateLinksController component (packages/features/eventtypes/components/MultiplePrivateLinksController.tsx), the currentLink.maxUsageCount ?? 1 fallback in the openSettingsDialog function is intentional. Missing maxUsageCount values indicate old/legacy private links that existed before the expiration feature was added, and they should default to single-use behavior (1) for backward compatibility.

Learnt from: Anshumancanrock
PR: #22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.343Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.

packages/prisma/schema.prisma (3)

Learnt from: vijayraghav-io
PR: #16579
File: packages/prisma/schema.prisma:149-153
Timestamp: 2025-07-16T07:14:49.248Z
Learning: In Cal.com's schema design, the team prefers to keep Boolean fields nullable (Boolean?) with defaults rather than making them non-nullable (Boolean) to avoid expensive database migrations that would update existing rows.

Learnt from: vijayraghav-io
PR: #21072
File: packages/prisma/schema.prisma:891-891
Timestamp: 2025-07-18T08:47:01.264Z
Learning: In Cal.com's calendar integration, both Google Calendar and Outlook Calendar are designed to allow multiple eventTypeIds to share the same subscription ID (googleChannelId or outlookSubscriptionId). This is an intentional design pattern to reuse existing subscriptions for efficiency rather than creating separate subscriptions for each event type. Therefore, unique constraints like @@unique([outlookSubscriptionId, eventTypeId]) should not be added as they would break this subscription sharing functionality.

Learnt from: vijayraghav-io
PR: #21072
File: packages/prisma/schema.prisma:891-891
Timestamp: 2025-07-18T08:47:01.264Z
Learning: The Outlook Calendar integration in Cal.com intentionally reuses subscription IDs across multiple event types for efficiency. The upsertSelectedCalendarsForEventTypeIds method creates separate SelectedCalendar records for each eventTypeId, all sharing the same outlookSubscriptionId. This subscription sharing pattern means that unique constraints like @@unique([outlookSubscriptionId, eventTypeId]) should not be applied as they would prevent this intended functionality.

apps/web/public/static/locales/en/common.json (1)

Learnt from: bandhan-majumder
PR: #22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.233Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.

🧬 Code Graph Analysis (2)
apps/web/app/api/recorded-daily-video/route.ts (1)
packages/emails/daily-video-emails.ts (1)
  • sendDailyVideoRecordingEmails (35-55)
packages/features/eventtypes/components/Locations.tsx (1)
packages/ui/components/form/switch/SettingsToggle.tsx (1)
  • SettingsToggle (29-125)
🔇 Additional comments (15)
apps/web/public/static/locales/en/common.json (1)

50-50: Ensure new key is replicated in all locale files

The English entry looks good and the key name is consistent with the TypeScript flag disableRecordingDownloadEmailForGuests.
To avoid runtime fall-back to English, remember to add the same key (even if just as an empty or copied value) to every other common.json locale under public/static/locales/<lang>/.
Failing to do so will surface untranslated strings in non-EN environments.

apps/web/lib/video/[uid]/getServerSideProps.ts (1)

25-25: LGTM! Type definition follows established patterns.

The addition of disableRecordingDownloadEmailForGuests: boolean is consistent with the existing CalVideoSettings interface structure and naming conventions.

apps/web/lib/daily-webhook/getBooking.ts (1)

26-26: LGTM! Necessary change to support the new email setting.

Adding calVideoSettings: true to the select clause enables fetching the complete CalVideoSettings object, including the new disableRecordingDownloadEmailForGuests field that will be used in the email sending logic.

apps/web/app/api/recorded-daily-video/route.ts (1)

140-140: LGTM! Correct integration of calVideoSettings into email workflow.

The addition of booking.eventType?.calVideoSettings as the third parameter correctly passes the video settings (including the new disableRecordingDownloadEmailForGuests flag) to the email function. The optional chaining handles potential null values appropriately.

packages/lib/server/repository/eventTypeRepository.ts (1)

711-711: LGTM! Correctly extends calVideoSettings selection.

The addition of disableRecordingDownloadEmailForGuests: true to the calVideoSettings select clause ensures the new field is included when fetching complete event type data. The placement and formatting are consistent with existing fields.

packages/features/eventtypes/lib/types.ts (1)

161-161: LGTM! Type definition correctly added.

The new disableRecordingDownloadEmailForGuests property is properly typed as an optional boolean and correctly positioned within the calVideoSettings object alongside related recording settings.

packages/trpc/server/routers/viewer/eventTypes/types.ts (1)

34-34: LGTM! Schema validation properly added.

The new disableRecordingDownloadEmailForGuests field is correctly defined with z.boolean().nullish(), maintaining consistency with other optional boolean fields in the calVideoSettingsSchema.

packages/lib/server/repository/booking.ts (1)

400-400: LGTM! Database field selection properly added.

The new disableRecordingDownloadEmailForGuests field is correctly added to the select statement within the calVideoSettings selection, enabling the booking repository to fetch this setting for meeting page functionality.

packages/prisma/zod/custom/eventtype.ts (1)

12-15: LGTM! Schema extensions properly implemented.

The new fields are correctly defined with z.boolean().optional().nullable(), maintaining consistency with the existing schema pattern. Note that this includes transcription-related fields (enableAutomaticTranscription, disableTranscriptionForGuests, disableTranscriptionForOrganizer) in addition to the main PR focus of disableRecordingDownloadEmailForGuests.

packages/prisma/schema.prisma (1)

75-84: Good field placement and consistent formatting.

The new field is logically positioned among other recording-related settings, and the indentation adjustments maintain consistency across the model definition.

packages/lib/server/repository/calVideoSettings.ts (2)

47-47: Type definition looks good.

The new optional field follows the established pattern with proper nullable boolean type definition.


60-61: Consistent implementation in upsert operation.

The new field is properly handled in both update and create branches with appropriate default fallback using nullish coalescing.

Also applies to: 72-73

packages/emails/daily-video-emails.ts (2)

35-39: Well-implemented function signature update.

The optional parameter with proper typing maintains backward compatibility while enabling the new functionality.


47-53: Correct conditional email logic implementation.

The logic properly preserves organizer emails while conditionally skipping attendee emails based on the flag. The optional chaining ensures safe property access and maintains backward compatibility.

packages/trpc/server/routers/viewer/eventTypes/create.handler.ts (1)

74-78: Consistent implementation of new CalVideo settings.

The new properties follow the established pattern with proper null coalescing defaults and maintain type safety. The addition of transcription-related properties alongside the recording email setting aligns with the PR's broader video settings enhancements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/prisma/migrations/20250704084455_add_disable_recording_download_email_for_guests/migration.sql (1)

2-2: Consider using nullable Boolean for consistency with team preferences.

Based on previous team discussions, Cal.com prefers using nullable Boolean fields (Boolean?) with defaults rather than non-nullable (Boolean) to avoid expensive database migrations. While this specific migration adds a new column with a default (which shouldn't require updating existing rows), consider using BOOLEAN DEFAULT false without NOT NULL for consistency with established patterns.

-ALTER TABLE "CalVideoSettings" ADD COLUMN     "disableRecordingDownloadEmailForGuests" BOOLEAN NOT NULL DEFAULT false;
+ALTER TABLE "CalVideoSettings" ADD COLUMN     "disableRecordingDownloadEmailForGuests" BOOLEAN DEFAULT false;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ab6767 and 1cfbf2e.

📒 Files selected for processing (16)
  • apps/web/app/api/recorded-daily-video/route.ts (1 hunks)
  • apps/web/lib/daily-webhook/getBooking.ts (1 hunks)
  • apps/web/lib/video/[uid]/getServerSideProps.ts (1 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • packages/emails/daily-video-emails.ts (1 hunks)
  • packages/features/eventtypes/components/Locations.tsx (1 hunks)
  • packages/features/eventtypes/lib/types.ts (1 hunks)
  • packages/features/schedules/components/Schedule.tsx (0 hunks)
  • packages/lib/server/repository/booking.ts (1 hunks)
  • packages/lib/server/repository/calVideoSettings.ts (3 hunks)
  • packages/lib/server/repository/eventTypeRepository.ts (1 hunks)
  • packages/prisma/migrations/20250704084455_add_disable_recording_download_email_for_guests/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
  • packages/prisma/zod/custom/eventtype.ts (1 hunks)
  • packages/trpc/server/routers/viewer/eventTypes/create.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/eventTypes/types.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/features/schedules/components/Schedule.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code. Functions like .add, .diff, .isBefore, and .isAfter are slow, especially in timezone mode. Prefer .utc() for better performance. Where possible, replace with native Date and direct .valueOf() comparisons for faster execution. Recommend using native methods or Day.js .utc() consistently in hot paths like loops.

Files:

  • apps/web/lib/daily-webhook/getBooking.ts
  • packages/lib/server/repository/eventTypeRepository.ts
  • packages/prisma/zod/custom/eventtype.ts
  • packages/trpc/server/routers/viewer/eventTypes/types.ts
  • packages/lib/server/repository/calVideoSettings.ts
  • apps/web/app/api/recorded-daily-video/route.ts
  • packages/features/eventtypes/components/Locations.tsx
  • packages/lib/server/repository/booking.ts
  • packages/trpc/server/routers/viewer/eventTypes/create.handler.ts
  • apps/web/lib/video/[uid]/getServerSideProps.ts
  • packages/emails/daily-video-emails.ts
  • packages/features/eventtypes/lib/types.ts
🧠 Learnings (5)
packages/prisma/migrations/20250704084455_add_disable_recording_download_email_for_guests/migration.sql (1)

Learnt from: vijayraghav-io
PR: #16579
File: packages/prisma/schema.prisma:149-153
Timestamp: 2025-07-16T07:14:49.248Z
Learning: In Cal.com's schema design, the team prefers to keep Boolean fields nullable (Boolean?) with defaults rather than making them non-nullable (Boolean) to avoid expensive database migrations that would update existing rows.

apps/web/public/static/locales/en/common.json (1)

Learnt from: bandhan-majumder
PR: #22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.233Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.

apps/web/lib/daily-webhook/getBooking.ts (3)

Learnt from: CR
PR: calcom/cal.com#0
File: .cursor/rules/review.mdc:0-0
Timestamp: 2025-07-21T13:54:11.770Z
Learning: Applies to backend/**/*.{ts,tsx} : For Prisma queries: Select selects only the fields you specify explicitly.

Learnt from: vijayraghav-io
PR: #21072
File: packages/app-store/office365calendar/api/webhook.ts:120-123
Timestamp: 2025-07-18T17:57:16.395Z
Learning: The office365calendar webhook handler in packages/app-store/office365calendar/api/webhook.ts is specifically designed for Office365 calendar integration, not as a generic webhook handler. Therefore, it's safe to assume that fetchAvailabilityAndSetCache method will be implemented in the Office365CalendarService, making explicit validation checks unnecessary.

Learnt from: eunjae-lee
PR: #22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.

packages/prisma/schema.prisma (3)

Learnt from: vijayraghav-io
PR: #16579
File: packages/prisma/schema.prisma:149-153
Timestamp: 2025-07-16T07:14:49.248Z
Learning: In Cal.com's schema design, the team prefers to keep Boolean fields nullable (Boolean?) with defaults rather than making them non-nullable (Boolean) to avoid expensive database migrations that would update existing rows.

Learnt from: vijayraghav-io
PR: #21072
File: packages/prisma/schema.prisma:891-891
Timestamp: 2025-07-18T08:47:01.264Z
Learning: In Cal.com's calendar integration, both Google Calendar and Outlook Calendar are designed to allow multiple eventTypeIds to share the same subscription ID (googleChannelId or outlookSubscriptionId). This is an intentional design pattern to reuse existing subscriptions for efficiency rather than creating separate subscriptions for each event type. Therefore, unique constraints like @@unique([outlookSubscriptionId, eventTypeId]) should not be added as they would break this subscription sharing functionality.

Learnt from: vijayraghav-io
PR: #21072
File: packages/prisma/schema.prisma:891-891
Timestamp: 2025-07-18T08:47:01.264Z
Learning: The Outlook Calendar integration in Cal.com intentionally reuses subscription IDs across multiple event types for efficiency. The upsertSelectedCalendarsForEventTypeIds method creates separate SelectedCalendar records for each eventTypeId, all sharing the same outlookSubscriptionId. This subscription sharing pattern means that unique constraints like @@unique([outlookSubscriptionId, eventTypeId]) should not be applied as they would prevent this intended functionality.

packages/features/eventtypes/components/Locations.tsx (2)

Learnt from: alishaz-polymath
PR: #22304
File: packages/features/eventtypes/components/MultiplePrivateLinksController.tsx:92-94
Timestamp: 2025-07-16T06:42:27.024Z
Learning: In the MultiplePrivateLinksController component (packages/features/eventtypes/components/MultiplePrivateLinksController.tsx), the currentLink.maxUsageCount ?? 1 fallback in the openSettingsDialog function is intentional. Missing maxUsageCount values indicate old/legacy private links that existed before the expiration feature was added, and they should default to single-use behavior (1) for backward compatibility.

Learnt from: Anshumancanrock
PR: #22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.343Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.

🧬 Code Graph Analysis (1)
apps/web/app/api/recorded-daily-video/route.ts (1)
packages/emails/daily-video-emails.ts (1)
  • sendDailyVideoRecordingEmails (35-55)
⏰ Context from checks skipped due to timeout of 90000ms. 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 (15)
apps/web/public/static/locales/en/common.json (1)

50-50: Key addition looks good and consistent

The new disable_recording_download_email_for_guests key follows existing naming conventions (snake_case) and sits logically next to related Cal Video toggles. No collisions or typos detected.

apps/web/lib/video/[uid]/getServerSideProps.ts (1)

25-25: LGTM! Type definition correctly extended.

The addition of disableRecordingDownloadEmailForGuests to the CalVideoSettings type is consistent with the other boolean properties and aligns with the broader feature implementation.

apps/web/lib/daily-webhook/getBooking.ts (1)

26-26: LGTM! Necessary field addition for downstream functionality.

Adding calVideoSettings: true to the selection ensures the new disableRecordingDownloadEmailForGuests flag is available for the email sending logic downstream. The change follows the established query pattern.

packages/lib/server/repository/booking.ts (1)

400-400: LGTM! Consistent field addition to calVideoSettings selection.

The addition of disableRecordingDownloadEmailForGuests: true follows the established pattern of other boolean fields in the calVideoSettings selection block and ensures the new field is available when booking data is retrieved for meeting pages.

packages/prisma/schema.prisma (1)

79-79: LGTM! New field follows existing patterns.

The new disableRecordingDownloadEmailForGuests field is well-positioned alongside other recording-related settings and follows the existing naming convention and type pattern within the CalVideoSettings model. The default value of false ensures backward compatibility.

packages/features/eventtypes/lib/types.ts (1)

161-161: LGTM! Type definition is consistent and well-structured.

The new optional property disableRecordingDownloadEmailForGuests is appropriately positioned within the calVideoSettings object, follows the existing naming convention, and maintains consistency with the corresponding Prisma schema field.

packages/lib/server/repository/eventTypeRepository.ts (1)

711-711: LGTM! Field addition follows established pattern.

The new disableRecordingDownloadEmailForGuests field is correctly added to the calVideoSettings selection, maintaining consistency with other recording-related settings.

packages/trpc/server/routers/viewer/eventTypes/types.ts (1)

34-34: LGTM! Schema extension is properly implemented.

The new field uses the appropriate .nullish() modifier, maintaining consistency with other boolean settings in the calVideoSettingsSchema.

packages/trpc/server/routers/viewer/eventTypes/create.handler.ts (1)

74-78: LGTM! Default values are properly handled.

The implementation correctly uses nullish coalescing (?? false) to provide sensible defaults. The conditional creation within the CalVideo location check is appropriate.

Note: Ensure the transcription-related fields (enableAutomaticTranscription, disableTranscriptionForGuests, disableTranscriptionForOrganizer) are fully utilized in the email logic, as the PR description suggests only disableRecordingDownloadEmailForGuests has complete end-to-end integration.

apps/web/app/api/recorded-daily-video/route.ts (1)

140-140: LGTM! Correctly integrates the new calVideoSettings parameter.

The addition of booking.eventType?.calVideoSettings as the third parameter enables the email function to respect the disableRecordingDownloadEmailForGuests setting. The optional chaining handles potential null/undefined values appropriately.

packages/lib/server/repository/calVideoSettings.ts (2)

47-47: Property addition follows established pattern correctly.

The new disableRecordingDownloadEmailForGuests property is properly typed as optional boolean | null, consistent with other CalVideo settings in the interface.


60-61: Implementation correctly handles both update and create paths.

The property is properly added to both the update and create objects in the upsert operation, with appropriate default fallback to false. The implementation is consistent with existing boolean properties.

Also applies to: 72-73

packages/features/eventtypes/components/Locations.tsx (1)

399-412: UI toggle implementation follows established patterns correctly.

The new toggle for disabling recording download emails for guests is properly integrated using the Controller pattern, with consistent styling and form binding. The implementation matches other CalVideo settings toggles in structure and behavior.

packages/emails/daily-video-emails.ts (2)

35-39: Function signature correctly adds optional settings parameter.

The addition of the optional calVideoSettings parameter maintains backward compatibility while providing the necessary configuration for conditional email sending behavior.


47-53: Conditional email logic correctly implements the feature requirement.

The implementation properly checks the flag using optional chaining and only skips attendee emails when explicitly disabled, while maintaining backward compatibility and always sending organizer emails.

Comment on lines +12 to +15
disableRecordingDownloadEmailForGuests: z.boolean().optional().nullable(),
enableAutomaticTranscription: z.boolean().optional().nullable(),
disableTranscriptionForGuests: z.boolean().optional().nullable(),
disableTranscriptionForOrganizer: z.boolean().optional().nullable(),
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider consistency in nullish field definitions and verify transcription field integration.

Two observations:

  1. Pattern inconsistency: These fields use .optional().nullable() while the same fields in types.ts use .nullish(). Consider using .nullish() consistently as it's more concise and the preferred Zod pattern.

  2. Incomplete integration concern: The AI summary suggests only disableRecordingDownloadEmailForGuests is fully integrated end-to-end. If the transcription fields (enableAutomaticTranscription, disableTranscriptionForGuests, disableTranscriptionForOrganizer) are not fully implemented, consider either completing their integration or documenting them as future work to avoid confusion.

-    disableRecordingDownloadEmailForGuests: z.boolean().optional().nullable(),
-    enableAutomaticTranscription: z.boolean().optional().nullable(),
-    disableTranscriptionForGuests: z.boolean().optional().nullable(),
-    disableTranscriptionForOrganizer: z.boolean().optional().nullable(),
+    disableRecordingDownloadEmailForGuests: z.boolean().nullish(),
+    enableAutomaticTranscription: z.boolean().nullish(),
+    disableTranscriptionForGuests: z.boolean().nullish(),
+    disableTranscriptionForOrganizer: z.boolean().nullish(),

🏁 Script executed:

#!/bin/bash
echo "=== Checking .nullish() usage in packages/prisma schema files ==="
rg "z\.boolean\(\)\.nullish" -n packages/prisma

echo ""
echo "=== Scanning occurrences of the new fields across the repository ==="
for field in disableRecordingDownloadEmailForGuests enableAutomaticTranscription disableTranscriptionForGuests disableTranscriptionForOrganizer; do
  echo ""
  echo ">>> Occurrences of '$field':"
  rg "$field" -n
done

Length of output: 15245


Ensure consistent use of .nullish() in Zod schema

All four new boolean fields in packages/prisma/zod/custom/eventtype.ts currently use .optional().nullable(). Replace these with the more concise and preferred .nullish() shorthand to align with other Zod type definitions in the codebase.

• File: packages/prisma/zod/custom/eventtype.ts
Lines 12–15:

-    disableRecordingDownloadEmailForGuests: z.boolean().optional().nullable(),
-    enableAutomaticTranscription:            z.boolean().optional().nullable(),
-    disableTranscriptionForGuests:           z.boolean().optional().nullable(),
-    disableTranscriptionForOrganizer:        z.boolean().optional().nullable(),
+    disableRecordingDownloadEmailForGuests: z.boolean().nullish(),
+    enableAutomaticTranscription:            z.boolean().nullish(),
+    disableTranscriptionForGuests:           z.boolean().nullish(),
+    disableTranscriptionForOrganizer:        z.boolean().nullish(),
📝 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.

Suggested change
disableRecordingDownloadEmailForGuests: z.boolean().optional().nullable(),
enableAutomaticTranscription: z.boolean().optional().nullable(),
disableTranscriptionForGuests: z.boolean().optional().nullable(),
disableTranscriptionForOrganizer: z.boolean().optional().nullable(),
disableRecordingDownloadEmailForGuests: z.boolean().nullish(),
enableAutomaticTranscription: z.boolean().nullish(),
disableTranscriptionForGuests: z.boolean().nullish(),
disableTranscriptionForOrganizer: z.boolean().nullish(),
🤖 Prompt for AI Agents
In packages/prisma/zod/custom/eventtype.ts at lines 12 to 15, replace the use of
.optional().nullable() on the four boolean fields with the more concise
.nullish() method to ensure consistency with other Zod schema definitions in the
codebase.

Copy link
Contributor

@joeauyeung joeauyeung left a comment

Choose a reason for hiding this comment

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

Heads up when toggling this option it isn't saving to the CalVideoSettings table

@Udit-takkar Udit-takkar marked this pull request as draft August 5, 2025 08:38
Copy link

linear bot commented Aug 8, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO ✨ feature New feature or request ❗️ migrations contains migration files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants