fix: bookings made via API don't include the specified location (#15067)

* fix booking via api not picking default location when unspecified

* test:add tests for default location of event for booking

* fix:failing tests

---------

Co-authored-by: Shaik-Sirajuddin <sirajudddinshaik30@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
This commit is contained in:
Shaik-Sirajuddin
2024-06-11 17:06:43 +00:00
committed by GitHub
co-authored by Shaik-Sirajuddin Alex van Andel
parent 5e09281974
commit 219b13d053
4 changed files with 289 additions and 5 deletions
@@ -30,7 +30,7 @@ export function getMockRequestDataForBooking({
responses: {
email: string;
name: string;
location: { optionValue: ""; value: string };
location?: { optionValue: ""; value: string };
smsReminderNumber?: string;
};
};
@@ -1453,15 +1453,26 @@ async function handler(
const isManagedEventType = !!eventType.parentId;
// If location passed is empty , use default location of event
// If location of event is not set , use host default
if (locationBodyString.trim().length == 0) {
if (eventType.locations.length > 0) {
locationBodyString = eventType.locations[0].type;
} else {
locationBodyString = OrganizerDefaultConferencingAppType;
}
}
// use host default
if ((isManagedEventType || isTeamEventType) && locationBodyString === OrganizerDefaultConferencingAppType) {
if (locationBodyString == OrganizerDefaultConferencingAppType) {
const metadataParseResult = userMetadataSchema.safeParse(organizerUser.metadata);
const organizerMetadata = metadataParseResult.success ? metadataParseResult.data : undefined;
if (organizerMetadata?.defaultConferencingApp?.appSlug) {
const app = getAppFromSlug(organizerMetadata?.defaultConferencingApp?.appSlug);
locationBodyString = app?.appData?.location?.type || locationBodyString;
organizerOrFirstDynamicGroupMemberDefaultLocationUrl =
organizerMetadata?.defaultConferencingApp?.appLink;
if (isManagedEventType || isTeamEventType) {
organizerOrFirstDynamicGroupMemberDefaultLocationUrl =
organizerMetadata?.defaultConferencingApp?.appLink;
}
} else {
locationBodyString = "integrations:daily";
}
@@ -1601,6 +1612,12 @@ async function handler(
organizerEmail = eventType.secondaryEmail.email;
}
//udpate cal event responses with latest location value , later used by webhook
if (reqBody.calEventResponses)
reqBody.calEventResponses["location"].value = {
value: platformBookingLocation ?? bookingLocation,
optionValue: "",
};
let evt: CalendarEvent = {
bookerUrl,
type: eventType.slug,
@@ -1010,6 +1010,273 @@ describe("handleNewBooking", () => {
);
});
describe("Event's first location should be used when location is unspecied", () => {
test(
`should create a successful booking with right location app when event has location option as video client`,
async ({ emails }) => {
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
const booker = getBooker({
email: "booker@example.com",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getZoomAppCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
const { req } = createMockNextJsRequest({
method: "POST",
body: getMockRequestDataForBooking({
data: {
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
},
},
}),
});
const scenarioData = getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 30,
length: 30,
users: [
{
id: 101,
},
],
locations: [
{
type: BookingLocations.ZoomVideo,
},
],
},
],
organizer,
apps: [TestData.apps["zoomvideo"]],
});
mockSuccessfulVideoMeetingCreation({
metadataLookupKey: "zoomvideo",
});
await createBookingScenario(scenarioData);
const createdBooking = await handleNewBooking(req);
expect(createdBooking).toContain({
location: BookingLocations.ZoomVideo,
});
const iCalUID = expectICalUIDAsString(createdBooking.iCalUID);
expectSuccessfulBookingCreationEmails({
booking: {
uid: createdBooking.uid!,
},
booker,
organizer,
emails,
iCalUID,
});
expectBookingCreatedWebhookToHaveBeenFired({
booker,
organizer,
location: BookingLocations.ZoomVideo,
subscriberUrl: "http://my-webhook.example.com",
videoCallUrl: "http://mock-zoomvideo.example.com",
});
},
timeout
);
test(
`should create a successful booking with right location when event's location is not a conferencing app
`,
//test with inPerson event type
async ({ emails }) => {
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
const booker = getBooker({
email: "booker@example.com",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [],
selectedCalendars: [TestData.selectedCalendars.google],
});
const { req } = createMockNextJsRequest({
method: "POST",
body: getMockRequestDataForBooking({
data: {
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
},
},
}),
});
const scenarioData = getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 30,
length: 30,
users: [
{
id: 101,
},
],
locations: [{ type: "inPerson", address: "Seoul" }],
},
],
organizer,
apps: [TestData.apps["daily-video"]],
});
await createBookingScenario(scenarioData);
const createdBooking = await handleNewBooking(req);
expect(createdBooking).toContain({
location: "Seoul",
});
const iCalUID = expectICalUIDAsString(createdBooking.iCalUID);
expectSuccessfulBookingCreationEmails({
booking: {
uid: createdBooking.uid!,
},
booker,
organizer,
emails,
iCalUID,
});
expectBookingCreatedWebhookToHaveBeenFired({
booker,
organizer,
location: "Seoul",
subscriberUrl: "http://my-webhook.example.com",
});
},
timeout
);
test(
`should create a successful booking with organizer default conferencing app when event's location is not set`,
async ({ emails }) => {
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
const booker = getBooker({
email: "booker@example.com",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getZoomAppCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
metadata: {
defaultConferencingApp: {
appSlug: "zoom",
},
},
});
const { req } = createMockNextJsRequest({
method: "POST",
body: getMockRequestDataForBooking({
data: {
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
},
},
}),
});
const scenarioData = getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 30,
length: 30,
users: [
{
id: 101,
},
],
},
],
organizer,
apps: [TestData.apps["zoomvideo"], TestData.apps["daily-video"]],
});
mockSuccessfulVideoMeetingCreation({
metadataLookupKey: "zoomvideo",
});
await createBookingScenario(scenarioData);
const createdBooking = await handleNewBooking(req);
expect(createdBooking).toContain({
location: BookingLocations.ZoomVideo,
});
const iCalUID = expectICalUIDAsString(createdBooking.iCalUID);
expectSuccessfulBookingCreationEmails({
booking: {
uid: createdBooking.uid!,
},
booker,
organizer,
emails,
iCalUID,
});
expectBookingCreatedWebhookToHaveBeenFired({
booker,
organizer,
location: BookingLocations.ZoomVideo,
subscriberUrl: "http://my-webhook.example.com",
videoCallUrl: "http://mock-zoomvideo.example.com",
});
},
timeout
);
});
describe("Video Meeting Creation", () => {
test(
`should create a successful booking with Zoom if used`,
@@ -1287,7 +1287,7 @@ describe("handleNewBooking", () => {
expectBookingCreatedWebhookToHaveBeenFired({
booker,
organizer,
location: OrganizerDefaultConferencingAppType,
location: BookingLocations.CalVideo,
subscriberUrl: "http://my-webhook.example.com",
videoCallUrl: `${WEBAPP_URL}/video/${createdBooking.uid}`,
});