Revert "fix: invalid Cancelled / Rescheduled downstream calendar block (#14700)" (#14800)

This reverts commit 0306ad737f.
This commit is contained in:
Alex van Andel
2024-04-29 13:31:02 -03:00
committed by GitHub
parent ad0b8a668c
commit 22425bb693
4 changed files with 114 additions and 54 deletions
+3 -2
View File
@@ -630,7 +630,8 @@ describe("getSchedule", () => {
...TestData.users.example,
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
},
],
bookings: [
@@ -642,7 +643,7 @@ describe("getSchedule", () => {
status: "ACCEPTED" as BookingStatus,
},
],
// apps: [TestData.apps.googleCalendar],
apps: [TestData.apps.googleCalendar],
};
await createBookingScenario(scenarioData);
+37 -44
View File
@@ -144,50 +144,43 @@ export async function getBusyTimes(params: {
});
const bookingSeatCountMap: { [x: string]: number } = {};
// Only take bookings as source of truth when there are no connected calendars
// this is because cancellations downstream aren't reflected in our Booking database.
// TODO: Reflect downstream cancellations in our Booking database and use Booking as
// source of truth.
const busyTimes =
credentials?.length > 0
? []
: bookings.reduce(
(aggregate: EventBusyDetails[], { id, startTime, endTime, eventType, title, ...rest }) => {
if (rest._count?.seatsReferences) {
const bookedAt = `${dayjs(startTime).utc().format()}<>${dayjs(endTime).utc().format()}`;
bookingSeatCountMap[bookedAt] = bookingSeatCountMap[bookedAt] || 0;
bookingSeatCountMap[bookedAt]++;
// Seat references on the current event are non-blocking until the event is fully booked.
if (
// there are still seats available.
bookingSeatCountMap[bookedAt] < (eventType?.seatsPerTimeSlot || 1) &&
// and this is the seated event, other event types should be blocked.
eventTypeId === eventType?.id
) {
// then we do not add the booking to the busyTimes.
return aggregate;
}
// if it does get blocked at this point; we remove the bookingSeatCountMap entry
// doing this allows using the map later to remove the ranges from calendar busy times.
delete bookingSeatCountMap[bookedAt];
}
if (rest.uid === rescheduleUid) {
return aggregate;
}
aggregate.push({
start: dayjs(startTime)
.subtract((eventType?.beforeEventBuffer || 0) + (afterEventBuffer || 0), "minute")
.toDate(),
end: dayjs(endTime)
.add((eventType?.afterEventBuffer || 0) + (beforeEventBuffer || 0), "minute")
.toDate(),
title,
source: `eventType-${eventType?.id}-booking-${id}`,
});
return aggregate;
},
[]
);
const busyTimes = bookings.reduce(
(aggregate: EventBusyDetails[], { id, startTime, endTime, eventType, title, ...rest }) => {
if (rest._count?.seatsReferences) {
const bookedAt = `${dayjs(startTime).utc().format()}<>${dayjs(endTime).utc().format()}`;
bookingSeatCountMap[bookedAt] = bookingSeatCountMap[bookedAt] || 0;
bookingSeatCountMap[bookedAt]++;
// Seat references on the current event are non-blocking until the event is fully booked.
if (
// there are still seats available.
bookingSeatCountMap[bookedAt] < (eventType?.seatsPerTimeSlot || 1) &&
// and this is the seated event, other event types should be blocked.
eventTypeId === eventType?.id
) {
// then we do not add the booking to the busyTimes.
return aggregate;
}
// if it does get blocked at this point; we remove the bookingSeatCountMap entry
// doing this allows using the map later to remove the ranges from calendar busy times.
delete bookingSeatCountMap[bookedAt];
}
if (rest.uid === rescheduleUid) {
return aggregate;
}
aggregate.push({
start: dayjs(startTime)
.subtract((eventType?.beforeEventBuffer || 0) + (afterEventBuffer || 0), "minute")
.toDate(),
end: dayjs(endTime)
.add((eventType?.afterEventBuffer || 0) + (beforeEventBuffer || 0), "minute")
.toDate(),
title,
source: `eventType-${eventType?.id}-booking-${id}`,
});
return aggregate;
},
[]
);
logger.debug(
`Busy Time from Cal Bookings ${JSON.stringify({
@@ -2433,7 +2433,13 @@ describe("handleNewBooking", () => {
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: "google_calendar",
externalId: "organizer@google-calendar.com",
primaryEmail: organizerOtherEmail,
},
});
await createBookingScenario(
@@ -2449,10 +2455,15 @@ describe("handleNewBooking", () => {
id: 101,
},
],
destinationCalendar: {
integration: "google_calendar",
externalId: "event-type-1@google-calendar.com",
primaryEmail: organizerDestinationCalendarEmailOnEventType,
},
},
],
organizer,
apps: [TestData.apps["daily-video"]],
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
@@ -2513,10 +2524,36 @@ describe("handleNewBooking", () => {
meetingPassword: "MOCK_PASS",
meetingUrl: "http://mock-dailyvideo.example.com/meeting-1",
},
{
type: appStoreMetadata.googlecalendar.type,
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
meetingPassword: "MOCK_PASSWORD",
meetingUrl: "https://UNUSED_URL",
},
],
iCalUID: createdBooking.iCalUID,
});
expectSuccessfulCalendarEventCreationInCalendar(calendarMock, {
calendarId: "event-type-1@google-calendar.com",
videoCallUrl: "http://mock-dailyvideo.example.com/meeting-1",
});
const iCalUID = expectICalUIDAsString(createdBooking.iCalUID);
expectSuccessfulBookingCreationEmails({
booking: {
uid: createdBooking.uid!,
urlOrigin: WEBSITE_URL,
},
booker,
organizer,
emails,
iCalUID,
destinationEmail: organizerDestinationCalendarEmailOnEventType,
});
await expect(async () => await handleNewBooking(req)).rejects.toThrowError(
ErrorCode.NoAvailableUsersFound
);
@@ -266,8 +266,12 @@ describe("handleNewBooking", () => {
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [],
selectedCalendars: [],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: "google_calendar",
externalId: "organizer@google-calendar.com",
},
});
const recurrence = getRecurrence({
@@ -299,6 +303,10 @@ describe("handleNewBooking", () => {
id: 101,
},
],
destinationCalendar: {
integration: "google_calendar",
externalId: "event-type-1@google-calendar.com",
},
},
],
bookings: [
@@ -312,7 +320,7 @@ describe("handleNewBooking", () => {
},
],
organizer,
apps: [TestData.apps["daily-video"]],
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
@@ -829,7 +837,12 @@ describe("handleNewBooking", () => {
],
// Has morning shift with some overlap with morning shift
schedules: [TestData.schedules.IstMorningShift],
credentials: [],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: TestData.apps["google-calendar"].type,
externalId: "organizer@google-calendar.com",
},
});
const otherTeamMembers = [
@@ -843,7 +856,12 @@ describe("handleNewBooking", () => {
id: 102,
// Has Evening shift
schedules: [TestData.schedules.IstMorningShift],
credentials: [],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: TestData.apps["google-calendar"].type,
externalId: "other-team-member-1@google-calendar.com",
},
},
];
@@ -883,6 +901,10 @@ describe("handleNewBooking", () => {
isFixed: true,
},
],
destinationCalendar: {
integration: "google_calendar",
externalId: "event-type-1@google-calendar.com",
},
},
],
bookings: [
@@ -901,7 +923,7 @@ describe("handleNewBooking", () => {
],
organizer,
usersApartFromOrganizer: otherTeamMembers,
apps: [TestData.apps["daily-video"]],
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
@@ -914,6 +936,13 @@ describe("handleNewBooking", () => {
},
});
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
create: {
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
},
});
const recurringCountInRequest = 4;
const mockBookingData1 = getMockRequestDataForBooking({
data: {