Skip to content
Draft
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
12 changes: 6 additions & 6 deletions apps/web/pages/api/book/recurring-event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ describe("handleNewBooking", () => {
organizer,
location: "integrations:daily",
subscriberUrl: "http://my-webhook.example.com",
//FIXME: All recurring bookings seem to have the same URL. https://github.com/calcom/cal.com/issues/11955
videoCallUrl: `${WEBAPP_URL}/video/${createdBookings[0].uid}`,
videoCallUrl: `${WEBAPP_URL}/video/${createdBooking.uid}`,
uid: createdBooking.uid ?? undefined,
});
}

Expand Down Expand Up @@ -551,8 +551,8 @@ describe("handleNewBooking", () => {
organizer,
location: "integrations:daily",
subscriberUrl: "http://my-webhook.example.com",
//FIXME: File a bug - All recurring bookings seem to have the same URL. They should have same CalVideo URL which could mean that future recurring meetings would have already expired by the time they are needed.
videoCallUrl: `${WEBAPP_URL}/video/${createdBookings[0].uid}`,
videoCallUrl: `${WEBAPP_URL}/video/${createdBooking.uid}`,
uid: createdBooking.uid ?? undefined,
});
}

Expand Down Expand Up @@ -769,8 +769,8 @@ describe("handleNewBooking", () => {
organizer,
location: "integrations:daily",
subscriberUrl: "http://my-webhook.example.com",
//FIXME: File a bug - All recurring bookings seem to have the same URL. They should have same CalVideo URL which could mean that future recurring meetings would have already expired by the time they are needed.
videoCallUrl: `${WEBAPP_URL}/video/${createdBookings[0].uid}`,
videoCallUrl: `${WEBAPP_URL}/video/${createdBooking.uid}`,
uid: createdBooking.uid ?? undefined,
});
}

Expand Down
28 changes: 20 additions & 8 deletions packages/features/bookings/lib/handleConfirmation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
import { scheduleTrigger } from "@calcom/features/webhooks/lib/scheduleTrigger";
import sendPayload from "@calcom/features/webhooks/lib/sendOrSchedulePayload";
import type { EventPayloadType, EventTypeInfo } from "@calcom/features/webhooks/lib/sendPayload";
import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser";
import { getPublicVideoCallUrl, getVideoCallUrlFromCalEvent, isDailyVideoCall } from "@calcom/lib/CalEventParser";
import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId";
import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType";
import { safeStringify } from "@calcom/lib/safeStringify";
Expand Down Expand Up @@ -276,8 +276,15 @@ export async function handleConfirmation(args: {
uid: booking.uid,
}));

const updateBookingsPromise = unconfirmedRecurringBookings.map((recurringBooking) =>
prisma.booking.update({
const updateBookingsPromise = unconfirmedRecurringBookings.map((recurringBooking) => {
// For Cal Video (Daily), each occurrence must use its own booking uid as the room
// identifier — the public URL is /video/<uid>. Other providers create a single
// meeting for the whole series, so they share meetingUrl.
const bookingVideoCallUrl = isDailyVideoCall(evt.videoCallData)
? getPublicVideoCallUrl(recurringBooking.uid)
: meetingUrl;

return prisma.booking.update({
where: {
id: recurringBooking.id,
},
Expand All @@ -289,7 +296,7 @@ export async function handleConfirmation(args: {
paid,
metadata: {
...(typeof recurringBooking.metadata === "object" ? recurringBooking.metadata : {}),
videoCallUrl: meetingUrl,
videoCallUrl: bookingVideoCallUrl,
},
},
select: {
Expand Down Expand Up @@ -334,8 +341,8 @@ export async function handleConfirmation(args: {
customInputs: true,
id: true,
},
})
);
});
});

const updatedBookingsResult = await Promise.all(updateBookingsPromise);
updatedBookings = updatedBookings.concat(updatedBookingsResult);
Expand Down Expand Up @@ -442,10 +449,15 @@ export async function handleConfirmation(args: {
try {
for (let index = 0; index < updatedBookings.length; index++) {
const eventTypeSlug = updatedBookings[index].eventType?.slug || "";
const bookingUid = updatedBookings[index].uid;
const evtOfBooking = {
...evt,
rescheduleReason: updatedBookings[index].cancellationReason || null,
metadata: { videoCallUrl: meetingUrl },
metadata: {
videoCallUrl: isDailyVideoCall(evt.videoCallData)
? getPublicVideoCallUrl(bookingUid)
: meetingUrl,
},
eventType: {
slug: eventTypeSlug,
schedulingType: updatedBookings[index].eventType?.schedulingType,
Expand All @@ -455,7 +467,7 @@ export async function handleConfirmation(args: {
};
evtOfBooking.startTime = updatedBookings[index].startTime.toISOString();
evtOfBooking.endTime = updatedBookings[index].endTime.toISOString();
evtOfBooking.uid = updatedBookings[index].uid;
evtOfBooking.uid = bookingUid;
const isFirstBooking = index === 0;

if (!eventTypeMetadata?.disableStandardEmails?.all?.attendee) {
Expand Down
11 changes: 10 additions & 1 deletion packages/testing/src/lib/bookingScenario/expects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ export function expectWebhookToHaveBeenCalledWith(
data: {
triggerEvent: WebhookTriggerEvents;
payload: Record<string, unknown> | null;
/** When provided, only the webhook whose payload.uid matches this value is checked. */
uid?: string;
}
) {
const fetchCalls = fetchMock.mock.calls;
Expand All @@ -283,7 +285,9 @@ export function expectWebhookToHaveBeenCalledWith(
const webhookFetchCall = webhooksToSubscriberUrl.find((call) => {
const body = call[1]?.body;
const parsedBody = JSON.parse((body as string) || "{}");
return parsedBody.triggerEvent === data.triggerEvent;
if (parsedBody.triggerEvent !== data.triggerEvent) return false;
if (data.uid !== undefined && parsedBody.payload?.uid !== data.uid) return false;
return true;
});

if (!webhookFetchCall) {
Expand Down Expand Up @@ -1032,6 +1036,7 @@ export function expectBookingCreatedWebhookToHaveBeenFired({
subscriberUrl,
paidEvent,
videoCallUrl,
uid,
isEmailHidden = false,
isAttendeePhoneNumberHidden = false,
}: {
Expand All @@ -1041,6 +1046,8 @@ export function expectBookingCreatedWebhookToHaveBeenFired({
location: string;
paidEvent?: boolean;
videoCallUrl?: string | null;
/** When provided, only the webhook whose payload.uid matches this value is checked. */
uid?: string;
isEmailHidden?: boolean;
isAttendeePhoneNumberHidden?: boolean;
}) {
Expand All @@ -1052,6 +1059,7 @@ export function expectBookingCreatedWebhookToHaveBeenFired({
if (!paidEvent) {
expectWebhookToHaveBeenCalledWith(subscriberUrl, {
triggerEvent: "BOOKING_CREATED",
uid,
payload: {
metadata: {
...(videoCallUrl ? { videoCallUrl } : null),
Expand Down Expand Up @@ -1080,6 +1088,7 @@ export function expectBookingCreatedWebhookToHaveBeenFired({
} else {
expectWebhookToHaveBeenCalledWith(subscriberUrl, {
triggerEvent: "BOOKING_CREATED",
uid,
payload: {
// FIXME: File this bug and link ticket here. This is a bug in the code. metadata must be sent here like other BOOKING_CREATED webhook
metadata: null,
Expand Down
Loading