3a7122d613
* fix: revert assignmentReason breaking change in webhook payloads
Remove the new { category, details } format from EventPayloadType to
maintain backward compatibility for webhook consumers. The new format
is stripped at all webhook payload construction sites by destructuring
assignmentReason out of CalendarEvent before spreading into the payload.
A sanitizeAssignmentReasonForWebhook function provides an additional
safety net in sendPayload itself. Emails and booking single view
continue to use the new format via CalendarEvent.
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* fix: strip assignmentReason from handlePaymentSuccess webhook payload
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* fix: strip assignmentReason from triggerWebhooks and handleSeats webhook payloads
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
* refactor: use zod safeParse instead of type assertion in sanitizeAssignmentReasonForWebhook
Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import type { TGetTranscriptAccessLink } from "@calcom/app-store/dailyvideo/zod";
|
|
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
|
|
import sendPayload from "@calcom/features/webhooks/lib/sendOrSchedulePayload";
|
|
import type { EventPayloadType } from "@calcom/features/webhooks/lib/sendPayload";
|
|
import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId";
|
|
import logger from "@calcom/lib/logger";
|
|
import { safeStringify } from "@calcom/lib/safeStringify";
|
|
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
|
import type { CalendarEvent } from "@calcom/types/Calendar";
|
|
|
|
const log = logger.getSubLogger({ prefix: ["daily-video-webhook-handler:triggerRecordingReadyWebhook"] });
|
|
|
|
type Booking = {
|
|
userId: number | undefined;
|
|
eventTypeId: number | null;
|
|
eventTypeParentId: number | null | undefined;
|
|
teamId?: number | null;
|
|
};
|
|
|
|
const getWebhooksByEventTrigger = async (eventTrigger: WebhookTriggerEvents, booking: Booking) => {
|
|
const isTeamBooking = booking.teamId;
|
|
const isBookingForManagedEventtype = booking.teamId && booking.eventTypeParentId;
|
|
const triggerForUser = !isTeamBooking || isBookingForManagedEventtype;
|
|
const organizerUserId = triggerForUser ? booking.userId : null;
|
|
const orgId = await getOrgIdFromMemberOrTeamId({ memberId: organizerUserId, teamId: booking.teamId });
|
|
|
|
const subscriberOptions = {
|
|
userId: organizerUserId,
|
|
eventTypeId: booking.eventTypeId,
|
|
triggerEvent: eventTrigger,
|
|
teamId: booking.teamId,
|
|
orgId,
|
|
};
|
|
|
|
return getWebhooks(subscriberOptions);
|
|
};
|
|
|
|
export const triggerRecordingReadyWebhook = async ({
|
|
evt,
|
|
downloadLink,
|
|
booking,
|
|
}: {
|
|
evt: CalendarEvent;
|
|
downloadLink: string;
|
|
booking: Booking;
|
|
}) => {
|
|
const eventTrigger: WebhookTriggerEvents = "RECORDING_READY";
|
|
const webhooks = await getWebhooksByEventTrigger(eventTrigger, booking);
|
|
|
|
log.debug(
|
|
"Webhooks:",
|
|
safeStringify({
|
|
webhooks,
|
|
})
|
|
);
|
|
|
|
const { assignmentReason: _emailAssignmentReason, ...evtWithoutAssignmentReason } = evt;
|
|
const payload: EventPayloadType = {
|
|
...evtWithoutAssignmentReason,
|
|
downloadLink,
|
|
};
|
|
|
|
const promises = webhooks.map((webhook) =>
|
|
sendPayload(webhook.secret, eventTrigger, new Date().toISOString(), webhook, payload).catch((e) => {
|
|
log.error(
|
|
`Error executing webhook for event: ${eventTrigger}, URL: ${webhook.subscriberUrl}, bookingId: ${evt.bookingId}, bookingUid: ${evt.uid}`,
|
|
safeStringify(e)
|
|
);
|
|
})
|
|
);
|
|
await Promise.all(promises);
|
|
};
|
|
|
|
export const triggerTranscriptionGeneratedWebhook = async ({
|
|
evt,
|
|
downloadLinks,
|
|
booking,
|
|
}: {
|
|
evt: CalendarEvent;
|
|
downloadLinks?: {
|
|
transcription: TGetTranscriptAccessLink["transcription"];
|
|
recording: string;
|
|
};
|
|
booking: Booking;
|
|
}) => {
|
|
const webhooks = await getWebhooksByEventTrigger(
|
|
WebhookTriggerEvents.RECORDING_TRANSCRIPTION_GENERATED,
|
|
booking
|
|
);
|
|
|
|
log.debug(
|
|
"Webhooks:",
|
|
safeStringify({
|
|
webhooks,
|
|
})
|
|
);
|
|
|
|
const { assignmentReason: _emailAssignmentReason2, ...evtWithoutAssignmentReason2 } = evt;
|
|
const payload: EventPayloadType = {
|
|
...evtWithoutAssignmentReason2,
|
|
downloadLinks,
|
|
};
|
|
|
|
const promises = webhooks.map((webhook) =>
|
|
sendPayload(
|
|
webhook.secret,
|
|
WebhookTriggerEvents.RECORDING_TRANSCRIPTION_GENERATED,
|
|
new Date().toISOString(),
|
|
webhook,
|
|
payload
|
|
).catch((e) => {
|
|
log.error(
|
|
`Error executing webhook for event: ${WebhookTriggerEvents.RECORDING_TRANSCRIPTION_GENERATED}, URL: ${webhook.subscriberUrl}, bookingId: ${evt.bookingId}, bookingUid: ${evt.uid}`,
|
|
safeStringify(e)
|
|
);
|
|
})
|
|
);
|
|
await Promise.all(promises);
|
|
};
|