hotfix: zoom location on emails (#1153)
* fix: zoom location on emails * test: fix Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
parent
43fa4f6497
commit
559ccb8ca7
5 changed files with 80 additions and 58 deletions
|
@ -642,6 +642,15 @@ const createEvent = async (
|
||||||
})
|
})
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
if (!creationResult) {
|
||||||
|
return {
|
||||||
|
type: credential.type,
|
||||||
|
success,
|
||||||
|
uid,
|
||||||
|
originalEvent: calEvent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const metadata: AdditionInformation = {};
|
const metadata: AdditionInformation = {};
|
||||||
if (creationResult) {
|
if (creationResult) {
|
||||||
// TODO: Handle created event metadata more elegantly
|
// TODO: Handle created event metadata more elegantly
|
||||||
|
@ -650,10 +659,10 @@ const createEvent = async (
|
||||||
metadata.entryPoints = creationResult.entryPoints;
|
metadata.entryPoints = creationResult.entryPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emailEvent = { ...calEvent, additionInformation: metadata };
|
calEvent.additionInformation = metadata;
|
||||||
|
|
||||||
if (!noMail) {
|
if (!noMail) {
|
||||||
const organizerMail = new EventOrganizerMail(emailEvent);
|
const organizerMail = new EventOrganizerMail(calEvent);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await organizerMail.sendEmail();
|
await organizerMail.sendEmail();
|
||||||
|
@ -674,27 +683,37 @@ const createEvent = async (
|
||||||
const updateEvent = async (
|
const updateEvent = async (
|
||||||
credential: Credential,
|
credential: Credential,
|
||||||
calEvent: CalendarEvent,
|
calEvent: CalendarEvent,
|
||||||
noMail: boolean | null = false
|
noMail: boolean | null = false,
|
||||||
|
bookingRefUid: string | null
|
||||||
): Promise<EventResult> => {
|
): Promise<EventResult> => {
|
||||||
const parser: CalEventParser = new CalEventParser(calEvent);
|
const parser: CalEventParser = new CalEventParser(calEvent);
|
||||||
const newUid: string = parser.getUid();
|
const uid = parser.getUid();
|
||||||
const richEvent: CalendarEvent = parser.asRichEventPlain();
|
const richEvent: CalendarEvent = parser.asRichEventPlain();
|
||||||
|
|
||||||
let success = true;
|
let success = true;
|
||||||
|
|
||||||
const updateResult =
|
const updatedResult =
|
||||||
credential && calEvent.uid
|
credential && bookingRefUid
|
||||||
? await calendars([credential])[0]
|
? await calendars([credential])[0]
|
||||||
.updateEvent(calEvent.uid, richEvent)
|
.updateEvent(bookingRefUid, richEvent)
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
log.error("updateEvent failed", e, calEvent);
|
log.error("updateEvent failed", e, calEvent);
|
||||||
success = false;
|
success = false;
|
||||||
|
return undefined;
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
if (!updatedResult) {
|
||||||
|
return {
|
||||||
|
type: credential.type,
|
||||||
|
success,
|
||||||
|
uid,
|
||||||
|
originalEvent: calEvent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!noMail) {
|
if (!noMail) {
|
||||||
const emailEvent = { ...calEvent, uid: newUid };
|
const organizerMail = new EventOrganizerRescheduledMail(calEvent);
|
||||||
const organizerMail = new EventOrganizerRescheduledMail(emailEvent);
|
|
||||||
try {
|
try {
|
||||||
await organizerMail.sendEmail();
|
await organizerMail.sendEmail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -705,8 +724,8 @@ const updateEvent = async (
|
||||||
return {
|
return {
|
||||||
type: credential.type,
|
type: credential.type,
|
||||||
success,
|
success,
|
||||||
uid: newUid,
|
uid,
|
||||||
updatedEvent: updateResult,
|
updatedEvent: updatedResult,
|
||||||
originalEvent: calEvent,
|
originalEvent: calEvent,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,7 +79,7 @@ export default class EventManager {
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
public async create(event: Ensure<CalendarEvent, "language">): Promise<CreateUpdateResult> {
|
public async create(event: Ensure<CalendarEvent, "language">): Promise<CreateUpdateResult> {
|
||||||
let evt = EventManager.processLocation(event);
|
const evt = EventManager.processLocation(event);
|
||||||
const isDedicated = evt.location ? EventManager.isDedicatedIntegration(evt.location) : null;
|
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.
|
// 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) {
|
if (isDedicated) {
|
||||||
const result = await this.createVideoEvent(evt);
|
const result = await this.createVideoEvent(evt);
|
||||||
if (result.videoCallData) {
|
if (result.videoCallData) {
|
||||||
evt = { ...evt, videoCallData: result.videoCallData };
|
evt.videoCallData = result.videoCallData;
|
||||||
}
|
}
|
||||||
results.push(result);
|
results.push(result);
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,17 +126,20 @@ export default class EventManager {
|
||||||
*
|
*
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
public async update(event: Ensure<CalendarEvent, "uid">): Promise<CreateUpdateResult> {
|
public async update(
|
||||||
let evt = EventManager.processLocation(event);
|
event: Ensure<CalendarEvent, "language">,
|
||||||
|
rescheduleUid: string
|
||||||
|
): Promise<CreateUpdateResult> {
|
||||||
|
const evt = EventManager.processLocation(event);
|
||||||
|
|
||||||
if (!evt.uid) {
|
if (!rescheduleUid) {
|
||||||
throw new Error("You called eventManager.update without an `uid`. This should never happen.");
|
throw new Error("You called eventManager.update without an `rescheduleUid`. This should never happen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get details of existing booking.
|
// Get details of existing booking.
|
||||||
const booking = await prisma.booking.findFirst({
|
const booking = await prisma.booking.findFirst({
|
||||||
where: {
|
where: {
|
||||||
uid: evt.uid,
|
uid: rescheduleUid,
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
|
@ -164,7 +167,7 @@ export default class EventManager {
|
||||||
if (isDedicated) {
|
if (isDedicated) {
|
||||||
const result = await this.updateVideoEvent(evt, booking);
|
const result = await this.updateVideoEvent(evt, booking);
|
||||||
if (result.videoCallData) {
|
if (result.videoCallData) {
|
||||||
evt = { ...evt, videoCallData: result.videoCallData };
|
evt.videoCallData = result.videoCallData;
|
||||||
}
|
}
|
||||||
results.push(result);
|
results.push(result);
|
||||||
} else {
|
} else {
|
||||||
|
@ -182,15 +185,11 @@ export default class EventManager {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let bookingDeletes = null;
|
const bookingDeletes = prisma.booking.delete({
|
||||||
|
where: {
|
||||||
if (evt.uid) {
|
id: booking.id,
|
||||||
bookingDeletes = prisma.booking.delete({
|
},
|
||||||
where: {
|
});
|
||||||
uid: evt.uid,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for all deletions to be applied.
|
// Wait for all deletions to be applied.
|
||||||
await Promise.all([bookingReferenceDeletes, attendeeDeletes, bookingDeletes]);
|
await Promise.all([bookingReferenceDeletes, attendeeDeletes, bookingDeletes]);
|
||||||
|
@ -275,8 +274,7 @@ export default class EventManager {
|
||||||
const bookingRefUid = booking
|
const bookingRefUid = booking
|
||||||
? booking.references.filter((ref) => ref.type === credential.type)[0]?.uid
|
? booking.references.filter((ref) => ref.type === credential.type)[0]?.uid
|
||||||
: null;
|
: null;
|
||||||
const evt = { ...event, uid: bookingRefUid };
|
return updateEvent(credential, event, noMail, bookingRefUid);
|
||||||
return updateEvent(credential, evt, noMail);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,10 +290,10 @@ export default class EventManager {
|
||||||
|
|
||||||
if (credential) {
|
if (credential) {
|
||||||
const bookingRef = booking ? booking.references.filter((ref) => ref.type === credential.type)[0] : null;
|
const bookingRef = booking ? booking.references.filter((ref) => ref.type === credential.type)[0] : null;
|
||||||
const evt = { ...event, uid: bookingRef?.uid };
|
const bookingRefUid = bookingRef ? bookingRef.uid : null;
|
||||||
return updateMeeting(credential, evt).then((returnVal: EventResult) => {
|
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.
|
// 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);
|
returnVal.videoCallData = EventManager.bookingReferenceToVideoCallData(bookingRef);
|
||||||
}
|
}
|
||||||
return returnVal;
|
return returnVal;
|
||||||
|
@ -441,15 +439,16 @@ export default class EventManager {
|
||||||
metadata.conferenceData = results[0].createdEvent?.conferenceData;
|
metadata.conferenceData = results[0].createdEvent?.conferenceData;
|
||||||
metadata.entryPoints = results[0].createdEvent?.entryPoints;
|
metadata.entryPoints = results[0].createdEvent?.entryPoints;
|
||||||
}
|
}
|
||||||
const emailEvent = { ...event, additionInformation: metadata };
|
|
||||||
|
event.additionInformation = metadata;
|
||||||
|
|
||||||
let attendeeMail;
|
let attendeeMail;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "reschedule":
|
case "reschedule":
|
||||||
attendeeMail = new EventAttendeeRescheduledMail(emailEvent);
|
attendeeMail = new EventAttendeeRescheduledMail(event);
|
||||||
break;
|
break;
|
||||||
case "new":
|
case "new":
|
||||||
attendeeMail = new EventAttendeeMail(emailEvent);
|
attendeeMail = new EventAttendeeMail(event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -116,10 +116,11 @@ const createMeeting = async (
|
||||||
entryPoints: [entryPoint],
|
entryPoints: [entryPoint],
|
||||||
};
|
};
|
||||||
|
|
||||||
const emailEvent = { ...calEvent, uid, additionInformation, videoCallData };
|
calEvent.additionInformation = additionInformation;
|
||||||
|
calEvent.videoCallData = videoCallData;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const organizerMail = new VideoEventOrganizerMail(emailEvent);
|
const organizerMail = new VideoEventOrganizerMail(calEvent);
|
||||||
await organizerMail.sendEmail();
|
await organizerMail.sendEmail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("organizerMail.sendEmail failed", e);
|
console.error("organizerMail.sendEmail failed", e);
|
||||||
|
@ -127,7 +128,7 @@ const createMeeting = async (
|
||||||
|
|
||||||
if (!createdMeeting || !createdMeeting.disableConfirmationEmail) {
|
if (!createdMeeting || !createdMeeting.disableConfirmationEmail) {
|
||||||
try {
|
try {
|
||||||
const attendeeMail = new VideoEventAttendeeMail(emailEvent);
|
const attendeeMail = new VideoEventAttendeeMail(calEvent);
|
||||||
await attendeeMail.sendEmail();
|
await attendeeMail.sendEmail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("attendeeMail.sendEmail failed", e);
|
console.error("attendeeMail.sendEmail failed", e);
|
||||||
|
@ -144,8 +145,12 @@ const createMeeting = async (
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMeeting = async (credential: Credential, calEvent: CalendarEvent): Promise<EventResult> => {
|
const updateMeeting = async (
|
||||||
const newUid: string = translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL));
|
credential: Credential,
|
||||||
|
calEvent: CalendarEvent,
|
||||||
|
bookingRefUid: string | null
|
||||||
|
): Promise<EventResult> => {
|
||||||
|
const uid: string = translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL));
|
||||||
|
|
||||||
if (!credential) {
|
if (!credential) {
|
||||||
throw new Error(
|
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;
|
let success = true;
|
||||||
|
|
||||||
const [firstVideoAdapter] = getVideoAdapters([credential]);
|
const [firstVideoAdapter] = getVideoAdapters([credential]);
|
||||||
const updatedMeeting = await firstVideoAdapter.updateMeeting(calEvent.uid, calEvent).catch((e) => {
|
const updatedMeeting =
|
||||||
log.error("updateMeeting failed", e, calEvent);
|
credential && bookingRefUid
|
||||||
success = false;
|
? await firstVideoAdapter.updateMeeting(bookingRefUid, calEvent).catch((e) => {
|
||||||
});
|
log.error("updateMeeting failed", e, calEvent);
|
||||||
|
success = false;
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
if (!updatedMeeting) {
|
if (!updatedMeeting) {
|
||||||
return {
|
return {
|
||||||
type: credential.type,
|
type: credential.type,
|
||||||
success,
|
success,
|
||||||
uid: calEvent.uid,
|
uid,
|
||||||
originalEvent: calEvent,
|
originalEvent: calEvent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const emailEvent = { ...calEvent, uid: newUid };
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const organizerMail = new EventOrganizerRescheduledMail(emailEvent);
|
const organizerMail = new EventOrganizerRescheduledMail(calEvent);
|
||||||
await organizerMail.sendEmail();
|
await organizerMail.sendEmail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("organizerMail.sendEmail failed", e);
|
console.error("organizerMail.sendEmail failed", e);
|
||||||
|
@ -185,7 +188,7 @@ const updateMeeting = async (credential: Credential, calEvent: CalendarEvent): P
|
||||||
|
|
||||||
if (!updatedMeeting.disableConfirmationEmail) {
|
if (!updatedMeeting.disableConfirmationEmail) {
|
||||||
try {
|
try {
|
||||||
const attendeeMail = new EventAttendeeRescheduledMail(emailEvent);
|
const attendeeMail = new EventAttendeeRescheduledMail(calEvent);
|
||||||
await attendeeMail.sendEmail();
|
await attendeeMail.sendEmail();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("attendeeMail.sendEmail failed", e);
|
console.error("attendeeMail.sendEmail failed", e);
|
||||||
|
@ -195,7 +198,7 @@ const updateMeeting = async (credential: Credential, calEvent: CalendarEvent): P
|
||||||
return {
|
return {
|
||||||
type: credential.type,
|
type: credential.type,
|
||||||
success,
|
success,
|
||||||
uid: newUid,
|
uid,
|
||||||
updatedEvent: updatedMeeting,
|
updatedEvent: updatedMeeting,
|
||||||
originalEvent: calEvent,
|
originalEvent: calEvent,
|
||||||
};
|
};
|
||||||
|
|
|
@ -439,8 +439,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
|
|
||||||
if (rescheduleUid) {
|
if (rescheduleUid) {
|
||||||
// Use EventManager to conditionally use all needed integrations.
|
// Use EventManager to conditionally use all needed integrations.
|
||||||
const eventManagerCalendarEvent = { ...evt, uid: rescheduleUid };
|
const updateResults = await eventManager.update(evt, rescheduleUid);
|
||||||
const updateResults = await eventManager.update(eventManagerCalendarEvent);
|
|
||||||
|
|
||||||
results = updateResults.results;
|
results = updateResults.results;
|
||||||
referencesToCreate = updateResults.referencesToCreate;
|
referencesToCreate = updateResults.referencesToCreate;
|
||||||
|
@ -473,7 +472,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType.requiresConfirmation && !rescheduleUid) {
|
if (eventType.requiresConfirmation && !rescheduleUid) {
|
||||||
await new EventOrganizerRequestMail({ ...evt, uid }).sendEmail();
|
await new EventOrganizerRequestMail(evt).sendEmail();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof eventType.price === "number" && eventType.price > 0) {
|
if (typeof eventType.price === "number" && eventType.price > 0) {
|
||||||
|
|
|
@ -67,6 +67,7 @@ describe("webhooks", () => {
|
||||||
}
|
}
|
||||||
body.payload.organizer.timeZone = dynamic;
|
body.payload.organizer.timeZone = dynamic;
|
||||||
body.payload.uid = 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`
|
// if we change the shape of our webhooks, we can simply update this by clicking `u`
|
||||||
// console.log("BODY", body);
|
// console.log("BODY", body);
|
||||||
|
@ -74,6 +75,7 @@ describe("webhooks", () => {
|
||||||
Object {
|
Object {
|
||||||
"createdAt": "[redacted/dynamic]",
|
"createdAt": "[redacted/dynamic]",
|
||||||
"payload": Object {
|
"payload": Object {
|
||||||
|
"additionInformation": "[redacted/dynamic]",
|
||||||
"attendees": Array [
|
"attendees": Array [
|
||||||
Object {
|
Object {
|
||||||
"email": "test@example.com",
|
"email": "test@example.com",
|
||||||
|
|
Loading…
Reference in a new issue