* Add email domain array * Create numbered email domain object * Check email domain * Rename function * Add tests * Frontend enable skip ownership check if free email domain * Backend ignore adding ownership to return records if free email domain check is enabled * feat: Only require confirmation for free email domains (#17917) * Add requiresConfirmationForFreeEmail to db * Add option to event type settings * Get requiresConfirmationForFreeEmail for event type page * Include requiresConfirmationForFreeEmail in fetching event type * Pass bookerEmail to `getRequiresConfirmationFlags` * Add free email domain check to `determineRequiresConfirmation` * Add `requiresConfirmationForFreeEmail` to types * Add severity to Watchlist table * Add migration for watchlist severity * Add `getEmailDomainInWatchlist` method to watchlist repository * Use watchlist repository to check for free email domain * Mock watchlist repository in test * Update test * Rename method * Add severity to blocked list * Move check free email domain to async * Type checks * Adjust for promise returned * Fix tests * Fix * Fix tests
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import dayjs from "@calcom/dayjs";
|
|
import { checkIfFreeEmailDomain } from "@calcom/lib/freeEmailDomainCheck/checkIfFreeEmailDomain";
|
|
|
|
import type { getEventTypeResponse } from "./getEventTypesFromDB";
|
|
|
|
type EventType = Pick<
|
|
getEventTypeResponse,
|
|
"metadata" | "requiresConfirmation" | "requiresConfirmationForFreeEmail"
|
|
>;
|
|
type PaymentAppData = { price: number };
|
|
|
|
export async function getRequiresConfirmationFlags({
|
|
eventType,
|
|
bookingStartTime,
|
|
userId,
|
|
paymentAppData,
|
|
originalRescheduledBookingOrganizerId,
|
|
bookerEmail,
|
|
}: {
|
|
eventType: EventType;
|
|
bookingStartTime: string;
|
|
userId: number | undefined;
|
|
paymentAppData: PaymentAppData;
|
|
originalRescheduledBookingOrganizerId: number | undefined;
|
|
bookerEmail: string;
|
|
}) {
|
|
const requiresConfirmation = await determineRequiresConfirmation(eventType, bookingStartTime, bookerEmail);
|
|
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,
|
|
};
|
|
}
|
|
|
|
async function determineRequiresConfirmation(
|
|
eventType: EventType,
|
|
bookingStartTime: string,
|
|
bookerEmail: string
|
|
): Promise<boolean> {
|
|
let requiresConfirmation = eventType?.requiresConfirmation;
|
|
const rcThreshold = eventType?.metadata?.requiresConfirmationThreshold;
|
|
const requiresConfirmationForFreeEmail = eventType?.requiresConfirmationForFreeEmail;
|
|
|
|
if (requiresConfirmationForFreeEmail) {
|
|
requiresConfirmation = await checkIfFreeEmailDomain(bookerEmail);
|
|
}
|
|
|
|
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;
|
|
}
|