Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion apps/web/app/api/recorded-daily-video/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,22 @@ export async function postHandler(request: NextRequest) {
log.error("Failed to Submit Transcription Batch Processor Job:", safeStringify(err));
}

// Get Cal Video settings to check if recording emails for guests are disabled
const calVideoSettings = await prisma.calVideoSettings.findUnique({
where: {
eventTypeId: booking.eventTypeId,
},
Comment on lines +140 to +143
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix TypeScript error: Handle null eventTypeId.

The pipeline failure indicates that booking.eventTypeId can be null, but the Prisma query expects a number. This will cause a runtime error.

Apply this fix to handle the null case:

+      if (!booking.eventTypeId) {
+        // If no eventTypeId, default to false (send emails to guests)
+        await sendDailyVideoRecordingEmails(evt, downloadLink, false);
+        return NextResponse.json({ message: "Success" });
+      }
+
       // Get Cal Video settings to check if recording emails for guests are disabled
       const calVideoSettings = await prisma.calVideoSettings.findUnique({
         where: {
           eventTypeId: booking.eventTypeId,
         },
📝 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
const calVideoSettings = await prisma.calVideoSettings.findUnique({
where: {
eventTypeId: booking.eventTypeId,
},
if (!booking.eventTypeId) {
// If no eventTypeId, default to false (send emails to guests)
await sendDailyVideoRecordingEmails(evt, downloadLink, false);
return NextResponse.json({ message: "Success" });
}
// Get Cal Video settings to check if recording emails for guests are disabled
const calVideoSettings = await prisma.calVideoSettings.findUnique({
where: {
eventTypeId: booking.eventTypeId,
},
🧰 Tools
🪛 GitHub Actions: PR Update

[error] 142-142: TypeScript error TS2322: Type 'number | null' is not assignable to type 'number | undefined'. Type 'null' is not assignable to type 'number | undefined' for property 'eventTypeId'.

🤖 Prompt for AI Agents
In apps/web/app/api/recorded-daily-video/route.ts around lines 140 to 143, the
Prisma query uses booking.eventTypeId which can be null, causing a TypeScript
error and potential runtime issue. Fix this by adding a check before the query
to ensure booking.eventTypeId is not null; if it is null, handle that case
appropriately (e.g., skip the query or return early). This prevents passing null
to the Prisma where clause expecting a number.

select: {
disableRecordingEmailsForGuests: true,
},
});

// send emails to all attendees only when user has team plan
await sendDailyVideoRecordingEmails(evt, downloadLink);
await sendDailyVideoRecordingEmails(
evt,
downloadLink,
calVideoSettings?.disableRecordingEmailsForGuests ?? false
);

return NextResponse.json({ message: "Success" });
} else if (body.type === "meeting.ended") {
Expand Down
18 changes: 13 additions & 5 deletions packages/emails/daily-video-emails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,26 @@ export const sendDailyVideoTranscriptEmails = async (calEvent: CalendarEvent, tr
await Promise.all(emailsToSend);
};

export const sendDailyVideoRecordingEmails = async (calEvent: CalendarEvent, downloadLink: string) => {
export const sendDailyVideoRecordingEmails = async (
calEvent: CalendarEvent,
downloadLink: string,
disableRecordingEmailsForGuests = false
) => {
const calendarEvent = formatCalEvent(calEvent);
const emailsToSend: Promise<unknown>[] = [];

// Always send to organizer
emailsToSend.push(
sendEmail(() => new OrganizerDailyVideoDownloadRecordingEmail(calendarEvent, downloadLink))
);

for (const attendee of calendarEvent.attendees) {
emailsToSend.push(
sendEmail(() => new AttendeeDailyVideoDownloadRecordingEmail(calendarEvent, attendee, downloadLink))
);
// Only send to attendees if not disabled
if (!disableRecordingEmailsForGuests) {
for (const attendee of calendarEvent.attendees) {
emailsToSend.push(
sendEmail(() => new AttendeeDailyVideoDownloadRecordingEmail(calendarEvent, attendee, downloadLink))
);
}
}
await Promise.all(emailsToSend);
};
18 changes: 13 additions & 5 deletions packages/emails/email-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -728,18 +728,26 @@ export const sendNoShowFeeChargedEmail = async (
await sendEmail(() => new NoShowFeeChargedEmail(evt, attendee));
};

export const sendDailyVideoRecordingEmails = async (calEvent: CalendarEvent, downloadLink: string) => {
export const sendDailyVideoRecordingEmails = async (
calEvent: CalendarEvent,
downloadLink: string,
disableRecordingEmailsForGuests = false
) => {
const calendarEvent = formatCalEvent(calEvent);
const emailsToSend: Promise<unknown>[] = [];

// Always send to organizer
emailsToSend.push(
sendEmail(() => new OrganizerDailyVideoDownloadRecordingEmail(calendarEvent, downloadLink))
);

for (const attendee of calendarEvent.attendees) {
emailsToSend.push(
sendEmail(() => new AttendeeDailyVideoDownloadRecordingEmail(calendarEvent, attendee, downloadLink))
);
// Only send to attendees if not disabled
if (!disableRecordingEmailsForGuests) {
for (const attendee of calendarEvent.attendees) {
emailsToSend.push(
sendEmail(() => new AttendeeDailyVideoDownloadRecordingEmail(calendarEvent, attendee, downloadLink))
);
}
}
await Promise.all(emailsToSend);
};
Expand Down
15 changes: 15 additions & 0 deletions packages/features/eventtypes/components/Locations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,21 @@ const Locations: React.FC<LocationsProps> = ({
/>
)}

<Controller
name="calVideoSettings.disableRecordingEmailsForGuests"
defaultValue={!!eventType.calVideoSettings?.disableRecordingEmailsForGuests}
render={({ field: { onChange, value } }) => {
return (
<SettingsToggle
title={t("disable_recording_emails_for_guests")}
labelClassName="text-sm leading-6 whitespace-normal break-words"
checked={value}
onCheckedChange={onChange}
/>
);
}}
/>
Comment on lines +426 to +439
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Good implementation pattern but fix TypeScript error.

The new toggle follows the established pattern of other CalVideo settings toggles and correctly uses t() for localization as required by the coding guidelines.

However, the pipeline failure indicates a TypeScript error where disableRecordingEmailsForGuests doesn't exist on the calVideoSettings type.

Ensure that the FormValues type in packages/features/eventtypes/lib/types.ts includes this new property in the calVideoSettings interface, or verify that all related type definitions have been updated consistently across the codebase.

🧰 Tools
🪛 GitHub Actions: PR Update

[error] 428-428: TypeScript error TS2551: Property 'disableRecordingEmailsForGuests' does not exist on type of 'calVideoSettings'. Did you mean 'disableRecordingForGuests'?

🤖 Prompt for AI Agents
In packages/features/eventtypes/components/Locations.tsx around lines 426 to
439, the TypeScript error occurs because the property
disableRecordingEmailsForGuests is missing from the calVideoSettings type. To
fix this, update the FormValues type definition in
packages/features/eventtypes/lib/types.ts by adding
disableRecordingEmailsForGuests as a boolean property to the calVideoSettings
interface. Also, verify that any other related type definitions referencing
calVideoSettings are updated accordingly to maintain consistency across the
codebase.


<TextField
label={t("enter_redirect_url_on_exit_description")}
defaultValue={eventType.calVideoSettings?.redirectUrlOnExit || ""}
Expand Down
1 change: 1 addition & 0 deletions packages/features/eventtypes/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export type FormValues = {
disableTranscriptionForGuests?: boolean;
disableTranscriptionForOrganizer?: boolean;
redirectUrlOnExit?: string;
disableRecordingEmailsForGuests?: boolean;
};
maxActiveBookingPerBookerOfferReschedule: boolean;
};
Expand Down
1 change: 1 addition & 0 deletions packages/lib/server/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"cal_ai_assistant": "Cal AI Assistant",
"send_cal_video_transcription_emails": "Send Cal Video Transcription Emails",
"description_send_cal_video_transcription_emails": "Send emails with the transcription of the Cal Video after the meeting ends. (Requires a paid plan)",
"disable_recording_emails_for_guests": "Disable recording emails for guests",
"verify_email_change_description": "You have recently requested to change the email address you use to log into your {{appName}} account. Please click the button below to confirm your new email address.",
"verify_email_change_success_toast": "Updated your email to {{email}}",
"verify_email_change_failure_toast": "Failed to update email.",
Expand Down
3 changes: 3 additions & 0 deletions packages/lib/server/repository/calVideoSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class CalVideoSettingsRepository {
disableTranscriptionForOrganizer?: boolean | null;
enableAutomaticTranscription?: boolean | null;
redirectUrlOnExit?: string | null;
disableRecordingEmailsForGuests?: boolean | null;
};
}) {
return await prisma.calVideoSettings.upsert({
Expand All @@ -30,6 +31,7 @@ export class CalVideoSettingsRepository {
disableTranscriptionForGuests: calVideoSettings.disableTranscriptionForGuests ?? false,
disableTranscriptionForOrganizer: calVideoSettings.disableTranscriptionForOrganizer ?? false,
redirectUrlOnExit: calVideoSettings.redirectUrlOnExit ?? null,
disableRecordingEmailsForGuests: calVideoSettings.disableRecordingEmailsForGuests ?? false,
updatedAt: new Date(),
},
create: {
Expand All @@ -39,6 +41,7 @@ export class CalVideoSettingsRepository {
disableTranscriptionForGuests: calVideoSettings.disableTranscriptionForGuests ?? false,
disableTranscriptionForOrganizer: calVideoSettings.disableTranscriptionForOrganizer ?? false,
redirectUrlOnExit: calVideoSettings.redirectUrlOnExit ?? null,
disableRecordingEmailsForGuests: calVideoSettings.disableRecordingEmailsForGuests ?? false,
eventTypeId,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ export class CalVideoSettings {
})
disableRecordingForGuests?: boolean;

@IsOptional()
@IsBoolean()
@DocsPropertyOptional({
description: "If true, recording emails will not be sent to guests",
})
disableRecordingEmailsForGuests?: boolean;

@IsOptional()
@IsUrl()
@DocsPropertyOptional({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "CalVideoSettings" ADD COLUMN "disableRecordingEmailsForGuests" BOOLEAN NOT NULL DEFAULT false;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using nullable Boolean field following team preferences.

Based on Cal.com's established schema design patterns, the team prefers nullable Boolean fields (Boolean?) with defaults rather than non-nullable fields to avoid expensive database migrations that update existing rows.

Consider changing the migration to:

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

This approach aligns with the team's preference and avoids the cost of updating all existing rows during migration.

📝 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
ALTER TABLE "CalVideoSettings" ADD COLUMN "disableRecordingEmailsForGuests" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "CalVideoSettings" ADD COLUMN "disableRecordingEmailsForGuests" BOOLEAN DEFAULT false;
🤖 Prompt for AI Agents
In
packages/prisma/migrations/20250128000000_add_disable_recording_emails_for_guests/migration.sql
at line 1, the new column disableRecordingEmailsForGuests is added as a
non-nullable Boolean with a default false. To align with team preferences and
avoid costly updates on existing rows, change the column to be nullable Boolean
(allow NULL values) with a default false instead. Modify the ALTER TABLE
statement to add the column as nullable with the default, so existing rows are
not updated during migration.

1 change: 1 addition & 0 deletions packages/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ model CalVideoSettings {
redirectUrlOnExit String?
disableTranscriptionForGuests Boolean @default(false)
disableTranscriptionForOrganizer Boolean @default(false)
disableRecordingEmailsForGuests Boolean @default(false)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Follow team preference for nullable Boolean fields.

The new field uses a non-nullable Boolean, but Cal.com's established schema design pattern prefers nullable Boolean fields with defaults to avoid expensive database migrations.

Consider changing to:

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

This approach aligns with the team's preference and avoids costly row updates during migration.

📝 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
disableRecordingEmailsForGuests Boolean @default(false)
disableRecordingEmailsForGuests Boolean? @default(false)
🤖 Prompt for AI Agents
In packages/prisma/schema.prisma at line 81, the field
disableRecordingEmailsForGuests is defined as a non-nullable Boolean with a
default value. To follow the team's preference and avoid expensive database
migrations, change this field to a nullable Boolean with a default value
instead. Update the schema to make the field Boolean? with @default(false) so it
aligns with the established pattern and reduces migration costs.


createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
Expand Down
1 change: 1 addition & 0 deletions packages/prisma/zod/custom/eventtype.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const calVideoSettingsSchema = z
disableRecordingForGuests: z.boolean().optional().nullable(),
disableRecordingForOrganizer: z.boolean().optional().nullable(),
redirectUrlOnExit: z.string().url().optional().nullable(),
disableRecordingEmailsForGuests: z.boolean().optional().nullable(),
})
.optional()
.nullable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const createHandler = async ({ ctx, input }: CreateOptions) => {
disableRecordingForGuests: calVideoSettings.disableRecordingForGuests ?? false,
disableRecordingForOrganizer: calVideoSettings.disableRecordingForOrganizer ?? false,
redirectUrlOnExit: calVideoSettings.redirectUrlOnExit ?? null,
disableRecordingEmailsForGuests: calVideoSettings.disableRecordingEmailsForGuests ?? false,
},
};
}
Expand Down
1 change: 1 addition & 0 deletions packages/trpc/server/routers/viewer/eventTypes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const calVideoSettingsSchema = z
disableTranscriptionForGuests: z.boolean().optional().nullable(),
disableTranscriptionForOrganizer: z.boolean().optional().nullable(),
redirectUrlOnExit: z.string().url().optional().nullable(),
disableRecordingEmailsForGuests: z.boolean().optional().nullable(),
})
.optional()
.nullable();
Expand Down
Loading