fix: Error during booking when default app is a Static Link Video App and Event has Organizer default location selected. (#9734)

pull/9763/head
Hariom Balhara 2023-06-23 22:34:34 +05:30 committed by GitHub
parent 0b704b9ed4
commit b731dfd421
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 12 deletions

View File

@ -50,6 +50,11 @@ export const DailyLocationType = "integrations:daily";
export const MeetLocationType = "integrations:google:meet"; export const MeetLocationType = "integrations:google:meet";
/**
* This isn't an actual location app type. It is a special value that informs to use the Organizer's default conferencing app during booking
*/
export const OrganizerDefaultConferencingAppType = "conferencing";
export enum DefaultEventLocationTypeEnum { export enum DefaultEventLocationTypeEnum {
/** /**
* Booker Address * Booker Address
@ -68,6 +73,7 @@ export enum DefaultEventLocationTypeEnum {
*/ */
UserPhone = "userPhone", UserPhone = "userPhone",
Link = "link", Link = "link",
// Same as `OrganizerDefaultConferencingAppType`
Conferencing = "conferencing", Conferencing = "conferencing",
} }
@ -324,10 +330,11 @@ export const getEventLocationWithType = (
return location; return location;
}; };
// FIXME: It assumes that type would be sent mostly now. If just in case a value and not type is sent(when old frontend sends requests to new backend), below forEach won't be able to find a match and thus bookingLocation would still be correct equal to reqBody.location /**
// We must handle the situation where frontend doesn't send us the value because it doesn't have it(displayLocationPublicly not set) * It converts a static link based video location type(e.g. integrations:campfire_video) to it's value (e.g. https://campfire.to/my_link) set in the eventType.
// But we want to store the actual location(except dynamic URL based location type) so that Emails, Calendars pick the value only. * If the type provided is already a value(when displayLocationPublicly is on), it would just return that.
// TODO: We must store both type as well as value so that we know the type of data that we are having. Is it an address or a phone number? This is to be done post v2.0 * For, dynamic link based video location apps, it doesn't do anything.
*/
export const getLocationValueForDB = ( export const getLocationValueForDB = (
bookingLocationTypeOrValue: EventLocationType["type"], bookingLocationTypeOrValue: EventLocationType["type"],
eventLocations: LocationObject[] eventLocations: LocationObject[]

View File

@ -23,9 +23,17 @@ const getVideoAdapters = async (withCredentials: CredentialPayload[]): Promise<V
for (const cred of withCredentials) { for (const cred of withCredentials) {
const appName = cred.type.split("_").join(""); // Transform `zoom_video` to `zoomvideo`; const appName = cred.type.split("_").join(""); // Transform `zoom_video` to `zoomvideo`;
const app = await appStore[appName as keyof typeof appStore](); const appImportFn = appStore[appName as keyof typeof appStore];
if (app && "lib" in app && "VideoApiAdapter" in app.lib) { // Static Link Video Apps don't exist in packages/app-store/index.ts(it's manually maintained at the moment) and they aren't needed there anyway.
const app = appImportFn ? await appImportFn() : null;
if (!app) {
log.error(`Couldn't get adapter for ${appName}`);
continue;
}
if ("lib" in app && "VideoApiAdapter" in app.lib) {
const makeVideoApiAdapter = app.lib.VideoApiAdapter as VideoApiAdapterFactory; const makeVideoApiAdapter = app.lib.VideoApiAdapter as VideoApiAdapterFactory;
const videoAdapter = makeVideoApiAdapter(cred); const videoAdapter = makeVideoApiAdapter(cred);
videoAdapters.push(videoAdapter); videoAdapters.push(videoAdapter);

View File

@ -11,6 +11,7 @@ import z from "zod";
import { getCalendar } from "@calcom/app-store/_utils/getCalendar"; import { getCalendar } from "@calcom/app-store/_utils/getCalendar";
import { metadata as GoogleMeetMetadata } from "@calcom/app-store/googlevideo/_metadata"; import { metadata as GoogleMeetMetadata } from "@calcom/app-store/googlevideo/_metadata";
import type { LocationObject } from "@calcom/app-store/locations"; import type { LocationObject } from "@calcom/app-store/locations";
import { OrganizerDefaultConferencingAppType } from "@calcom/app-store/locations";
import { getLocationValueForDB } from "@calcom/app-store/locations"; import { getLocationValueForDB } from "@calcom/app-store/locations";
import { MeetLocationType } from "@calcom/app-store/locations"; import { MeetLocationType } from "@calcom/app-store/locations";
import type { EventTypeAppsList } from "@calcom/app-store/utils"; import type { EventTypeAppsList } from "@calcom/app-store/utils";
@ -761,7 +762,9 @@ async function handler(
})); }));
let locationBodyString = location; let locationBodyString = location;
let defaultLocationUrl = undefined;
// TODO: It's definition should be moved to getLocationValueForDb
let organizerOrFirstDynamicGroupMemberDefaultLocationUrl = undefined;
if (dynamicUserList.length > 1) { if (dynamicUserList.length > 1) {
users = users.sort((a, b) => { users = users.sort((a, b) => {
@ -771,7 +774,8 @@ async function handler(
}); });
const firstUsersMetadata = userMetadataSchema.parse(users[0].metadata); const firstUsersMetadata = userMetadataSchema.parse(users[0].metadata);
locationBodyString = firstUsersMetadata?.defaultConferencingApp?.appLink || locationBodyString; locationBodyString = firstUsersMetadata?.defaultConferencingApp?.appLink || locationBodyString;
defaultLocationUrl = firstUsersMetadata?.defaultConferencingApp?.appLink; organizerOrFirstDynamicGroupMemberDefaultLocationUrl =
firstUsersMetadata?.defaultConferencingApp?.appLink;
} }
if ( if (
@ -838,14 +842,16 @@ async function handler(
const [organizerUser] = users; const [organizerUser] = users;
const tOrganizer = await getTranslation(organizerUser?.locale ?? "en", "common"); const tOrganizer = await getTranslation(organizerUser?.locale ?? "en", "common");
// use host default // use host default
if (isTeamEventType && locationBodyString === "conferencing") { if (isTeamEventType && locationBodyString === OrganizerDefaultConferencingAppType) {
const metadataParseResult = userMetadataSchema.safeParse(organizerUser.metadata); const metadataParseResult = userMetadataSchema.safeParse(organizerUser.metadata);
const organizerMetadata = metadataParseResult.success ? metadataParseResult.data : undefined; const organizerMetadata = metadataParseResult.success ? metadataParseResult.data : undefined;
if (organizerMetadata) { if (organizerMetadata) {
const app = getAppFromSlug(organizerMetadata?.defaultConferencingApp?.appSlug); const app = getAppFromSlug(organizerMetadata?.defaultConferencingApp?.appSlug);
locationBodyString = app?.appData?.location?.type || locationBodyString; locationBodyString = app?.appData?.location?.type || locationBodyString;
defaultLocationUrl = organizerMetadata?.defaultConferencingApp?.appLink; organizerOrFirstDynamicGroupMemberDefaultLocationUrl =
organizerMetadata?.defaultConferencingApp?.appLink;
} else { } else {
locationBodyString = ""; locationBodyString = "";
} }
@ -877,7 +883,11 @@ async function handler(
const seed = `${organizerUser.username}:${dayjs(reqBody.start).utc().format()}:${new Date().getTime()}`; const seed = `${organizerUser.username}:${dayjs(reqBody.start).utc().format()}:${new Date().getTime()}`;
const uid = translator.fromUUID(uuidv5(seed, uuidv5.URL)); const uid = translator.fromUUID(uuidv5(seed, uuidv5.URL));
const bookingLocation = getLocationValueForDB(locationBodyString, eventType.locations); // For static link based video apps, it would have the static URL value instead of it's type(e.g. integrations:campfire_video)
// This ensures that createMeeting isn't called for static video apps as bookingLocation becomes just a regular value for them.
const bookingLocation = organizerOrFirstDynamicGroupMemberDefaultLocationUrl
? organizerOrFirstDynamicGroupMemberDefaultLocationUrl
: getLocationValueForDB(locationBodyString, eventType.locations);
const customInputs = getCustomInputsResponses(reqBody, eventType.customInputs); const customInputs = getCustomInputsResponses(reqBody, eventType.customInputs);
const teamMemberPromises = const teamMemberPromises =
@ -2026,7 +2036,8 @@ async function handler(
metadata.conferenceData = results[0].createdEvent?.conferenceData; metadata.conferenceData = results[0].createdEvent?.conferenceData;
metadata.entryPoints = results[0].createdEvent?.entryPoints; metadata.entryPoints = results[0].createdEvent?.entryPoints;
handleAppsStatus(results, booking); handleAppsStatus(results, booking);
videoCallUrl = metadata.hangoutLink || defaultLocationUrl || videoCallUrl; videoCallUrl =
metadata.hangoutLink || organizerOrFirstDynamicGroupMemberDefaultLocationUrl || videoCallUrl;
} }
if (noEmail !== true) { if (noEmail !== true) {
let isHostConfirmationEmailsDisabled = false; let isHostConfirmationEmailsDisabled = false;