diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index bb72f5600d8385..12526877e5d522 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -1,6 +1,5 @@ import type { App, DestinationCalendar, EventTypeCustomInput } from "@prisma/client"; import { Prisma } from "@prisma/client"; -import type { IncomingMessage } from "http"; import { isValidPhoneNumber } from "libphonenumber-js"; // eslint-disable-next-line no-restricted-imports import { cloneDeep } from "lodash"; @@ -41,7 +40,6 @@ import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/ import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; import { handleWebhookTrigger } from "@calcom/features/bookings/lib/handleWebhookTrigger"; import { isEventTypeLoggingEnabled } from "@calcom/features/bookings/lib/isEventTypeLoggingEnabled"; -import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; import { allowDisablingAttendeeConfirmationEmails, allowDisablingHostConfirmationEmails, @@ -81,7 +79,6 @@ import { getPiiFreeCalendarEvent, getPiiFreeEventType, getPiiFreeUser } from "@c import { safeStringify } from "@calcom/lib/safeStringify"; import { checkBookingLimits, checkDurationLimits, getLuckyUser } from "@calcom/lib/server"; import { getTranslation } from "@calcom/lib/server/i18n"; -import { UserRepository } from "@calcom/lib/server/repository/user"; import { slugify } from "@calcom/lib/slugify"; import { updateWebUser as syncServicesUpdateWebUser } from "@calcom/lib/sync/SyncServiceManager"; import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat"; @@ -110,6 +107,7 @@ import { checkForConflicts } from "./conflictChecker/checkForConflicts"; import { getAllCredentials } from "./getAllCredentialsForUsersOnEvent/getAllCredentials"; import { refreshCredentials } from "./getAllCredentialsForUsersOnEvent/refreshCredentials"; import getBookingDataSchema from "./getBookingDataSchema"; +import { loadUsers } from "./handleNewBooking/loadUsers"; import handleSeats from "./handleSeats/handleSeats"; import type { BookingSeat } from "./handleSeats/types"; @@ -292,40 +290,6 @@ type IsFixedAwareUser = User & { priority?: number; }; -const loadUsers = async (eventType: NewBookingEventType, dynamicUserList: string[], req: IncomingMessage) => { - try { - if (!eventType.id) { - if (!Array.isArray(dynamicUserList) || dynamicUserList.length === 0) { - throw new Error("dynamicUserList is not properly defined or empty."); - } - const { isValidOrgDomain, currentOrgDomain } = orgDomainConfig(req); - const users = await findUsersByUsername({ - usernameList: dynamicUserList, - orgSlug: isValidOrgDomain ? currentOrgDomain : null, - }); - return users; - } - const hosts = eventType.hosts || []; - - if (!Array.isArray(hosts)) { - throw new Error("eventType.hosts is not properly defined."); - } - - const users = hosts.map(({ user, isFixed, priority }) => ({ - ...user, - isFixed, - priority, - })); - - return users.length ? users : eventType.users; - } catch (error) { - if (error instanceof HttpError || error instanceof Prisma.PrismaClientKnownRequestError) { - throw new HttpError({ statusCode: 400, message: error.message }); - } - throw new HttpError({ statusCode: 500, message: "Unable to load users" }); - } -}; - export async function ensureAvailableUsers( eventType: Awaited> & { users: IsFixedAwareUser[]; @@ -2650,40 +2614,3 @@ function handleCustomInputs( } }); } - -/** - * This method is mostly same as the one in UserRepository but it includes a lot more relations which are specific requirement here - * TODO: Figure out how to keep it in UserRepository and use it here - */ -export const findUsersByUsername = async ({ - usernameList, - orgSlug, -}: { - orgSlug: string | null; - usernameList: string[]; -}) => { - log.debug("findUsersByUsername", { usernameList, orgSlug }); - const { where, profiles } = await UserRepository._getWhereClauseForFindingUsersByUsername({ - orgSlug, - usernameList, - }); - return ( - await prisma.user.findMany({ - where, - select: { - ...userSelect.select, - credentials: { - select: credentialForCalendarServiceSelect, - }, - metadata: true, - }, - }) - ).map((user) => { - const profile = profiles?.find((profile) => profile.user.id === user.id) ?? null; - return { - ...user, - organizationId: profile?.organizationId ?? null, - profile, - }; - }); -}; diff --git a/packages/features/bookings/lib/handleNewBooking/loadUsers.ts b/packages/features/bookings/lib/handleNewBooking/loadUsers.ts new file mode 100644 index 00000000000000..7e60d290a14555 --- /dev/null +++ b/packages/features/bookings/lib/handleNewBooking/loadUsers.ts @@ -0,0 +1,87 @@ +import { Prisma } from "@prisma/client"; +import type { IncomingMessage } from "http"; + +import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; +import { HttpError } from "@calcom/lib/http-error"; +import logger from "@calcom/lib/logger"; +import { UserRepository } from "@calcom/lib/server/repository/user"; +import prisma, { userSelect } from "@calcom/prisma"; +import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential"; + +import type { NewBookingEventType } from "../handleNewBooking"; + +const log = logger.getSubLogger({ prefix: ["[loadUsers]:handleNewBooking "] }); + +type EventType = Pick; + +export const loadUsers = async (eventType: EventType, dynamicUserList: string[], req: IncomingMessage) => { + try { + const { currentOrgDomain } = orgDomainConfig(req); + + return eventType.id + ? await loadUsersByEventType(eventType) + : await loadDynamicUsers(dynamicUserList, currentOrgDomain); + } catch (error) { + if (error instanceof HttpError || error instanceof Prisma.PrismaClientKnownRequestError) { + throw new HttpError({ statusCode: 400, message: error.message }); + } + throw new HttpError({ statusCode: 500, message: "Unable to load users" }); + } +}; + +const loadUsersByEventType = async (eventType: EventType): Promise => { + const hosts = eventType.hosts || []; + const users = hosts.map(({ user, isFixed, priority }) => ({ + ...user, + isFixed, + priority, + })); + return users.length ? users : eventType.users; +}; + +const loadDynamicUsers = async (dynamicUserList: string[], currentOrgDomain: string | null) => { + if (!Array.isArray(dynamicUserList) || dynamicUserList.length === 0) { + throw new Error("dynamicUserList is not properly defined or empty."); + } + return findUsersByUsername({ + usernameList: dynamicUserList, + orgSlug: !!currentOrgDomain ? currentOrgDomain : null, + }); +}; + +/** + * This method is mostly same as the one in UserRepository but it includes a lot more relations which are specific requirement here + * TODO: Figure out how to keep it in UserRepository and use it here + */ +export const findUsersByUsername = async ({ + usernameList, + orgSlug, +}: { + orgSlug: string | null; + usernameList: string[]; +}) => { + log.debug("findUsersByUsername", { usernameList, orgSlug }); + const { where, profiles } = await UserRepository._getWhereClauseForFindingUsersByUsername({ + orgSlug, + usernameList, + }); + return ( + await prisma.user.findMany({ + where, + select: { + ...userSelect.select, + credentials: { + select: credentialForCalendarServiceSelect, + }, + metadata: true, + }, + }) + ).map((user) => { + const profile = profiles?.find((profile) => profile.user.id === user.id) ?? null; + return { + ...user, + organizationId: profile?.organizationId ?? null, + profile, + }; + }); +};