refactor: move functions to separate files (#15590)

* refactor: move functions to separate files

* chore: remove inline function

* chore: type error

* fix: type error

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
This commit is contained in:
Udit Takkar
2024-06-27 22:05:11 +00:00
committed by GitHub
co-authored by Keith Williams
parent 3e10e2db36
commit a52f7efe88
9 changed files with 397 additions and 319 deletions
@@ -1,6 +1,5 @@
import type { App, DestinationCalendar, EventTypeCustomInput } from "@prisma/client";
import { Prisma } from "@prisma/client";
import { isValidPhoneNumber } from "libphonenumber-js";
// eslint-disable-next-line no-restricted-imports
import { cloneDeep } from "lodash";
import type { NextApiRequest } from "next";
@@ -8,11 +7,10 @@ import type { TFunction } from "next-i18next";
import short, { uuid } from "short-uuid";
import type { Logger } from "tslog";
import { v5 as uuidv5 } from "uuid";
import z from "zod";
import type z from "zod";
import processExternalId from "@calcom/app-store/_utils/calendars/processExternalId";
import { metadata as GoogleMeetMetadata } from "@calcom/app-store/googlevideo/_metadata";
import type { LocationObject } from "@calcom/app-store/locations";
import {
MeetLocationType,
OrganizerDefaultConferencingAppType,
@@ -55,12 +53,7 @@ import {
deleteWebhookScheduledTriggers,
scheduleTrigger,
} from "@calcom/features/webhooks/lib/scheduleTrigger";
import {
isPrismaObjOrUndefined,
parseBookingLimit,
parseDurationLimit,
parseRecurringEvent,
} from "@calcom/lib";
import { isPrismaObjOrUndefined, parseBookingLimit, parseDurationLimit } from "@calcom/lib";
import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser";
import { getUTCOffsetByTimezone } from "@calcom/lib/date-fns";
import { getDefaultEvent, getUsernameList } from "@calcom/lib/defaultEvents";
@@ -87,9 +80,7 @@ import type { BookingReference } from "@calcom/prisma/client";
import { BookingStatus, SchedulingType, WebhookTriggerEvents } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import {
EventTypeMetaDataSchema,
bookingCreateSchemaLegacyPropsForApi,
customInputSchema,
userMetadata as userMetadataSchema,
} from "@calcom/prisma/zod-utils";
import type {
@@ -107,6 +98,12 @@ import { checkForConflicts } from "./conflictChecker/checkForConflicts";
import { getAllCredentials } from "./getAllCredentialsForUsersOnEvent/getAllCredentials";
import { refreshCredentials } from "./getAllCredentialsForUsersOnEvent/refreshCredentials";
import getBookingDataSchema from "./getBookingDataSchema";
import { checkIfBookerEmailIsBlocked } from "./handleNewBooking/checkIfBookerEmailIsBlocked";
import { getEventTypesFromDB } from "./handleNewBooking/getEventTypesFromDB";
import type { getEventTypeResponse } from "./handleNewBooking/getEventTypesFromDB";
import { getRequiresConfirmationFlags } from "./handleNewBooking/getRequiresConfirmationFlags";
import { handleAppsStatus } from "./handleNewBooking/handleAppsStatus";
import { handleCustomInputs } from "./handleNewBooking/handleCustomInputs";
import { loadUsers } from "./handleNewBooking/loadUsers";
import handleSeats from "./handleSeats/handleSeats";
import type { BookingSeat } from "./handleSeats/types";
@@ -117,9 +114,7 @@ const log = logger.getSubLogger({ prefix: ["[api] book:user"] });
type User = Prisma.UserGetPayload<typeof userSelect>;
type BookingType = Prisma.PromiseReturnType<typeof getOriginalRescheduledBooking>;
export type Booking = Prisma.PromiseReturnType<typeof createBooking>;
export type NewBookingEventType =
| Awaited<ReturnType<typeof getDefaultEvent>>
| Awaited<ReturnType<typeof getEventTypesFromDB>>;
export type NewBookingEventType = Awaited<ReturnType<typeof getDefaultEvent>> | getEventTypeResponse;
// Work with Typescript to require reqBody.end
type ReqBodyWithoutEnd = z.infer<ReturnType<typeof getBookingDataSchema>>;
@@ -162,127 +157,6 @@ export interface IEventTypePaymentCredentialType {
key: Prisma.JsonValue;
}
export const getEventTypesFromDB = async (eventTypeId: number) => {
const eventType = await prisma.eventType.findUniqueOrThrow({
where: {
id: eventTypeId,
},
select: {
id: true,
customInputs: true,
disableGuests: true,
users: {
select: {
credentials: {
select: credentialForCalendarServiceSelect,
},
...userSelect.select,
},
},
slug: true,
team: {
select: {
id: true,
name: true,
parentId: true,
},
},
bookingFields: true,
title: true,
length: true,
eventName: true,
schedulingType: true,
description: true,
periodType: true,
periodStartDate: true,
periodEndDate: true,
periodDays: true,
periodCountCalendarDays: true,
lockTimeZoneToggleOnBookingPage: true,
requiresConfirmation: true,
requiresBookerEmailVerification: true,
minimumBookingNotice: true,
userId: true,
price: true,
currency: true,
metadata: true,
destinationCalendar: true,
hideCalendarNotes: true,
seatsPerTimeSlot: true,
recurringEvent: true,
seatsShowAttendees: true,
seatsShowAvailabilityCount: true,
bookingLimits: true,
durationLimits: true,
assignAllTeamMembers: true,
parentId: true,
useEventTypeDestinationCalendarEmail: true,
owner: {
select: {
hideBranding: true,
},
},
workflows: {
include: {
workflow: {
include: {
steps: true,
},
},
},
},
locations: true,
timeZone: true,
schedule: {
select: {
id: true,
availability: true,
timeZone: true,
},
},
hosts: {
select: {
isFixed: true,
priority: true,
user: {
select: {
credentials: {
select: credentialForCalendarServiceSelect,
},
...userSelect.select,
},
},
},
},
availability: {
select: {
date: true,
startTime: true,
endTime: true,
days: true,
},
},
secondaryEmailId: true,
secondaryEmail: {
select: {
id: true,
email: true,
},
},
},
});
return {
...eventType,
metadata: EventTypeMetaDataSchema.parse(eventType?.metadata || {}),
recurringEvent: parseRecurringEvent(eventType?.recurringEvent),
customInputs: customInputSchema.array().parse(eventType?.customInputs || []),
locations: (eventType?.locations ?? []) as LocationObject[],
bookingFields: getBookingFieldsWithSystemFields(eventType || {}),
isDynamic: false,
};
};
type IsFixedAwareUser = User & {
isFixed: boolean;
credentials: CredentialPayload[];
@@ -291,7 +165,7 @@ type IsFixedAwareUser = User & {
};
export async function ensureAvailableUsers(
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>> & {
eventType: getEventTypeResponse & {
users: IsFixedAwareUser[];
},
input: { dateFrom: string; dateTo: string; timeZone: string; originalRescheduledBooking?: BookingType },
@@ -479,7 +353,7 @@ export async function getBookingData<T extends z.ZodType>({
schema,
}: {
req: NextApiRequest;
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>>;
eventType: getEventTypeResponse;
schema: T;
}) {
const reqBody = await schema.parseAsync(req.body);
@@ -722,7 +596,7 @@ export function getCustomInputsResponses(
responses?: Record<string, object>;
customInputs?: z.infer<typeof bookingCreateSchemaLegacyPropsForApi>["customInputs"];
},
eventTypeCustomInputs: Awaited<ReturnType<typeof getEventTypesFromDB>>["customInputs"]
eventTypeCustomInputs: getEventTypeResponse["customInputs"]
) {
const customInputsResponses = {} as NonNullable<CalendarEvent["customInputs"]>;
if (reqBody.customInputs && (reqBody.customInputs.length || 0) > 0) {
@@ -777,43 +651,6 @@ export const createLoggerWithEventDetails = (
});
};
export function handleAppsStatus(
results: EventResult<AdditionalInformation>[],
booking: (Booking & { appsStatus?: AppsStatus[] }) | null,
reqAppsStatus: ReqAppsStatus
) {
// Taking care of apps status
const resultStatus: AppsStatus[] = results.map((app) => ({
appName: app.appName,
type: app.type,
success: app.success ? 1 : 0,
failures: !app.success ? 1 : 0,
errors: app.calError ? [app.calError] : [],
warnings: app.calWarnings,
}));
if (reqAppsStatus === undefined) {
if (booking !== null) {
booking.appsStatus = resultStatus;
}
return resultStatus;
}
// From down here we can assume reqAppsStatus is not undefined anymore
// Other status exist, so this is the last booking of a series,
// proceeding to prepare the info for the event
const calcAppsStatus = reqAppsStatus.concat(resultStatus).reduce((prev, curr) => {
if (prev[curr.type]) {
prev[curr.type].success += curr.success;
prev[curr.type].errors = prev[curr.type].errors.concat(curr.errors);
prev[curr.type].warnings = prev[curr.type].warnings?.concat(curr.warnings || []);
} else {
prev[curr.type] = curr;
}
return prev;
}, {} as { [key: string]: AppsStatus });
return Object.values(calcAppsStatus);
}
function getICalSequence(originalRescheduledBooking: BookingType | null) {
// If new booking set the sequence to 0
if (!originalRescheduledBooking) {
@@ -880,65 +717,6 @@ type BookingDataSchemaGetter =
| typeof getBookingDataSchema
| typeof import("@calcom/features/bookings/lib/getBookingDataSchemaForApi").default;
const checkIfBookerEmailIsBlocked = async ({
bookerEmail,
loggedInUserId,
}: {
bookerEmail: string;
loggedInUserId?: number;
}) => {
const baseEmail = extractBaseEmail(bookerEmail);
const blacklistedGuestEmails = process.env.BLACKLISTED_GUEST_EMAILS
? process.env.BLACKLISTED_GUEST_EMAILS.split(",")
: [];
const blacklistedEmail = blacklistedGuestEmails.find(
(guestEmail: string) => guestEmail.toLowerCase() === baseEmail.toLowerCase()
);
if (!blacklistedEmail) {
return false;
}
const user = await prisma.user.findFirst({
where: {
OR: [
{
email: baseEmail,
emailVerified: {
not: null,
},
},
{
secondaryEmails: {
some: {
email: baseEmail,
emailVerified: {
not: null,
},
},
},
},
],
},
select: {
id: true,
email: true,
},
});
if (!user) {
throw new HttpError({ statusCode: 403, message: "Cannot use this email to create the booking." });
}
if (user.id !== loggedInUserId) {
throw new HttpError({
statusCode: 403,
message: `Attendee email has been blocked. Make sure to login as ${bookerEmail} to use this email for creating a booking.`,
});
}
};
async function handler(
req: NextApiRequest & {
userId?: number | undefined;
@@ -1245,7 +1023,7 @@ async function handler(
//checks what users are available
if (isFirstSeat) {
const eventTypeWithUsers: Awaited<ReturnType<typeof getEventTypesFromDB>> & {
const eventTypeWithUsers: getEventTypeResponse & {
users: IsFixedAwareUser[];
} = {
...eventType,
@@ -2540,77 +2318,3 @@ function getVideoCallDetails({
return { videoCallUrl, metadata, updatedVideoEvent };
}
function getRequiresConfirmationFlags({
eventType,
bookingStartTime,
userId,
paymentAppData,
originalRescheduledBookingOrganizerId,
}: {
eventType: Pick<Awaited<ReturnType<typeof getEventTypesFromDB>>, "metadata" | "requiresConfirmation">;
bookingStartTime: string;
userId: number | undefined;
paymentAppData: { price: number };
originalRescheduledBookingOrganizerId: number | undefined;
}) {
let requiresConfirmation = eventType?.requiresConfirmation;
const rcThreshold = eventType?.metadata?.requiresConfirmationThreshold;
if (rcThreshold) {
if (dayjs(dayjs(bookingStartTime).utc().format()).diff(dayjs(), rcThreshold.unit) > rcThreshold.time) {
requiresConfirmation = false;
}
}
// If the user is not the owner of the event, new booking should be always pending.
// Otherwise, an owner rescheduling should be always accepted.
// Before comparing make sure that userId is set, otherwise undefined === undefined
const userReschedulingIsOwner = !!(userId && originalRescheduledBookingOrganizerId === userId);
const isConfirmedByDefault = (!requiresConfirmation && !paymentAppData.price) || userReschedulingIsOwner;
return {
/**
* Organizer of the booking is rescheduling
*/
userReschedulingIsOwner,
/**
* Booking won't need confirmation to be ACCEPTED
*/
isConfirmedByDefault,
};
}
function handleCustomInputs(
eventTypeCustomInputs: EventTypeCustomInput[],
reqCustomInputs: {
value: string | boolean;
label: string;
}[]
) {
eventTypeCustomInputs.forEach((etcInput) => {
if (etcInput.required) {
const input = reqCustomInputs.find((i) => i.label === etcInput.label);
if (etcInput.type === "BOOL") {
z.literal(true, {
errorMap: () => ({ message: `Missing ${etcInput.type} customInput: '${etcInput.label}'` }),
}).parse(input?.value);
} else if (etcInput.type === "PHONE") {
z.string({
errorMap: () => ({
message: `Missing ${etcInput.type} customInput: '${etcInput.label}'`,
}),
})
.refine((val) => isValidPhoneNumber(val), {
message: "Phone number is invalid",
})
.parse(input?.value);
} else {
// type: NUMBER are also passed as string
z.string({
errorMap: () => ({ message: `Missing ${etcInput.type} customInput: '${etcInput.label}'` }),
})
.min(1)
.parse(input?.value);
}
}
});
}
@@ -0,0 +1,62 @@
import { extractBaseEmail } from "@calcom/lib/extract-base-email";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
export const checkIfBookerEmailIsBlocked = async ({
bookerEmail,
loggedInUserId,
}: {
bookerEmail: string;
loggedInUserId?: number;
}) => {
const baseEmail = extractBaseEmail(bookerEmail);
const blacklistedGuestEmails = process.env.BLACKLISTED_GUEST_EMAILS
? process.env.BLACKLISTED_GUEST_EMAILS.split(",")
: [];
const blacklistedEmail = blacklistedGuestEmails.find(
(guestEmail: string) => guestEmail.toLowerCase() === baseEmail.toLowerCase()
);
if (!blacklistedEmail) {
return false;
}
const user = await prisma.user.findFirst({
where: {
OR: [
{
email: baseEmail,
emailVerified: {
not: null,
},
},
{
secondaryEmails: {
some: {
email: baseEmail,
emailVerified: {
not: null,
},
},
},
},
],
},
select: {
id: true,
email: true,
},
});
if (!user) {
throw new HttpError({ statusCode: 403, message: "Cannot use this email to create the booking." });
}
if (user.id !== loggedInUserId) {
throw new HttpError({
statusCode: 403,
message: `Attendee email has been blocked. Make sure to login as ${bookerEmail} to use this email for creating a booking.`,
});
}
};
@@ -0,0 +1,129 @@
import type { LocationObject } from "@calcom/app-store/locations";
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
import { parseRecurringEvent } from "@calcom/lib";
import prisma, { userSelect } from "@calcom/prisma";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import { EventTypeMetaDataSchema, customInputSchema } from "@calcom/prisma/zod-utils";
export const getEventTypesFromDB = async (eventTypeId: number) => {
const eventType = await prisma.eventType.findUniqueOrThrow({
where: {
id: eventTypeId,
},
select: {
id: true,
customInputs: true,
disableGuests: true,
users: {
select: {
credentials: {
select: credentialForCalendarServiceSelect,
},
...userSelect.select,
},
},
slug: true,
team: {
select: {
id: true,
name: true,
parentId: true,
},
},
bookingFields: true,
title: true,
length: true,
eventName: true,
schedulingType: true,
description: true,
periodType: true,
periodStartDate: true,
periodEndDate: true,
periodDays: true,
periodCountCalendarDays: true,
lockTimeZoneToggleOnBookingPage: true,
requiresConfirmation: true,
requiresBookerEmailVerification: true,
minimumBookingNotice: true,
userId: true,
price: true,
currency: true,
metadata: true,
destinationCalendar: true,
hideCalendarNotes: true,
seatsPerTimeSlot: true,
recurringEvent: true,
seatsShowAttendees: true,
seatsShowAvailabilityCount: true,
bookingLimits: true,
durationLimits: true,
assignAllTeamMembers: true,
parentId: true,
useEventTypeDestinationCalendarEmail: true,
owner: {
select: {
hideBranding: true,
},
},
workflows: {
include: {
workflow: {
include: {
steps: true,
},
},
},
},
locations: true,
timeZone: true,
schedule: {
select: {
id: true,
availability: true,
timeZone: true,
},
},
hosts: {
select: {
isFixed: true,
priority: true,
user: {
select: {
credentials: {
select: credentialForCalendarServiceSelect,
},
...userSelect.select,
},
},
},
},
availability: {
select: {
date: true,
startTime: true,
endTime: true,
days: true,
},
},
secondaryEmailId: true,
secondaryEmail: {
select: {
id: true,
email: true,
},
},
},
});
return {
...eventType,
metadata: EventTypeMetaDataSchema.parse(eventType?.metadata || {}),
recurringEvent: parseRecurringEvent(eventType?.recurringEvent),
customInputs: customInputSchema.array().parse(eventType?.customInputs || []),
locations: (eventType?.locations ?? []) as LocationObject[],
bookingFields: getBookingFieldsWithSystemFields(eventType || {}),
isDynamic: false,
};
};
export type getEventTypeResponse = Awaited<ReturnType<typeof getEventTypesFromDB>>;
@@ -0,0 +1,71 @@
import dayjs from "@calcom/dayjs";
import type { getEventTypeResponse } from "./getEventTypesFromDB";
type EventType = Pick<getEventTypeResponse, "metadata" | "requiresConfirmation">;
type PaymentAppData = { price: number };
export function getRequiresConfirmationFlags({
eventType,
bookingStartTime,
userId,
paymentAppData,
originalRescheduledBookingOrganizerId,
}: {
eventType: EventType;
bookingStartTime: string;
userId: number | undefined;
paymentAppData: PaymentAppData;
originalRescheduledBookingOrganizerId: number | undefined;
}) {
const requiresConfirmation = determineRequiresConfirmation(eventType, bookingStartTime);
const userReschedulingIsOwner = isUserReschedulingOwner(userId, originalRescheduledBookingOrganizerId);
const isConfirmedByDefault = determineIsConfirmedByDefault(
requiresConfirmation,
paymentAppData.price,
userReschedulingIsOwner
);
return {
/**
* Organizer of the booking is rescheduling
*/
userReschedulingIsOwner,
/**
* Booking won't need confirmation to be ACCEPTED
*/
isConfirmedByDefault,
};
}
function determineRequiresConfirmation(eventType: EventType, bookingStartTime: string): boolean {
let requiresConfirmation = eventType?.requiresConfirmation;
const rcThreshold = eventType?.metadata?.requiresConfirmationThreshold;
if (rcThreshold) {
const timeDifference = dayjs(dayjs(bookingStartTime).utc().format()).diff(dayjs(), rcThreshold.unit);
if (timeDifference > rcThreshold.time) {
requiresConfirmation = false;
}
}
return requiresConfirmation;
}
function isUserReschedulingOwner(
userId: number | undefined,
originalRescheduledBookingOrganizerId: number | undefined
): boolean {
// If the user is not the owner of the event, new booking should be always pending.
// Otherwise, an owner rescheduling should be always accepted.
// Before comparing make sure that userId is set, otherwise undefined === undefined
return !!(userId && originalRescheduledBookingOrganizerId === userId);
}
function determineIsConfirmedByDefault(
requiresConfirmation: boolean,
price: number,
userReschedulingIsOwner: boolean
): boolean {
return (!requiresConfirmation && price === 0) || userReschedulingIsOwner;
}
@@ -0,0 +1,60 @@
import type { AdditionalInformation, AppsStatus } from "@calcom/types/Calendar";
import type { EventResult } from "@calcom/types/EventManager";
import type { ReqAppsStatus, Booking } from "../handleNewBooking";
export function handleAppsStatus(
results: EventResult<AdditionalInformation>[],
booking: (Booking & { appsStatus?: AppsStatus[] }) | null,
reqAppsStatus: ReqAppsStatus
): AppsStatus[] {
const resultStatus = mapResultsToAppsStatus(results);
if (reqAppsStatus === undefined) {
return updateBookingWithStatus(booking, resultStatus);
}
return calculateAggregatedAppsStatus(reqAppsStatus, resultStatus);
}
function mapResultsToAppsStatus(results: EventResult<AdditionalInformation>[]): AppsStatus[] {
return results.map((app) => ({
appName: app.appName,
type: app.type,
success: app.success ? 1 : 0,
failures: !app.success ? 1 : 0,
errors: app.calError ? [app.calError] : [],
warnings: app.calWarnings,
}));
}
function updateBookingWithStatus(
booking: (Booking & { appsStatus?: AppsStatus[] }) | null,
resultStatus: AppsStatus[]
): AppsStatus[] {
if (booking !== null) {
booking.appsStatus = resultStatus;
}
return resultStatus;
}
function calculateAggregatedAppsStatus(
reqAppsStatus: NonNullable<ReqAppsStatus>,
resultStatus: AppsStatus[]
): AppsStatus[] {
// From down here we can assume reqAppsStatus is not undefined anymore
// Other status exist, so this is the last booking of a series,
// proceeding to prepare the info for the event
const aggregatedStatus = reqAppsStatus.concat(resultStatus).reduce((acc, curr) => {
if (acc[curr.type]) {
acc[curr.type].success += curr.success;
acc[curr.type].errors = acc[curr.type].errors.concat(curr.errors);
acc[curr.type].warnings = acc[curr.type].warnings?.concat(curr.warnings || []);
} else {
acc[curr.type] = curr;
}
return acc;
}, {} as { [key: string]: AppsStatus });
return Object.values(aggregatedStatus);
}
@@ -0,0 +1,56 @@
import type { EventTypeCustomInput } from "@prisma/client";
import { isValidPhoneNumber } from "libphonenumber-js";
import z from "zod";
type CustomInput = {
value: string | boolean;
label: string;
};
export function handleCustomInputs(
eventTypeCustomInputs: EventTypeCustomInput[],
reqCustomInputs: CustomInput[]
) {
eventTypeCustomInputs.forEach((etcInput) => {
if (etcInput.required) {
const input = reqCustomInputs.find((input) => input.label === etcInput.label);
validateInput(etcInput, input?.value);
}
});
}
function validateInput(etcInput: EventTypeCustomInput, value: string | boolean | undefined) {
const errorMessage = `Missing ${etcInput.type} customInput: '${etcInput.label}'`;
if (etcInput.type === "BOOL") {
validateBooleanInput(value, errorMessage);
} else if (etcInput.type === "PHONE") {
validatePhoneInput(value, errorMessage);
} else {
validateStringInput(value, errorMessage);
}
}
function validateBooleanInput(value: string | boolean | undefined, errorMessage: string) {
z.literal(true, {
errorMap: () => ({ message: errorMessage }),
}).parse(value);
}
function validatePhoneInput(value: string | boolean | undefined, errorMessage: string) {
z.string({
errorMap: () => ({ message: errorMessage }),
})
.refine((val) => isValidPhoneNumber(val), {
message: "Phone number is invalid",
})
.parse(value);
}
function validateStringInput(value: string | boolean | undefined, errorMessage: string) {
z.string({
errorMap: () => ({ message: errorMessage }),
})
.min(1)
.parse(value);
}
@@ -6,8 +6,9 @@ import { sendRescheduledEmails } from "@calcom/emails";
import prisma from "@calcom/prisma";
import type { AdditionalInformation, AppsStatus } from "@calcom/types/Calendar";
import { addVideoCallDataToEvent, handleAppsStatus, findBookingQuery } from "../../../handleNewBooking";
import { addVideoCallDataToEvent, findBookingQuery } from "../../../handleNewBooking";
import type { Booking, createLoggerWithEventDetails } from "../../../handleNewBooking";
import { handleAppsStatus } from "../../../handleNewBooking/handleAppsStatus";
import type { SeatedBooking, RescheduleSeatedBookingObject } from "../../types";
const moveSeatedBookingToNewTimeSlot = async (
@@ -1,6 +1,6 @@
import type { Workflow, WorkflowsOnEventTypes, WorkflowStep } from "@prisma/client";
import type { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking";
import type { getEventTypeResponse } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB";
import { scheduleEmailReminder } from "@calcom/features/ee/workflows/lib/reminders/emailReminderManager";
import type { BookingInfo } from "@calcom/features/ee/workflows/lib/reminders/smsReminderManager";
import type { getDefaultEvent } from "@calcom/lib/defaultEvents";
@@ -9,9 +9,7 @@ import { WorkflowTriggerEvents, TimeUnit, WorkflowActions, WorkflowTemplates } f
const log = logger.getSubLogger({ prefix: ["[scheduleMandatoryReminder]"] });
export type NewBookingEventType =
| Awaited<ReturnType<typeof getDefaultEvent>>
| Awaited<ReturnType<typeof getEventTypesFromDB>>;
export type NewBookingEventType = Awaited<ReturnType<typeof getDefaultEvent>> | getEventTypeResponse;
export async function scheduleMandatoryReminder(
evt: BookingInfo,
@@ -8,11 +8,8 @@ import { createInstantMeetingWithCalVideo } from "@calcom/core/videoClient";
import dayjs from "@calcom/dayjs";
import getBookingDataSchema from "@calcom/features/bookings/lib/getBookingDataSchema";
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
import {
getBookingData,
getCustomInputsResponses,
getEventTypesFromDB,
} from "@calcom/features/bookings/lib/handleNewBooking";
import { getBookingData, getCustomInputsResponses } from "@calcom/features/bookings/lib/handleNewBooking";
import { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB";
import { getFullName } from "@calcom/features/form-builder/utils";
import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload";
import { isPrismaObjOrUndefined } from "@calcom/lib";