From 559ccb8ca7f61f8f2bb77ddf671e4a01554d0377 Mon Sep 17 00:00:00 2001 From: Mihai C <34626017+mihaic195@users.noreply.github.com> Date: Tue, 9 Nov 2021 18:27:33 +0200 Subject: [PATCH] hotfix: zoom location on emails (#1153) * fix: zoom location on emails * test: fix Co-authored-by: Peer Richelsen --- lib/calendarClient.ts | 41 +++++++++++++++++++-------- lib/events/EventManager.ts | 49 ++++++++++++++++----------------- lib/videoClient.ts | 41 ++++++++++++++------------- pages/api/book/event.ts | 5 ++-- playwright/integrations.test.ts | 2 ++ 5 files changed, 80 insertions(+), 58 deletions(-) diff --git a/lib/calendarClient.ts b/lib/calendarClient.ts index 0e45b834..fd20b1bc 100644 --- a/lib/calendarClient.ts +++ b/lib/calendarClient.ts @@ -642,6 +642,15 @@ const createEvent = async ( }) : undefined; + if (!creationResult) { + return { + type: credential.type, + success, + uid, + originalEvent: calEvent, + }; + } + const metadata: AdditionInformation = {}; if (creationResult) { // TODO: Handle created event metadata more elegantly @@ -650,10 +659,10 @@ const createEvent = async ( metadata.entryPoints = creationResult.entryPoints; } - const emailEvent = { ...calEvent, additionInformation: metadata }; + calEvent.additionInformation = metadata; if (!noMail) { - const organizerMail = new EventOrganizerMail(emailEvent); + const organizerMail = new EventOrganizerMail(calEvent); try { await organizerMail.sendEmail(); @@ -674,27 +683,37 @@ const createEvent = async ( const updateEvent = async ( credential: Credential, calEvent: CalendarEvent, - noMail: boolean | null = false + noMail: boolean | null = false, + bookingRefUid: string | null ): Promise => { const parser: CalEventParser = new CalEventParser(calEvent); - const newUid: string = parser.getUid(); + const uid = parser.getUid(); const richEvent: CalendarEvent = parser.asRichEventPlain(); let success = true; - const updateResult = - credential && calEvent.uid + const updatedResult = + credential && bookingRefUid ? await calendars([credential])[0] - .updateEvent(calEvent.uid, richEvent) + .updateEvent(bookingRefUid, richEvent) .catch((e) => { log.error("updateEvent failed", e, calEvent); success = false; + return undefined; }) : null; + if (!updatedResult) { + return { + type: credential.type, + success, + uid, + originalEvent: calEvent, + }; + } + if (!noMail) { - const emailEvent = { ...calEvent, uid: newUid }; - const organizerMail = new EventOrganizerRescheduledMail(emailEvent); + const organizerMail = new EventOrganizerRescheduledMail(calEvent); try { await organizerMail.sendEmail(); } catch (e) { @@ -705,8 +724,8 @@ const updateEvent = async ( return { type: credential.type, success, - uid: newUid, - updatedEvent: updateResult, + uid, + updatedEvent: updatedResult, originalEvent: calEvent, }; }; diff --git a/lib/events/EventManager.ts b/lib/events/EventManager.ts index e0be3109..8a442385 100644 --- a/lib/events/EventManager.ts +++ b/lib/events/EventManager.ts @@ -79,7 +79,7 @@ export default class EventManager { * @param event */ public async create(event: Ensure): Promise { - let evt = EventManager.processLocation(event); + const evt = EventManager.processLocation(event); const isDedicated = evt.location ? EventManager.isDedicatedIntegration(evt.location) : null; // First, create all calendar events. If this is a dedicated integration event, don't send a mail right here. @@ -88,7 +88,7 @@ export default class EventManager { if (isDedicated) { const result = await this.createVideoEvent(evt); if (result.videoCallData) { - evt = { ...evt, videoCallData: result.videoCallData }; + evt.videoCallData = result.videoCallData; } results.push(result); } else { @@ -126,17 +126,20 @@ export default class EventManager { * * @param event */ - public async update(event: Ensure): Promise { - let evt = EventManager.processLocation(event); + public async update( + event: Ensure, + rescheduleUid: string + ): Promise { + const evt = EventManager.processLocation(event); - if (!evt.uid) { - throw new Error("You called eventManager.update without an `uid`. This should never happen."); + if (!rescheduleUid) { + throw new Error("You called eventManager.update without an `rescheduleUid`. This should never happen."); } // Get details of existing booking. const booking = await prisma.booking.findFirst({ where: { - uid: evt.uid, + uid: rescheduleUid, }, select: { id: true, @@ -164,7 +167,7 @@ export default class EventManager { if (isDedicated) { const result = await this.updateVideoEvent(evt, booking); if (result.videoCallData) { - evt = { ...evt, videoCallData: result.videoCallData }; + evt.videoCallData = result.videoCallData; } results.push(result); } else { @@ -182,15 +185,11 @@ export default class EventManager { }, }); - let bookingDeletes = null; - - if (evt.uid) { - bookingDeletes = prisma.booking.delete({ - where: { - uid: evt.uid, - }, - }); - } + const bookingDeletes = prisma.booking.delete({ + where: { + id: booking.id, + }, + }); // Wait for all deletions to be applied. await Promise.all([bookingReferenceDeletes, attendeeDeletes, bookingDeletes]); @@ -275,8 +274,7 @@ export default class EventManager { const bookingRefUid = booking ? booking.references.filter((ref) => ref.type === credential.type)[0]?.uid : null; - const evt = { ...event, uid: bookingRefUid }; - return updateEvent(credential, evt, noMail); + return updateEvent(credential, event, noMail, bookingRefUid); }); } @@ -292,10 +290,10 @@ export default class EventManager { if (credential) { const bookingRef = booking ? booking.references.filter((ref) => ref.type === credential.type)[0] : null; - const evt = { ...event, uid: bookingRef?.uid }; - return updateMeeting(credential, evt).then((returnVal: EventResult) => { + const bookingRefUid = bookingRef ? bookingRef.uid : null; + return updateMeeting(credential, event, bookingRefUid).then((returnVal: EventResult) => { // Some video integrations, such as Zoom, don't return any data about the booking when updating it. - if (returnVal.videoCallData == undefined) { + if (returnVal.videoCallData === undefined) { returnVal.videoCallData = EventManager.bookingReferenceToVideoCallData(bookingRef); } return returnVal; @@ -441,15 +439,16 @@ export default class EventManager { metadata.conferenceData = results[0].createdEvent?.conferenceData; metadata.entryPoints = results[0].createdEvent?.entryPoints; } - const emailEvent = { ...event, additionInformation: metadata }; + + event.additionInformation = metadata; let attendeeMail; switch (type) { case "reschedule": - attendeeMail = new EventAttendeeRescheduledMail(emailEvent); + attendeeMail = new EventAttendeeRescheduledMail(event); break; case "new": - attendeeMail = new EventAttendeeMail(emailEvent); + attendeeMail = new EventAttendeeMail(event); break; } try { diff --git a/lib/videoClient.ts b/lib/videoClient.ts index ac9dc8eb..647a663f 100644 --- a/lib/videoClient.ts +++ b/lib/videoClient.ts @@ -116,10 +116,11 @@ const createMeeting = async ( entryPoints: [entryPoint], }; - const emailEvent = { ...calEvent, uid, additionInformation, videoCallData }; + calEvent.additionInformation = additionInformation; + calEvent.videoCallData = videoCallData; try { - const organizerMail = new VideoEventOrganizerMail(emailEvent); + const organizerMail = new VideoEventOrganizerMail(calEvent); await organizerMail.sendEmail(); } catch (e) { console.error("organizerMail.sendEmail failed", e); @@ -127,7 +128,7 @@ const createMeeting = async ( if (!createdMeeting || !createdMeeting.disableConfirmationEmail) { try { - const attendeeMail = new VideoEventAttendeeMail(emailEvent); + const attendeeMail = new VideoEventAttendeeMail(calEvent); await attendeeMail.sendEmail(); } catch (e) { console.error("attendeeMail.sendEmail failed", e); @@ -144,8 +145,12 @@ const createMeeting = async ( }; }; -const updateMeeting = async (credential: Credential, calEvent: CalendarEvent): Promise => { - const newUid: string = translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL)); +const updateMeeting = async ( + credential: Credential, + calEvent: CalendarEvent, + bookingRefUid: string | null +): Promise => { + const uid: string = translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL)); if (!credential) { throw new Error( @@ -153,31 +158,29 @@ const updateMeeting = async (credential: Credential, calEvent: CalendarEvent): P ); } - if (!calEvent.uid) { - throw new Error("You can't update an meeting without it's UID."); - } - let success = true; const [firstVideoAdapter] = getVideoAdapters([credential]); - const updatedMeeting = await firstVideoAdapter.updateMeeting(calEvent.uid, calEvent).catch((e) => { - log.error("updateMeeting failed", e, calEvent); - success = false; - }); + const updatedMeeting = + credential && bookingRefUid + ? await firstVideoAdapter.updateMeeting(bookingRefUid, calEvent).catch((e) => { + log.error("updateMeeting failed", e, calEvent); + success = false; + return undefined; + }) + : undefined; if (!updatedMeeting) { return { type: credential.type, success, - uid: calEvent.uid, + uid, originalEvent: calEvent, }; } - const emailEvent = { ...calEvent, uid: newUid }; - try { - const organizerMail = new EventOrganizerRescheduledMail(emailEvent); + const organizerMail = new EventOrganizerRescheduledMail(calEvent); await organizerMail.sendEmail(); } catch (e) { console.error("organizerMail.sendEmail failed", e); @@ -185,7 +188,7 @@ const updateMeeting = async (credential: Credential, calEvent: CalendarEvent): P if (!updatedMeeting.disableConfirmationEmail) { try { - const attendeeMail = new EventAttendeeRescheduledMail(emailEvent); + const attendeeMail = new EventAttendeeRescheduledMail(calEvent); await attendeeMail.sendEmail(); } catch (e) { console.error("attendeeMail.sendEmail failed", e); @@ -195,7 +198,7 @@ const updateMeeting = async (credential: Credential, calEvent: CalendarEvent): P return { type: credential.type, success, - uid: newUid, + uid, updatedEvent: updatedMeeting, originalEvent: calEvent, }; diff --git a/pages/api/book/event.ts b/pages/api/book/event.ts index 22204345..f498a8a4 100644 --- a/pages/api/book/event.ts +++ b/pages/api/book/event.ts @@ -439,8 +439,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) if (rescheduleUid) { // Use EventManager to conditionally use all needed integrations. - const eventManagerCalendarEvent = { ...evt, uid: rescheduleUid }; - const updateResults = await eventManager.update(eventManagerCalendarEvent); + const updateResults = await eventManager.update(evt, rescheduleUid); results = updateResults.results; referencesToCreate = updateResults.referencesToCreate; @@ -473,7 +472,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } if (eventType.requiresConfirmation && !rescheduleUid) { - await new EventOrganizerRequestMail({ ...evt, uid }).sendEmail(); + await new EventOrganizerRequestMail(evt).sendEmail(); } if (typeof eventType.price === "number" && eventType.price > 0) { diff --git a/playwright/integrations.test.ts b/playwright/integrations.test.ts index dbe280c3..8ea3ffec 100644 --- a/playwright/integrations.test.ts +++ b/playwright/integrations.test.ts @@ -67,6 +67,7 @@ describe("webhooks", () => { } body.payload.organizer.timeZone = dynamic; body.payload.uid = dynamic; + body.payload.additionInformation = dynamic; // if we change the shape of our webhooks, we can simply update this by clicking `u` // console.log("BODY", body); @@ -74,6 +75,7 @@ describe("webhooks", () => { Object { "createdAt": "[redacted/dynamic]", "payload": Object { + "additionInformation": "[redacted/dynamic]", "attendees": Array [ Object { "email": "test@example.com",