diff --git a/lib/calendarClient.ts b/lib/calendarClient.ts index f9c4dfd5a0..bfe0f472d6 100644 --- a/lib/calendarClient.ts +++ b/lib/calendarClient.ts @@ -509,7 +509,11 @@ const listCalendars = (withCredentials) => results.reduce((acc, calendars) => acc.concat(calendars), []) ); -const createEvent = async (credential: Credential, calEvent: CalendarEvent): Promise => { +const createEvent = async ( + credential: Credential, + calEvent: CalendarEvent, + noMail = false +): Promise => { const parser: CalEventParser = new CalEventParser(calEvent); const uid: string = parser.getUid(); const richEvent: CalendarEvent = parser.asRichEvent(); @@ -529,29 +533,31 @@ const createEvent = async (credential: Credential, calEvent: CalendarEvent): Pro const maybeEntryPoints = creationResult?.entryPoints; const maybeConferenceData = creationResult?.conferenceData; - const organizerMail = new EventOrganizerMail(calEvent, uid, { - hangoutLink: maybeHangoutLink, - conferenceData: maybeConferenceData, - entryPoints: maybeEntryPoints, - }); + if (!noMail) { + const organizerMail = new EventOrganizerMail(calEvent, uid, { + hangoutLink: maybeHangoutLink, + conferenceData: maybeConferenceData, + entryPoints: maybeEntryPoints, + }); - const attendeeMail = new EventAttendeeMail(calEvent, uid, { - hangoutLink: maybeHangoutLink, - conferenceData: maybeConferenceData, - entryPoints: maybeEntryPoints, - }); + const attendeeMail = new EventAttendeeMail(calEvent, uid, { + hangoutLink: maybeHangoutLink, + conferenceData: maybeConferenceData, + entryPoints: maybeEntryPoints, + }); - try { - await organizerMail.sendEmail(); - } catch (e) { - console.error("organizerMail.sendEmail failed", e); - } - - if (!creationResult || !creationResult.disableConfirmationEmail) { try { - await attendeeMail.sendEmail(); + await organizerMail.sendEmail(); } catch (e) { - console.error("attendeeMail.sendEmail failed", e); + console.error("organizerMail.sendEmail failed", e); + } + + if (!creationResult || !creationResult.disableConfirmationEmail) { + try { + await attendeeMail.sendEmail(); + } catch (e) { + console.error("attendeeMail.sendEmail failed", e); + } } } @@ -567,7 +573,8 @@ const createEvent = async (credential: Credential, calEvent: CalendarEvent): Pro const updateEvent = async ( credential: Credential, uidToUpdate: string, - calEvent: CalendarEvent + calEvent: CalendarEvent, + noMail: false ): Promise => { const parser: CalEventParser = new CalEventParser(calEvent); const newUid: string = parser.getUid(); @@ -584,19 +591,21 @@ const updateEvent = async ( }) : null; - const organizerMail = new EventOrganizerRescheduledMail(calEvent, newUid); - const attendeeMail = new EventAttendeeRescheduledMail(calEvent, newUid); - try { - await organizerMail.sendEmail(); - } catch (e) { - console.error("organizerMail.sendEmail failed", e); - } - - if (!updateResult || !updateResult.disableConfirmationEmail) { + if (!noMail) { + const organizerMail = new EventOrganizerRescheduledMail(calEvent, newUid); + const attendeeMail = new EventAttendeeRescheduledMail(calEvent, newUid); try { - await attendeeMail.sendEmail(); + await organizerMail.sendEmail(); } catch (e) { - console.error("attendeeMail.sendEmail failed", e); + console.error("organizerMail.sendEmail failed", e); + } + + if (!updateResult || !updateResult.disableConfirmationEmail) { + try { + await attendeeMail.sendEmail(); + } catch (e) { + console.error("attendeeMail.sendEmail failed", e); + } } } diff --git a/lib/events/EventManager.ts b/lib/events/EventManager.ts index 5fbc58d487..6c254c3c2b 100644 --- a/lib/events/EventManager.ts +++ b/lib/events/EventManager.ts @@ -33,11 +33,13 @@ export default class EventManager { } public async create(event: CalendarEvent): Promise> { - // First, create all calendar events. - const results: Array = await this.createAllCalendarEvents(event); + const isVideo = EventManager.isIntegration(event.location); + + // First, create all calendar events. If this is a video event, don't send a mail right here. + const results: Array = await this.createAllCalendarEvents(event, isVideo); // If and only if event type is a video meeting, create a video meeting as well. - if (EventManager.isIntegration(event.location)) { + if (isVideo) { results.push(await this.createVideoEvent(event)); } @@ -45,11 +47,13 @@ export default class EventManager { } public async update(event: CalendarEvent, booking: PartialBooking): Promise> { - // First, update all calendar events. - const results: Array = await this.updateAllCalendarEvents(event, booking); + const isVideo = EventManager.isIntegration(event.location); + + // First, update all calendar events. If this is a video event, don't send a mail right here. + const results: Array = await this.updateAllCalendarEvents(event, booking, isVideo); // If and only if event type is a video meeting, update the video meeting as well. - if (EventManager.isIntegration(event.location)) { + if (isVideo) { results.push(await this.updateVideoEvent(event, booking)); } @@ -58,13 +62,17 @@ export default class EventManager { /** * Creates event entries for all calendar integrations given in the credentials. + * When noMail is true, no mails will be sent. This is used when the event is + * a video meeting because then the mail containing the video credentials will be + * more important than the mails created for these bare calendar events. * * @param event + * @param noMail * @private */ - private createAllCalendarEvents(event: CalendarEvent): Promise> { + private createAllCalendarEvents(event: CalendarEvent, noMail: boolean): Promise> { return async.mapLimit(this.calendarCredentials, 5, async (credential: Credential) => { - return createEvent(credential, event); + return createEvent(credential, event, noMail); }); } @@ -89,16 +97,35 @@ export default class EventManager { } } + /** + * Updates the event entries for all calendar integrations given in the credentials. + * When noMail is true, no mails will be sent. This is used when the event is + * a video meeting because then the mail containing the video credentials will be + * more important than the mails created for these bare calendar events. + * + * @param event + * @param booking + * @param noMail + * @private + */ private updateAllCalendarEvents( event: CalendarEvent, - booking: PartialBooking + booking: PartialBooking, + noMail: boolean ): Promise> { return async.mapLimit(this.calendarCredentials, 5, async (credential) => { const bookingRefUid = booking.references.filter((ref) => ref.type === credential.type)[0]?.uid; - return updateEvent(credential, bookingRefUid, event); + return updateEvent(credential, bookingRefUid, event, noMail); }); } + /** + * Updates a single video event. + * + * @param event + * @param booking + * @private + */ private updateVideoEvent(event: CalendarEvent, booking: PartialBooking) { const credential = this.getVideoCredential(event); diff --git a/pages/api/book/[user].ts b/pages/api/book/[user].ts index fef3fac871..e5863cb554 100644 --- a/pages/api/book/[user].ts +++ b/pages/api/book/[user].ts @@ -356,7 +356,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await Promise.all([bookingReferenceDeletes, attendeeDeletes, bookingDeletes]); } else { // Use EventManager to conditionally use all needed integrations. - const results: Array = await eventManager.create(evt); + results = await eventManager.create(evt); if (results.length > 0 && results.every((res) => !res.success)) { const error = {