diff --git a/apps/api/v1/pages/api/bookings/[id]/_delete.ts b/apps/api/v1/pages/api/bookings/[id]/_delete.ts index 476b1de577..1756c29467 100644 --- a/apps/api/v1/pages/api/bookings/[id]/_delete.ts +++ b/apps/api/v1/pages/api/bookings/[id]/_delete.ts @@ -82,6 +82,7 @@ async function handler(req: NextApiRequest) { return await handleCancelBooking({ bookingData: { id, allRemainingBookings, cancellationReason, cancelledBy }, userId: req.userId, + actionSource: "API_V1", }); } diff --git a/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts b/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts index 738092fa0f..47a8bd5390 100644 --- a/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts +++ b/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts @@ -279,6 +279,7 @@ export class BookingsController_2024_04_15 { platformCancelUrl: bookingRequest.platformCancelUrl, platformRescheduleUrl: bookingRequest.platformRescheduleUrl, platformBookingUrl: bookingRequest.platformBookingUrl, + actionSource: "API_V2", }); if (!res.onlyRemovedAttendee && res.isPlatformManagedUserBooking) { void (await this.billingService.cancelUsageByBookingUid(res.bookingUid)); diff --git a/packages/features/bookings/lib/handleCancelBooking.ts b/packages/features/bookings/lib/handleCancelBooking.ts index f64ed8d7e8..827ee3e434 100644 --- a/packages/features/bookings/lib/handleCancelBooking.ts +++ b/packages/features/bookings/lib/handleCancelBooking.ts @@ -10,7 +10,7 @@ import { makeGuestActor, makeUserActor, } from "@calcom/features/booking-audit/lib/makeActor"; -import type { ActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; +import type { ValidActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; import { BookingReferenceRepository } from "@calcom/features/bookingReference/repositories/BookingReferenceRepository"; import { getBookingEventHandlerService } from "@calcom/features/bookings/di/BookingEventHandlerService.container"; import EventManager from "@calcom/features/bookings/lib/EventManager"; @@ -81,7 +81,7 @@ export type CancelBookingInput = { userId?: number; userUuid?: string; bookingData: z.infer; - actionSource?: ActionSource; + actionSource: ValidActionSource; } & PlatformParams; type Dependencies = { @@ -173,17 +173,7 @@ async function handler(input: CancelBookingInput, dependencies?: Dependencies) { const userUuid = input.userUuid ?? null; - // Extract action source once for reuse - const actionSource = input.actionSource ?? "UNKNOWN"; - if (actionSource === "UNKNOWN") { - log.warn( - "Booking cancellation with unknown actionSource", - safeStringify({ - bookingUid: bookingToDelete.uid, - userUuid, - }) - ); - } + const actionSource = input.actionSource; const actorToUse = getAuditActor({ userUuid, @@ -724,10 +714,15 @@ type BookingCancelServiceDependencies = { export class BookingCancelService implements IBookingCancelService { constructor(private readonly deps: BookingCancelServiceDependencies) {} - async cancelBooking(input: { bookingData: CancelRegularBookingData; bookingMeta?: CancelBookingMeta }) { + async cancelBooking(input: { + bookingData: CancelRegularBookingData; + bookingMeta?: CancelBookingMeta; + actionSource: ValidActionSource; + }) { const cancelBookingInput: CancelBookingInput = { bookingData: input.bookingData, ...(input.bookingMeta || {}), + actionSource: input.actionSource, }; return handler(cancelBookingInput, this.deps); diff --git a/packages/features/bookings/lib/handleCancelBooking/test/handleCancelBooking.test.ts b/packages/features/bookings/lib/handleCancelBooking/test/handleCancelBooking.test.ts index 9bbe478412..0da58f3485 100644 --- a/packages/features/bookings/lib/handleCancelBooking/test/handleCancelBooking.test.ts +++ b/packages/features/bookings/lib/handleCancelBooking/test/handleCancelBooking.test.ts @@ -134,6 +134,7 @@ describe("Cancel Booking", () => { cancelledBy: organizer.email, cancellationReason: "No reason", }, + actionSource: "WEBAPP", }); expectBookingCancelledWebhookToHaveBeenFired({ @@ -264,6 +265,7 @@ describe("Cancel Booking", () => { cancelledBy: organizer.email, cancellationReason: "No reason", }, + actionSource: "WEBAPP", }); expectBookingCancelledWebhookToHaveBeenFired({ @@ -411,6 +413,7 @@ describe("Cancel Booking", () => { cancelledBy: organizer.email, cancellationReason: "Testing round robin cancellation with host as attendee", }, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -563,6 +566,7 @@ describe("Cancel Booking", () => { cancelledBy: primaryHost.email, cancellationReason: "Testing EMAIL_HOST workflow sends to secondary host in round robin", }, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -640,6 +644,7 @@ describe("Cancel Booking", () => { cancelledBy: organizer.email, cancellationReason: "Testing past booking cancellation", }, + actionSource: "WEBAPP", }) ).rejects.toThrow("Cannot cancel a booking that has already ended"); }); @@ -708,6 +713,7 @@ describe("Cancel Booking", () => { uid: uidOfBookingToBeCancelled, cancelledBy: organizer.email, }, + actionSource: "WEBAPP", }) ).rejects.toThrow("Cancellation reason is required when you are the host"); }); @@ -819,6 +825,7 @@ describe("Cancel Booking", () => { cancelledBy: organizer.email, cancellationReason: "No reason", }, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -945,6 +952,7 @@ describe("Cancel Booking", () => { cancelledBy: organizer.email, cancellationReason: "No reason", }, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -1062,6 +1070,7 @@ describe("Cancel Booking", () => { cancellationReason: "Attendee cancelled within time threshold", }, userId: 999, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -1170,6 +1179,7 @@ describe("Cancel Booking", () => { cancelledBy: organizer.email, cancellationReason: "Organization booking cancellation test", }, + actionSource: "WEBAPP", }); expectBookingCancelledWebhookToHaveBeenFired({ @@ -1292,6 +1302,7 @@ describe("Cancel Booking", () => { cancellationReason: "Cancelling seated event", }, userId: organizer.id, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -1413,6 +1424,7 @@ describe("Cancel Booking", () => { allRemainingBookings: true, }, userId: organizer.id, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -1534,6 +1546,7 @@ describe("Cancel Booking", () => { cancelSubsequentBookings: true, }, userId: organizer.id, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); @@ -1647,6 +1660,7 @@ describe("Cancel Booking", () => { cancellationReason: "Testing booking reference cleanup", }, userId: organizer.id, + actionSource: "WEBAPP", }); expect(result.success).toBe(true); diff --git a/packages/features/bookings/lib/handleConfirmation.ts b/packages/features/bookings/lib/handleConfirmation.ts index 22e6bbf993..9269ae1f1b 100644 --- a/packages/features/bookings/lib/handleConfirmation.ts +++ b/packages/features/bookings/lib/handleConfirmation.ts @@ -2,7 +2,7 @@ import { eventTypeAppMetadataOptionalSchema } from "@calcom/app-store/zod-utils" import { scheduleMandatoryReminder } from "@calcom/ee/workflows/lib/reminders/scheduleMandatoryReminder"; import { sendScheduledEmailsAndSMS } from "@calcom/emails/email-manager"; import type { Actor } from "@calcom/features/booking-audit/lib/dto/types"; -import type { ActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; +import type { ValidActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; import { getBookingEventHandlerService } from "@calcom/features/bookings/di/BookingEventHandlerService.container"; import type { EventManagerUser } from "@calcom/features/bookings/lib/EventManager"; import EventManager, { placeholderCreatedEvent } from "@calcom/features/bookings/lib/EventManager"; @@ -48,7 +48,7 @@ async function fireBookingAcceptedEvent({ }: { actor: Actor; organizationId: number | null; - actionSource: ActionSource; + actionSource: ValidActionSource; acceptedBookings: { uid: string; oldStatus: BookingStatus; @@ -133,7 +133,7 @@ export async function handleConfirmation(args: { emailsEnabled?: boolean; platformClientParams?: PlatformClientParams; traceContext: TraceContext; - actionSource: ActionSource; + actionSource: ValidActionSource; actor: Actor; }) { const { diff --git a/packages/features/bookings/lib/handleSeats/test/handleSeats.test.ts b/packages/features/bookings/lib/handleSeats/test/handleSeats.test.ts index 49d24127ea..961cbfce43 100644 --- a/packages/features/bookings/lib/handleSeats/test/handleSeats.test.ts +++ b/packages/features/bookings/lib/handleSeats/test/handleSeats.test.ts @@ -1976,6 +1976,7 @@ describe("handleSeats", () => { cancellationReason: "test cancellation reason", }, userId: organizer.id, + actionSource: "WEBAPP", }); // Ensure that the booking has been cancelled @@ -2115,6 +2116,7 @@ describe("handleSeats", () => { cancellationReason: "test cancellation reason", }, userId: organizer.id, + actionSource: "WEBAPP", }); // Ensure that the booking has been cancelled @@ -2967,6 +2969,7 @@ describe("handleSeats", () => { cancellationReason: "test cancellation reason", }, userId: organizer.id, + actionSource: "WEBAPP", }); // Ensure that the booking has been cancelled diff --git a/packages/features/bookings/lib/interfaces/IBookingCancelService.ts b/packages/features/bookings/lib/interfaces/IBookingCancelService.ts index adc99efd9d..1fd65c5ec2 100644 --- a/packages/features/bookings/lib/interfaces/IBookingCancelService.ts +++ b/packages/features/bookings/lib/interfaces/IBookingCancelService.ts @@ -3,10 +3,12 @@ import type { CancelBookingMeta, HandleCancelBookingResponse, } from "../dto/BookingCancel"; +import type { ValidActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; export interface IBookingCancelService { cancelBooking(input: { bookingData: CancelRegularBookingData; bookingMeta?: CancelBookingMeta; + actionSource: ValidActionSource; }): Promise; } diff --git a/packages/trpc/server/routers/viewer/bookings/_router.tsx b/packages/trpc/server/routers/viewer/bookings/_router.tsx index 105713ebac..960d181543 100644 --- a/packages/trpc/server/routers/viewer/bookings/_router.tsx +++ b/packages/trpc/server/routers/viewer/bookings/_router.tsx @@ -121,6 +121,7 @@ export const bookingsRouter = router({ return reportBookingHandler({ ctx, input, + actionSource: "WEBAPP", }); }), reportWrongAssignment: authedProcedure diff --git a/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts b/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts index cda0198ce9..90d6c82889 100644 --- a/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/addGuests.handler.ts @@ -2,7 +2,7 @@ import { getUsersCredentialsIncludeServiceAccountKey } from "@calcom/app-store/d import { eventTypeMetaDataSchemaWithTypedApps } from "@calcom/app-store/zod-utils"; import dayjs from "@calcom/dayjs"; import { makeUserActor } from "@calcom/features/booking-audit/lib/makeActor"; -import type { ActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; +import type { ValidActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; import { getBookingEventHandlerService } from "@calcom/features/bookings/di/BookingEventHandlerService.container"; import { BookingEmailSmsHandler } from "@calcom/features/bookings/lib/BookingEmailSmsHandler"; import EventManager from "@calcom/features/bookings/lib/EventManager"; @@ -35,7 +35,7 @@ type AddGuestsOptions = { }; input: TAddGuestsInputSchema; emailsEnabled?: boolean; - actionSource: ActionSource; + actionSource: ValidActionSource; }; export type Booking = NonNullable< diff --git a/packages/trpc/server/routers/viewer/bookings/reportBooking.handler.ts b/packages/trpc/server/routers/viewer/bookings/reportBooking.handler.ts index 9d856c6db4..401b9be929 100644 --- a/packages/trpc/server/routers/viewer/bookings/reportBooking.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/reportBooking.handler.ts @@ -1,4 +1,5 @@ import { PrismaBookingReportRepository } from "@calcom/features/bookingReport/repositories/PrismaBookingReportRepository"; +import type { ValidActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; import handleCancelBooking from "@calcom/features/bookings/lib/handleCancelBooking"; import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository"; import { BookingAccessService } from "@calcom/features/bookings/services/BookingAccessService"; @@ -16,11 +17,12 @@ type ReportBookingOptions = { user: NonNullable; }; input: TReportBookingInputSchema; + actionSource: ValidActionSource; }; const log = logger.getSubLogger({ prefix: ["reportBookingHandler"] }); -export const reportBookingHandler = async ({ ctx, input }: ReportBookingOptions) => { +export const reportBookingHandler = async ({ ctx, input, actionSource }: ReportBookingOptions) => { const { user } = ctx; const { bookingUid, reason, description } = input; @@ -90,6 +92,7 @@ export const reportBookingHandler = async ({ ctx, input }: ReportBookingOptions) ...(seatReferenceUid ? { seatReferenceUid } : {}), }, userId: user.id, + actionSource, }); didCancel = true; } catch (error) { diff --git a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts index 6d46e8dc87..ef77ee55e6 100644 --- a/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts +++ b/packages/trpc/server/routers/viewer/bookings/requestReschedule.handler.ts @@ -6,7 +6,7 @@ import { getUsersCredentialsIncludeServiceAccountKey } from "@calcom/app-store/d import dayjs from "@calcom/dayjs"; import { sendRequestRescheduleEmailAndSMS } from "@calcom/emails/email-manager"; import { makeUserActor } from "@calcom/features/booking-audit/lib/makeActor"; -import type { ActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; +import type { ValidActionSource } from "@calcom/features/booking-audit/lib/types/actionSource"; import { getBookingEventHandlerService } from "@calcom/features/bookings/di/BookingEventHandlerService.container"; import { getFeaturesRepository } from "@calcom/features/di/containers/FeaturesRepository"; import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses"; @@ -47,7 +47,7 @@ type RequestRescheduleOptions = { user: NonNullable; }; input: TRequestRescheduleInputSchema; - source: ActionSource; + source: ValidActionSource; }; const log = logger.getSubLogger({ prefix: ["requestRescheduleHandler"] }); export const requestRescheduleHandler = async ({ ctx, input, source }: RequestRescheduleOptions) => {