From d067b0782ae400d439a25f635a3f72f53dfa4b98 Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Wed, 10 May 2023 20:26:31 +0530 Subject: [PATCH] feat: add RECORDING_READY webhook (#8277) * feat: add RECORDING_READY webhook Signed-off-by: Udit Takkar * fix: type errors and improvements Signed-off-by: Udit Takkar --------- Signed-off-by: Udit Takkar Co-authored-by: Keith Williams Co-authored-by: Hariom Balhara --- .../eventtype/EventTeamWebhooksTab.tsx | 2 +- apps/web/pages/api/recorded-daily-video.ts | 83 ++++++++++++++----- apps/web/public/static/locales/en/common.json | 1 + .../webhooks/components/WebhookForm.tsx | 1 + packages/features/webhooks/lib/constants.ts | 1 + packages/features/webhooks/lib/sendPayload.ts | 1 + .../migration.sql | 2 + packages/prisma/schema.prisma | 1 + 8 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 packages/prisma/migrations/20230414112451_add_recording_ready/migration.sql diff --git a/apps/web/components/eventtype/EventTeamWebhooksTab.tsx b/apps/web/components/eventtype/EventTeamWebhooksTab.tsx index f2685037fa..ec1a30ad3d 100644 --- a/apps/web/components/eventtype/EventTeamWebhooksTab.tsx +++ b/apps/web/components/eventtype/EventTeamWebhooksTab.tsx @@ -170,7 +170,7 @@ export const EventTeamWebhooksTab = ({ {/* Edit webhook dialog */} !isOpen && setEditModalOpen(false)}> - + app.slug)} diff --git a/apps/web/pages/api/recorded-daily-video.ts b/apps/web/pages/api/recorded-daily-video.ts index 19de912751..1192727d3a 100644 --- a/apps/web/pages/api/recorded-daily-video.ts +++ b/apps/web/pages/api/recorded-daily-video.ts @@ -1,3 +1,4 @@ +import type { WebhookTriggerEvents } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { z } from "zod"; @@ -5,6 +6,8 @@ import { DailyLocationType } from "@calcom/app-store/locations"; import { getDownloadLinkOfCalVideoByRecordingId } from "@calcom/core/videoClient"; import { sendDailyVideoRecordingEmails } from "@calcom/emails"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; +import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks"; +import sendPayload from "@calcom/features/webhooks/lib/sendPayload"; import { IS_SELF_HOSTED } from "@calcom/lib/constants"; import { defaultHandler } from "@calcom/lib/server"; import { getTranslation } from "@calcom/lib/server/i18n"; @@ -20,6 +23,38 @@ const downloadLinkSchema = z.object({ download_link: z.string(), }); +const triggerWebhook = async ({ + evt, + downloadLink, + booking, +}: { + evt: CalendarEvent; + downloadLink: string; + booking: { + userId: number | undefined; + eventTypeId: number | null; + }; +}) => { + const eventTrigger: WebhookTriggerEvents = "RECORDING_READY"; + // Send Webhook call if hooked to BOOKING.RECORDING_READY + const subscriberOptions = { + userId: booking.userId ?? 0, + eventTypeId: booking.eventTypeId ?? 0, + triggerEvent: eventTrigger, + }; + const webhooks = await getWebhooks(subscriberOptions); + + const promises = webhooks.map((webhook) => + sendPayload(webhook.secret, eventTrigger, new Date().toISOString(), webhook, { + ...evt, + downloadLink, + }).catch((e) => { + console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${webhook.subscriberUrl}`, e); + }) + ); + await Promise.all(promises); +}; + async function handler(req: NextApiRequest, res: NextApiResponse) { if (!process.env.SENDGRID_API_KEY || !process.env.SENDGRID_EMAIL) { return res.status(405).json({ message: "No SendGrid API key or email" }); @@ -51,6 +86,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { uid: true, location: true, isRecorded: true, + eventTypeId: true, user: { select: { id: true, @@ -105,31 +141,36 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { }, }); + const response = await getDownloadLinkOfCalVideoByRecordingId(recordingId); + const downloadLinkResponse = downloadLinkSchema.parse(response); + const downloadLink = downloadLinkResponse.download_link; + + const evt: CalendarEvent = { + type: booking.title, + title: booking.title, + description: booking.description || undefined, + startTime: booking.startTime.toISOString(), + endTime: booking.endTime.toISOString(), + organizer: { + email: booking.user?.email || "Email-less", + name: booking.user?.name || "Nameless", + timeZone: booking.user?.timeZone || "Europe/London", + language: { translate: t, locale: booking?.user?.locale ?? "en" }, + }, + attendees: attendeesList, + uid: booking.uid, + }; + + await triggerWebhook({ + evt, + downloadLink, + booking: { userId: booking?.user?.id, eventTypeId: booking.eventTypeId }, + }); + const isSendingEmailsAllowed = IS_SELF_HOSTED || session?.user?.belongsToActiveTeam; // send emails to all attendees only when user has team plan if (isSendingEmailsAllowed) { - const response = await getDownloadLinkOfCalVideoByRecordingId(recordingId); - - const downloadLinkResponse = downloadLinkSchema.parse(response); - const downloadLink = downloadLinkResponse.download_link; - - const evt: CalendarEvent = { - type: booking.title, - title: booking.title, - description: booking.description || undefined, - startTime: booking.startTime.toISOString(), - endTime: booking.endTime.toISOString(), - organizer: { - email: booking.user?.email || "Email-less", - name: booking.user?.name || "Nameless", - timeZone: booking.user?.timeZone || "Europe/London", - language: { translate: t, locale: booking?.user?.locale ?? "en" }, - }, - attendees: attendeesList, - uid: booking.uid, - }; - await sendDailyVideoRecordingEmails(evt, downloadLink); return res.status(200).json({ message: "Success" }); } diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 9190aa6da3..87b92b9730 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -367,6 +367,7 @@ "create_webhook": "Create Webhook", "booking_cancelled": "Booking Cancelled", "booking_rescheduled": "Booking Rescheduled", + "recording_ready":"Recording Download Link Ready", "booking_created": "Booking Created", "meeting_ended": "Meeting Ended", "form_submitted": "Form Submitted", diff --git a/packages/features/webhooks/components/WebhookForm.tsx b/packages/features/webhooks/components/WebhookForm.tsx index 9912306a4d..56d6e06ab2 100644 --- a/packages/features/webhooks/components/WebhookForm.tsx +++ b/packages/features/webhooks/components/WebhookForm.tsx @@ -34,6 +34,7 @@ const WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2: Record