fix: use Cal.com video URL (#27184)

This commit is contained in:
Anik Dhabal Babu
2026-01-23 11:42:08 +00:00
committed by GitHub
parent 25fa46fd34
commit 646d18e286
2 changed files with 134 additions and 5 deletions
@@ -9,6 +9,7 @@ import {
WorkflowTemplates,
WorkflowTriggerEvents,
} from "@calcom/prisma/enums";
import { TimeFormat } from "@calcom/lib/timeFormat";
import type { CalendarEvent } from "@calcom/types/Calendar";
import { EmailWorkflowService } from "./EmailWorkflowService";
@@ -34,6 +35,20 @@ vi.mock("@calcom/emails/lib/generateIcsString", () => ({
default: vi.fn().mockReturnValue("mock-ics-content"),
}));
vi.mock("@calcom/lib/constants", async () => {
const actual = await vi.importActual<typeof import("@calcom/lib/constants")>("@calcom/lib/constants");
return {
...actual,
WEBAPP_URL: "https://cal.com",
APP_NAME: "Cal.com",
};
});
vi.mock("short-uuid", () => ({
__esModule: true,
default: () => ({ fromUUID: (uid: string) => uid }),
}));
const mockWorkflowReminderRepository: Pick<WorkflowReminderRepository, "findByIdIncludeStepAndWorkflow"> = {
findByIdIncludeStepAndWorkflow: vi.fn(),
};
@@ -582,4 +597,109 @@ describe("EmailWorkflowService", () => {
expect(result.attachments).toBeUndefined();
});
});
describe("generateEmailPayloadForEvtWorkflow - Cal Video meeting URL", () => {
const mockBookingInfoWithCalVideo = {
uid: "booking-cal-video-123",
bookerUrl: "https://cal.com",
title: "Test Meeting with Cal Video",
startTime: "2024-12-01T10:00:00Z",
endTime: "2024-12-01T11:00:00Z",
organizer: {
name: "Organizer Name",
email: "organizer@example.com",
timeZone: "UTC",
language: { locale: "en" },
timeFormat: TimeFormat.TWELVE_HOUR,
},
attendees: [
{
name: "Attendee Name",
email: "attendee@example.com",
timeZone: "UTC",
language: { locale: "en" },
},
],
videoCallData: {
type: "daily_video",
url: "https://test-org.daily.co/test-room-name",
id: "test-room-name",
password: "test-password",
},
location: "Cal Video",
};
test("should use Cal.com video URL instead of daily.co URL for REMINDER template when using Cal video", async () => {
const result = await emailWorkflowService.generateEmailPayloadForEvtWorkflow({
evt: mockBookingInfoWithCalVideo,
sendTo: ["attendee@example.com"],
hideBranding: false,
emailSubject: "Test Subject",
emailBody: "", // Empty body with REMINDER template triggers REMINDER template
sender: "Cal.com",
action: WorkflowActions.EMAIL_ATTENDEE,
template: WorkflowTemplates.REMINDER,
includeCalendarEvent: false,
triggerEvent: WorkflowTriggerEvents.BEFORE_EVENT,
});
// The meetingUrl should NOT contain daily.co
expect(result.html).not.toContain("daily.co");
// The meetingUrl should contain the Cal.com video URL format
expect(result.html).toContain("/video/booking-cal-video-123");
});
test("should use Cal.com video URL instead of daily.co URL for custom template when using Cal video", async () => {
const customEmailBody = "Join the meeting at {MEETING_URL}";
const result = await emailWorkflowService.generateEmailPayloadForEvtWorkflow({
evt: mockBookingInfoWithCalVideo,
sendTo: ["attendee@example.com"],
hideBranding: false,
emailSubject: "Test Subject",
emailBody: customEmailBody,
sender: "Cal.com",
action: WorkflowActions.EMAIL_ATTENDEE,
template: WorkflowTemplates.CUSTOM,
includeCalendarEvent: false,
triggerEvent: WorkflowTriggerEvents.BEFORE_EVENT,
});
// The meetingUrl should NOT contain daily.co
expect(result.html).not.toContain("daily.co");
// The meetingUrl should contain the Cal.com video URL format
expect(result.html).toContain("/video/booking-cal-video-123");
});
test("should use Cal.com video URL format when videoCallData.url contains daily.co domain", async () => {
const mockBookingInfoWithDailyCoUrl = {
...mockBookingInfoWithCalVideo,
videoCallData: {
type: "daily_video",
url: "https://some-org.daily.co/another-room-name",
id: "another-room-name",
password: "test-password",
},
};
const result = await emailWorkflowService.generateEmailPayloadForEvtWorkflow({
evt: mockBookingInfoWithDailyCoUrl,
sendTo: ["attendee@example.com"],
hideBranding: false,
emailSubject: "Test Subject",
emailBody: "", // Empty body with REMINDER template triggers REMINDER template
sender: "Cal.com",
action: WorkflowActions.EMAIL_ATTENDEE,
template: WorkflowTemplates.REMINDER,
includeCalendarEvent: false,
triggerEvent: WorkflowTriggerEvents.BEFORE_EVENT,
});
// Even though videoCallData.url contains daily.co, the meetingUrl should NOT contain it
expect(result.html).not.toContain("daily.co");
expect(result.html).not.toContain("some-org.daily.co");
expect(result.html).not.toContain("another-room-name");
// Should use Cal.com video URL instead
expect(result.html).toContain("/video/booking-cal-video-123");
});
});
});
@@ -397,7 +397,12 @@ export class EmailWorkflowService {
if (matchedTemplate === WorkflowTemplates.REMINDER) {
const t = await getTranslation(locale, "common");
const meetingUrl =
getVideoCallUrlFromCalEvent({
videoCallData: evt.videoCallData,
uid: evt.uid,
location: evt.location,
}) || bookingMetadataSchema.safeParse(evt.metadata || {}).data?.videoCallUrl;
emailContent = emailReminderTemplate({
isEditingMode: false,
locale,
@@ -409,8 +414,7 @@ export class EmailWorkflowService {
eventName: evt.title,
timeZone,
location: evt.location || "",
meetingUrl:
evt.videoCallData?.url || bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl || "",
meetingUrl,
otherPerson: attendeeName,
name,
});
@@ -438,7 +442,12 @@ export class EmailWorkflowService {
sendToEmail: sendTo[0],
});
const meetingUrl =
getVideoCallUrlFromCalEvent({ videoCallData: evt.videoCallData }) || bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl;
getVideoCallUrlFromCalEvent({
videoCallData: evt.videoCallData,
uid: evt.uid,
location: evt.location,
}) || bookingMetadataSchema.safeParse(evt.metadata || {}).data?.videoCallUrl;
const variables: VariablesType = {
eventName: evt.title || "",
organizerName: evt.organizer.name,
@@ -515,7 +524,7 @@ export class EmailWorkflowService {
language: { ...evt.organizer.language, translate: organizerT },
},
attendees: processedAttendees,
location: bookingMetadataSchema.parse(evt.metadata || {})?.videoCallUrl || evt.location,
location: bookingMetadataSchema.safeParse(evt.metadata || {}).data?.videoCallUrl || evt.location,
};
const shouldIncludeCalendarEvent =