Fixes bug when changing the location of a booking (#3585)
* use correct booking * delete calendar event and update booking reference * use middleware to get booking * updating event instad of deleting and creating a new one * fix issue with google hangout link * remove unsed imports * Apply suggestions from code review * Update bookings.tsx Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: Omar López <zomars@me.com> Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
CarinaWolli
Omar López
Syed Ali Shahbaz
Peer Richelsen
kodiakhq[bot]
parent
f036f0fb64
commit
88384192f8
@@ -191,26 +191,62 @@ export default class GoogleCalendarService implements Calendar {
|
||||
payload["location"] = getLocation(event);
|
||||
}
|
||||
|
||||
if (event.conferenceData && event.location === "integrations:google:meet") {
|
||||
payload["conferenceData"] = event.conferenceData;
|
||||
}
|
||||
|
||||
const calendar = google.calendar({
|
||||
version: "v3",
|
||||
auth: myGoogleAuth,
|
||||
});
|
||||
|
||||
const selectedCalendar = externalCalendarId
|
||||
? externalCalendarId
|
||||
: event.destinationCalendar?.externalId;
|
||||
|
||||
calendar.events.update(
|
||||
{
|
||||
auth: myGoogleAuth,
|
||||
calendarId: externalCalendarId ? externalCalendarId : event.destinationCalendar?.externalId,
|
||||
calendarId: selectedCalendar,
|
||||
eventId: uid,
|
||||
sendNotifications: true,
|
||||
sendUpdates: "all",
|
||||
requestBody: payload,
|
||||
conferenceDataVersion: 1,
|
||||
},
|
||||
function (err, event) {
|
||||
function (err, evt) {
|
||||
if (err) {
|
||||
console.error("There was an error contacting google calendar service: ", err);
|
||||
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(event?.data);
|
||||
|
||||
if (evt && evt.data.id && evt.data.hangoutLink && event.location === "integrations:google:meet") {
|
||||
calendar.events.patch({
|
||||
// Update the same event but this time we know the hangout link
|
||||
calendarId: selectedCalendar,
|
||||
auth: myGoogleAuth,
|
||||
eventId: evt.data.id || "",
|
||||
requestBody: {
|
||||
description: getRichDescription({
|
||||
...event,
|
||||
additionalInformation: { hangoutLink: evt.data.hangoutLink },
|
||||
}),
|
||||
},
|
||||
});
|
||||
return resolve({
|
||||
uid: "",
|
||||
...evt.data,
|
||||
id: evt.data.id || "",
|
||||
additionalInfo: {
|
||||
hangoutLink: evt.data.hangoutLink || "",
|
||||
},
|
||||
type: "google_calendar",
|
||||
password: "",
|
||||
url: "",
|
||||
});
|
||||
}
|
||||
return resolve(evt?.data);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -156,6 +156,42 @@ export default class EventManager {
|
||||
};
|
||||
}
|
||||
|
||||
public async updateLocation(event: CalendarEvent, booking: PartialBooking): Promise<CreateUpdateResult> {
|
||||
const evt = processLocation(event);
|
||||
const isDedicated = evt.location ? isDedicatedIntegration(evt.location) : null;
|
||||
|
||||
const results: Array<EventResult<Exclude<Event, AdditionalInformation>>> = [];
|
||||
// If and only if event type is a dedicated meeting, create a dedicated video meeting.
|
||||
if (isDedicated) {
|
||||
const result = await this.createVideoEvent(evt);
|
||||
if (result.createdEvent) {
|
||||
evt.videoCallData = result.createdEvent;
|
||||
}
|
||||
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
// Update the calendar event with the proper video call data
|
||||
results.push(...(await this.updateAllCalendarEvents(evt, booking)));
|
||||
|
||||
const referencesToCreate = results.map((result) => {
|
||||
return {
|
||||
type: result.type,
|
||||
uid: result.createdEvent?.id?.toString() ?? "",
|
||||
meetingId: result.createdEvent?.id?.toString(),
|
||||
meetingPassword: result.createdEvent?.password,
|
||||
meetingUrl: result.createdEvent?.url,
|
||||
externalCalendarId: evt.destinationCalendar?.externalId,
|
||||
credentialId: evt.destinationCalendar?.credentialId,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
results,
|
||||
referencesToCreate,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a calendarEvent and a rescheduleUid and updates the event that has the
|
||||
* given uid using the data delivered in the given CalendarEvent.
|
||||
|
||||
@@ -23,36 +23,44 @@ export const bookingsRouter = createProtectedRouter()
|
||||
.middleware(async ({ ctx, rawInput, next }) => {
|
||||
// Endpoints that just read the logged in user's data - like 'list' don't necessary have any input
|
||||
if (!rawInput) return next({ ctx: { ...ctx, booking: null } });
|
||||
|
||||
const webhookIdAndEventTypeId = commonBookingSchema.safeParse(rawInput);
|
||||
if (!webhookIdAndEventTypeId.success) throw new TRPCError({ code: "PARSE_ERROR" });
|
||||
|
||||
const { bookingId } = webhookIdAndEventTypeId.data;
|
||||
const booking = await ctx.prisma.booking.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
/* If user is organizer */
|
||||
{ userId: ctx.user.id, id: bookingId },
|
||||
/* Or part of a collective booking */
|
||||
id: bookingId,
|
||||
AND: [
|
||||
{
|
||||
eventType: {
|
||||
schedulingType: SchedulingType.COLLECTIVE,
|
||||
users: {
|
||||
some: {
|
||||
id: ctx.user.id,
|
||||
OR: [
|
||||
/* If user is organizer */
|
||||
{ userId: ctx.user.id },
|
||||
/* Or part of a collective booking */
|
||||
{
|
||||
eventType: {
|
||||
schedulingType: SchedulingType.COLLECTIVE,
|
||||
users: {
|
||||
some: {
|
||||
id: ctx.user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
include: {
|
||||
attendees: true,
|
||||
eventType: true,
|
||||
user: {
|
||||
include: { destinationCalendar: true },
|
||||
},
|
||||
destinationCalendar: true,
|
||||
references: true,
|
||||
user: {
|
||||
include: {
|
||||
destinationCalendar: true,
|
||||
credentials: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return next({ ctx: { ...ctx, booking } });
|
||||
@@ -73,11 +81,6 @@ export const bookingsRouter = createProtectedRouter()
|
||||
const { booking } = ctx;
|
||||
|
||||
try {
|
||||
await ctx.prisma.booking.update({
|
||||
where: { id: bookingId },
|
||||
data: { location },
|
||||
});
|
||||
|
||||
const organizer = await ctx.prisma.user.findFirst({
|
||||
where: {
|
||||
id: booking.userId || 0,
|
||||
@@ -127,10 +130,9 @@ export const bookingsRouter = createProtectedRouter()
|
||||
};
|
||||
|
||||
const eventManager = new EventManager(ctx.user);
|
||||
// TODO: This is causing duplicate calendar events when updating location
|
||||
const scheduleResult = await eventManager.create(evt);
|
||||
|
||||
const results = scheduleResult.results;
|
||||
const updatedResult = await eventManager.updateLocation(evt, booking);
|
||||
const results = updatedResult.results;
|
||||
if (results.length > 0 && results.every((res) => !res.success)) {
|
||||
const error = {
|
||||
errorCode: "BookingUpdateLocationFailed",
|
||||
@@ -138,11 +140,23 @@ export const bookingsRouter = createProtectedRouter()
|
||||
};
|
||||
logger.error(`Booking ${ctx.user.username} failed`, error, results);
|
||||
} else {
|
||||
await ctx.prisma.booking.update({
|
||||
where: {
|
||||
id: bookingId,
|
||||
},
|
||||
data: {
|
||||
location,
|
||||
references: {
|
||||
create: updatedResult.referencesToCreate,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const metadata: AdditionalInformation = {};
|
||||
if (results.length) {
|
||||
metadata.hangoutLink = results[0].createdEvent?.hangoutLink;
|
||||
metadata.conferenceData = results[0].createdEvent?.conferenceData;
|
||||
metadata.entryPoints = results[0].createdEvent?.entryPoints;
|
||||
metadata.hangoutLink = results[0].updatedEvent?.hangoutLink;
|
||||
metadata.conferenceData = results[0].updatedEvent?.conferenceData;
|
||||
metadata.entryPoints = results[0].updatedEvent?.entryPoints;
|
||||
}
|
||||
try {
|
||||
await sendLocationChangeEmails({ ...evt, additionalInformation: metadata });
|
||||
|
||||
Reference in New Issue
Block a user