Skip to content

Commit 27cc38a

Browse files
feat(bookings): add booking audit logging to instant bookings
wire up BookingEventHandlerService.onBookingCreated in InstantBookingCreateService to emit audit events, matching the pattern already used in RegularBookingService and RecurringBookingService.
1 parent 1c193cc commit 27cc38a

2 files changed

Lines changed: 66 additions & 0 deletions

File tree

packages/features/bookings/di/InstantBookingCreateService.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { InstantBookingCreateService } from "@calcom/features/bookings/lib/service/InstantBookingCreateService";
2+
import { moduleLoader as bookingEventHandlerModuleLoader } from "@calcom/features/bookings/di/BookingEventHandlerService.module";
23
import { createModule, bindModuleToClassOnToken } from "@calcom/features/di/di";
4+
import { moduleLoader as featuresRepositoryModuleLoader } from "@calcom/features/di/modules/FeaturesRepository";
35
import { DI_TOKENS } from "@calcom/features/di/tokens";
46
import { moduleLoader as prismaModuleLoader } from "@calcom/features/di/modules/Prisma";
57

@@ -14,6 +16,8 @@ const loadModule = bindModuleToClassOnToken({
1416
depsMap: {
1517
// TODO: In a followup PR, we aim to remove prisma dependency and instead inject the repositories as dependencies.
1618
prismaClient: prismaModuleLoader,
19+
bookingEventHandler: bookingEventHandlerModuleLoader,
20+
featuresRepository: featuresRepositoryModuleLoader,
1721
},
1822
});
1923

packages/features/bookings/lib/service/InstantBookingCreateService.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,23 @@ import short from "short-uuid";
33
import { v5 as uuidv5 } from "uuid";
44

55
import dayjs from "@calcom/dayjs";
6+
import type { ActionSource } from "@calcom/features/booking-audit/lib/types/actionSource";
67
import type {
78
CreateInstantBookingData,
89
InstantBookingCreateResult,
910
} from "@calcom/features/bookings/lib/dto/types";
1011
import getBookingDataSchema from "@calcom/features/bookings/lib/getBookingDataSchema";
1112
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
1213
import { getBookingData } from "@calcom/features/bookings/lib/handleNewBooking/getBookingData";
14+
import { buildBookingCreatedAuditData } from "@calcom/features/bookings/lib/handleNewBooking/buildBookingEventAuditData";
15+
import { getAuditActionSource } from "@calcom/features/bookings/lib/handleNewBooking/getAuditActionSource";
16+
import { getBookingAuditActorForNewBooking } from "@calcom/features/bookings/lib/handleNewBooking/getBookingAuditActorForNewBooking";
1317
import { getCustomInputsResponses } from "@calcom/features/bookings/lib/handleNewBooking/getCustomInputsResponses";
1418
import { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB";
1519
import type { IBookingCreateService } from "@calcom/features/bookings/lib/interfaces/IBookingCreateService";
20+
import type { BookingEventHandlerService } from "@calcom/features/bookings/lib/onBookingEvents/BookingEventHandlerService";
1621
import { createInstantMeetingWithCalVideo } from "@calcom/features/conferencing/lib/videoClient";
22+
import type { FeaturesRepository } from "@calcom/features/flags/features.repository";
1723
import { getFullName } from "@calcom/features/form-builder/utils";
1824
import { sendNotification } from "@calcom/features/notifications/sendNotification";
1925
import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload";
@@ -31,6 +37,8 @@ import { WebhookVersion } from "../../../webhooks/lib/interface/IWebhookReposito
3137

3238
interface IInstantBookingCreateServiceDependencies {
3339
prismaClient: PrismaClient;
40+
bookingEventHandler: BookingEventHandlerService;
41+
featuresRepository: FeaturesRepository;
3442
}
3543

3644
const handleInstantMeetingWebhookTrigger = async (args: {
@@ -343,6 +351,60 @@ export async function handler(
343351
prismaClient: prisma,
344352
});
345353

354+
// Fire booking audit event
355+
try {
356+
const orgId = eventType.team?.parentId ?? null;
357+
const isBookingAuditEnabled = orgId
358+
? await deps.featuresRepository.checkIfTeamHasFeature(orgId, "booking-audit")
359+
: false;
360+
361+
const actionSource: ActionSource = getAuditActionSource({
362+
creationSource: bookingData.creationSource ?? null,
363+
eventTypeId: eventType.id,
364+
rescheduleUid: null,
365+
});
366+
367+
const bookerAttendeeId = newBooking.attendees?.find((a) => a.email === bookerEmail)?.id ?? null;
368+
const auditActor = getBookingAuditActorForNewBooking({
369+
bookerAttendeeId,
370+
actorUserUuid: null,
371+
bookerEmail,
372+
bookerName: fullName,
373+
rescheduledBy: null,
374+
logger,
375+
});
376+
377+
await deps.bookingEventHandler.onBookingCreated({
378+
payload: {
379+
config: { isDryRun: false },
380+
bookingFormData: { hashedLink: null },
381+
booking: {
382+
uid: newBooking.uid,
383+
startTime: newBooking.startTime,
384+
endTime: newBooking.endTime,
385+
status: newBooking.status,
386+
userId: newBooking.userId,
387+
},
388+
organizationId: orgId,
389+
},
390+
actor: auditActor,
391+
auditData: buildBookingCreatedAuditData({
392+
booking: {
393+
startTime: newBooking.startTime,
394+
endTime: newBooking.endTime,
395+
status: newBooking.status,
396+
userUuid: null,
397+
},
398+
attendeeSeatId: null,
399+
}),
400+
source: actionSource,
401+
operationId: null,
402+
isBookingAuditEnabled,
403+
});
404+
} catch (error) {
405+
logger.error("Error firing booking audit event for instant booking", error);
406+
}
407+
346408
return {
347409
message: "Success",
348410
meetingTokenId: instantMeetingToken.id,

0 commit comments

Comments
 (0)