Files
calendar/packages/features/bookings/lib/handleNewBooking/getRequiresConfirmationFlags.ts
T
Syed Ali ShahbazandGitHub a2bee76da6 feat: Add spam blocker DI structure (#24040)
* --init

* --

* replace old structure with new DI

* fix type

* --

* moving stuff around

* moving stuff around again

* minor clean up

* --

* resolve conflict

* clea up

* old schema clean up

* further clean up

* removing unwanted merged responsibilities

* --

* improve DI and SOLID

* some type fixes

* --1

* clean up --cont

* fix DI in facade for test

* more fix

* fix

* checking

* o.o

* fix import

* fix failing test --2

* fix failing test --3

* fix failing test --4

* normalization use

* introduce facade container injection

* uniform async telemetry spans

* further improvements

* replace prismock with repo mocks

* ensure we don't pass prisma outside of repo

* fix import

* remove try catch from repo calls

* async await fixes

* using deps pattern

* more clean up and fixes

* more clean up

* address feedback --1

* separation of concern

* clean up

* test clean up

* feedback --2

* remove extra fetch

* remove await

* migrate _post test from prismock

* fix type

* --

* fix tokens path

* rename AuditRepo

* test --1

* update _post to integration test

* fix test

* fix test

* test fix maybe?

* --

* feedback

* feedback

* fixes

* more feedback

* NIT

* use sentry and logger imports as planned

* assertion in test

* add missing test case

* add tests for controllers and services

* NITs

* fix domain normalisation
2025-10-14 10:16:18 +03:00

94 lines
2.9 KiB
TypeScript

import dayjs from "@calcom/dayjs";
import { checkIfFreeEmailDomain } from "@calcom/features/watchlist/lib/freeEmailDomainCheck/checkIfFreeEmailDomain";
import { withReporting } from "@calcom/lib/sentryWrapper";
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,
};
}
// Define the function with underscore prefix
const _determineRequiresConfirmation = async (
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({ email: bookerEmail });
}
if (rcThreshold) {
const timeDifference = dayjs(dayjs(bookingStartTime).utc().format()).diff(dayjs(), rcThreshold.unit);
if (timeDifference > rcThreshold.time) {
requiresConfirmation = false;
}
}
return requiresConfirmation;
};
export const determineRequiresConfirmation = withReporting(
_determineRequiresConfirmation,
"determineRequiresConfirmation"
);
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;
}