diff --git a/apps/web/app/api/recorded-daily-video/route.ts b/apps/web/app/api/recorded-daily-video/route.ts index 007297cf81..4c9834219e 100644 --- a/apps/web/app/api/recorded-daily-video/route.ts +++ b/apps/web/app/api/recorded-daily-video/route.ts @@ -5,6 +5,7 @@ import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; import { getRoomNameFromRecordingId, getBatchProcessorJobAccessLink } from "@calcom/app-store/dailyvideo/lib"; +import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository"; import { sendDailyVideoRecordingEmails, sendDailyVideoTranscriptEmails, @@ -74,7 +75,7 @@ export async function postHandler(request: NextRequest) { } } - log.debug( + log.info( "Daily video webhook Request Body:", safeStringify({ body, @@ -98,47 +99,55 @@ export async function postHandler(request: NextRequest) { const bookingReference = await getBookingReference(room_name); const booking = await getBooking(bookingReference.bookingId as number); - const evt = await getCalendarEvent(booking); + const bookingRepository = new BookingRepository(prisma); - await prisma.booking.update({ - where: { - uid: booking.uid, - }, - data: { + const [evt, updateRecordStatus, downloadLink, teamId] = await Promise.all([ + getCalendarEvent(booking), + bookingRepository.updateRecordedStatus({ + bookingUid: booking.uid, isRecorded: true, + }), + getProxyDownloadLinkOfCalVideo(recording_id), + getTeamIdFromEventType({ + eventType: { + team: { id: booking?.eventType?.teamId ?? null }, + parentId: booking?.eventType?.parentId ?? null, + }, + }), + ]); + + const tasks = [ + { + fn: triggerRecordingReadyWebhook({ + evt, + downloadLink, + booking: { + userId: booking?.user?.id, + eventTypeId: booking.eventTypeId, + eventTypeParentId: booking.eventType?.parentId, + teamId, + }, + }), + errorMsg: "trigger recording ready webhook", }, - }); - - const downloadLink = await getProxyDownloadLinkOfCalVideo(recording_id); - - const teamId = await getTeamIdFromEventType({ - eventType: { - team: { id: booking?.eventType?.teamId ?? null }, - parentId: booking?.eventType?.parentId ?? null, + { + fn: submitBatchProcessorTranscriptionJob(recording_id), + errorMsg: "submit transcription batch processor job", }, - }); - - await triggerRecordingReadyWebhook({ - evt, - downloadLink, - booking: { - userId: booking?.user?.id, - eventTypeId: booking.eventTypeId, - eventTypeParentId: booking.eventType?.parentId, - teamId, + { + fn: sendDailyVideoRecordingEmails(evt, downloadLink), + errorMsg: "send recording emails", }, + ]; + + const results = await Promise.allSettled(tasks.map((t) => t.fn)); + + results.forEach((result, index) => { + if (result.status === "rejected") { + log.error(`Failed to ${tasks[index].errorMsg}:`, safeStringify(result.reason)); + } }); - try { - // Submit Transcription Batch Processor Job - await submitBatchProcessorTranscriptionJob(recording_id); - } catch (err) { - log.error("Failed to Submit Transcription Batch Processor Job:", safeStringify(err)); - } - - // send emails to all attendees only when user has team plan - await sendDailyVideoRecordingEmails(evt, downloadLink); - return NextResponse.json({ message: "Success" }); } else if (body.type === "meeting.ended") { const meetingEndedResponse = meetingEndedSchema.safeParse(body); @@ -189,10 +198,11 @@ export async function postHandler(request: NextRequest) { }, }); - const evt = await getCalendarEvent(booking); - - const recording = await getProxyDownloadLinkOfCalVideo(input.recordingId); - const batchProcessorJobAccessLink = await getBatchProcessorJobAccessLink(id); + const [evt, recording, batchProcessorJobAccessLink] = await Promise.all([ + getCalendarEvent(booking), + getProxyDownloadLinkOfCalVideo(input.recordingId), + getBatchProcessorJobAccessLink(id), + ]); await triggerTranscriptionGeneratedWebhook({ evt, @@ -211,7 +221,9 @@ export async function postHandler(request: NextRequest) { return NextResponse.json({ message: "Success" }); } else { log.error("Invalid type in /recorded-daily-video", body); - return NextResponse.json({ message: "Invalid type in /recorded-daily-video" }); + return NextResponse.json({ + message: "Invalid type in /recorded-daily-video", + }); } } catch (err) { log.error("Error in /recorded-daily-video", err); diff --git a/packages/features/bookings/repositories/BookingRepository.ts b/packages/features/bookings/repositories/BookingRepository.ts index 062a42e33f..37d569adc9 100644 --- a/packages/features/bookings/repositories/BookingRepository.ts +++ b/packages/features/bookings/repositories/BookingRepository.ts @@ -1912,4 +1912,11 @@ export class BookingRepository { }, }); } + + async updateRecordedStatus({ bookingUid, isRecorded }: { bookingUid: string; isRecorded: boolean }): Promise { + await this.prismaClient.booking.update({ + where: { uid: bookingUid }, + data: { isRecorded }, + }); + } }