feat: refactor handleCancelBooking to not have next request (#20241)

* refactor handleCancelBooking to not have next request

* fix platform v2 function calls

* dont fall back to "" if no seat refrence

* add missing type from merge

* chore: bump platform libraries

---------

Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com>
Co-authored-by: supalarry <laurisskraucis@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-04-01 14:52:24 +00:00
1 parent a5c15e6517
commit f94e80558a
10 files changed
+89 -67

No files matched your search

@@ -79,9 +79,10 @@ async function handler(req: NextApiRequest) {
allRemainingBookings: req.query.allRemainingBookings === "true",
});
// Normalizing for universal handler
req.body = { id, allRemainingBookings, cancellationReason, cancelledBy };
return await handleCancelBooking(req);
return await handleCancelBooking({
bookingData: { id, allRemainingBookings, cancellationReason, cancelledBy },
userId: req.userId,
});
}
export default defaultResponder(handler);
+1 -1
View File
@@ -38,7 +38,7 @@
"@axiomhq/winston": "^1.2.0",
"@calcom/platform-constants": "*",
"@calcom/platform-enums": "*",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.160",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.164",
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
"@calcom/platform-types": "*",
"@calcom/platform-utils": "*",
@@ -214,9 +214,16 @@ export class BookingsController_2024_04_15 {
if (bookingUid) {
try {
req.body.uid = bookingUid;
const res = await handleCancelBooking(
await this.createNextApiBookingRequest(req, oAuthClientId, undefined, isEmbed)
);
const bookingRequest = await this.createNextApiBookingRequest(req, oAuthClientId, undefined, isEmbed);
const res = await handleCancelBooking({
bookingData: bookingRequest.body,
userId: bookingRequest.userId,
arePlatformEmailsEnabled: bookingRequest.arePlatformEmailsEnabled,
platformClientId: bookingRequest.platformClientId,
platformCancelUrl: bookingRequest.platformCancelUrl,
platformRescheduleUrl: bookingRequest.platformRescheduleUrl,
platformBookingUrl: bookingRequest.platformBookingUrl,
});
if (!res.onlyRemovedAttendee) {
void (await this.billingService.cancelUsageByBookingUid(res.bookingUid));
}
@@ -344,7 +344,16 @@ export class BookingsService_2024_08_13 {
}
const bookingRequest = await this.inputService.createCancelBookingRequest(request, bookingUid, body);
const res = await handleCancelBooking(bookingRequest);
const res = await handleCancelBooking({
bookingData: bookingRequest.body,
userId: bookingRequest.userId,
arePlatformEmailsEnabled: bookingRequest.arePlatformEmailsEnabled,
platformClientId: bookingRequest.platformClientId,
platformCancelUrl: bookingRequest.platformCancelUrl,
platformRescheduleUrl: bookingRequest.platformRescheduleUrl,
platformBookingUrl: bookingRequest.platformBookingUrl,
});
if (!res.onlyRemovedAttendee) {
await this.billingService.cancelUsageByBookingUid(res.bookingUid);
}
+3 -1
View File
@@ -5,6 +5,7 @@ import type { NextRequest } from "next/server";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import handleCancelBooking from "@calcom/features/bookings/lib/handleCancelBooking";
import { bookingCancelInput } from "@calcom/prisma/zod-utils";
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
@@ -16,8 +17,9 @@ async function handler(req: NextRequest) {
return NextResponse.json({ success: false, message: "Invalid JSON" }, { status: 400 });
}
const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
const bookingData = bookingCancelInput.parse(appDirRequestBody);
const result = await handleCancelBooking({
appDirRequestBody,
bookingData,
userId: session?.user?.id || -1,
});
@@ -1,5 +1,5 @@
import type { Prisma, WorkflowReminder } from "@prisma/client";
import type { NextApiRequest } from "next";
import type { z } from "zod";
import { FAKE_DAILY_CREDENTIAL } from "@calcom/app-store/dailyvideo/lib/VideoApiAdapter";
import { DailyLocationType } from "@calcom/app-store/locations";
@@ -34,12 +34,26 @@ import type { CalendarEvent } from "@calcom/types/Calendar";
import { getAllCredentials } from "./getAllCredentialsForUsersOnEvent/getAllCredentials";
import { getBookingToDelete } from "./getBookingToDelete";
import type { CustomRequest, AppRouterRequest } from "./handleCancelBooking/types";
import { handleInternalNote } from "./handleInternalNote";
import cancelAttendeeSeat from "./handleSeats/cancel/cancelAttendeeSeat";
const log = logger.getSubLogger({ prefix: ["handleCancelBooking"] });
type PlatformParams = {
platformClientId?: string;
platformRescheduleUrl?: string;
platformCancelUrl?: string;
platformBookingUrl?: string;
arePlatformEmailsEnabled?: boolean;
};
export type BookingToDelete = Awaited<ReturnType<typeof getBookingToDelete>>;
export type CancelBookingInput = {
userId?: number;
bookingData: z.infer<typeof bookingCancelInput>;
} & PlatformParams;
export type HandleCancelBookingResponse = {
success: boolean;
message: string;
@@ -48,8 +62,8 @@ export type HandleCancelBookingResponse = {
bookingUid: string;
};
async function handler(req: CustomRequest) {
const body = (req as AppRouterRequest).appDirRequestBody ?? (req as NextApiRequest).body;
async function handler(input: CancelBookingInput) {
const body = input.bookingData;
const {
id,
uid,
@@ -60,22 +74,21 @@ async function handler(req: CustomRequest) {
cancelSubsequentBookings,
internalNote,
} = bookingCancelInput.parse(body);
req.bookingToDelete = await getBookingToDelete(id, uid);
const bookingToDelete = await getBookingToDelete(id, uid);
const {
bookingToDelete,
userId,
platformBookingUrl,
platformCancelUrl,
platformClientId,
platformRescheduleUrl,
arePlatformEmailsEnabled,
} = req;
} = input;
if (!bookingToDelete.userId || !bookingToDelete.user) {
throw new HttpError({ statusCode: 400, message: "User not found" });
}
if (!platformClientId && !cancellationReason && req.bookingToDelete.userId == userId) {
if (!platformClientId && !cancellationReason && bookingToDelete.userId == userId) {
throw new HttpError({
statusCode: 400,
message: "Cancellation reason is required when you are the host",
@@ -248,7 +261,10 @@ async function handler(req: CustomRequest) {
// If it's just an attendee of a booking then just remove them from that booking
const result = await cancelAttendeeSeat(
req,
{
seatReferenceUid: seatReferenceUid,
bookingToDelete,
},
dataForWebhooks,
bookingToDelete?.eventType?.metadata as EventTypeMetadata
);
@@ -477,7 +493,6 @@ async function handler(req: CustomRequest) {
} catch (error) {
console.error("Error deleting event", error);
}
(req as NextApiRequest).statusCode = 200;
return {
success: true,
message: "Booking successfully cancelled.",
@@ -10,7 +10,6 @@ import {
TestData,
getDate,
} from "@calcom/web/test/utils/bookingScenario/bookingScenario";
import { createMockNextJsRequest } from "@calcom/web/test/utils/bookingScenario/createMockNextJsRequest";
import { expectBookingCancelledWebhookToHaveBeenFired } from "@calcom/web/test/utils/bookingScenario/expects";
import { setupAndTeardown } from "@calcom/web/test/utils/bookingScenario/setupAndTeardown";
@@ -110,17 +109,14 @@ describe("Cancel Booking", () => {
},
});
const { req } = createMockNextJsRequest({
method: "POST",
body: {
await handleCancelBooking({
bookingData: {
id: idOfBookingToBeCancelled,
uid: uidOfBookingToBeCancelled,
cancelledBy: organizer.email,
},
});
await handleCancelBooking(req);
expectBookingCancelledWebhookToHaveBeenFired({
booker,
organizer,
@@ -240,17 +236,14 @@ describe("Cancel Booking", () => {
},
});
const { req } = createMockNextJsRequest({
method: "POST",
body: {
await handleCancelBooking({
bookingData: {
id: idOfBookingToBeCancelled,
uid: uidOfBookingToBeCancelled,
cancelledBy: organizer.email,
},
});
await handleCancelBooking(req);
expectBookingCancelledWebhookToHaveBeenFired({
booker,
organizer,
@@ -1,5 +1,3 @@
import type { NextApiRequest } from "next";
import { getCalendar } from "@calcom/app-store/_utils/getCalendar";
import { sendCancelledSeatEmailsAndSMS } from "@calcom/emails";
import sendPayload from "@calcom/features/webhooks/lib/sendOrSchedulePayload";
@@ -18,10 +16,13 @@ import { bookingCancelAttendeeSeatSchema } from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
import type { CalendarEvent } from "@calcom/types/Calendar";
import type { AppRouterRequest, CustomRequest } from "../../handleCancelBooking/types";
import type { BookingToDelete } from "../../handleCancelBooking";
async function cancelAttendeeSeat(
req: CustomRequest,
data: {
seatReferenceUid?: string;
bookingToDelete: BookingToDelete;
},
dataForWebhooks: {
webhooks: {
id: string;
@@ -35,12 +36,13 @@ async function cancelAttendeeSeat(
},
eventTypeMetadata: EventTypeMetadata
) {
const body = (req as AppRouterRequest).appDirRequestBody ?? (req as NextApiRequest).body;
const input = bookingCancelAttendeeSeatSchema.safeParse(body);
const input = bookingCancelAttendeeSeatSchema.safeParse({
seatReferenceUid: data.seatReferenceUid,
});
const { webhooks, evt, eventTypeInfo } = dataForWebhooks;
if (!input.success) return;
const { seatReferenceUid } = input.data;
const bookingToDelete = req.bookingToDelete;
const bookingToDelete = data.bookingToDelete;
if (!bookingToDelete?.attendees.length || bookingToDelete.attendees.length < 2) return;
if (!bookingToDelete.userId) {
@@ -65,7 +67,6 @@ async function cancelAttendeeSeat(
},
}),
]);
(req as NextApiRequest).statusCode = 200;
const attendee = bookingToDelete?.attendees.find((attendee) => attendee.id === seatReference.attendeeId);
const bookingToDeleteUser = bookingToDelete.user ?? null;
@@ -1671,16 +1671,14 @@ describe("handleSeats", () => {
seatReferenceUid: bookingSeatToBeCancelledUid,
});
const { req } = createMockNextJsRequest({
method: "POST",
body: mockCancelBookingData,
await handleCancelBooking({
bookingData: {
...mockCancelBookingData,
cancellationReason: "test cancellation reason",
},
userId: organizer.id,
});
req.userId = organizer.id;
req.body.cancellationReason = "test cancellation reason";
await handleCancelBooking(req);
// Ensure that the booking has been cancelled
const cancelledBooking = await prismaMock.booking.findFirst({
where: {
@@ -1812,16 +1810,14 @@ describe("handleSeats", () => {
seatReferenceUid: bookingSeatToBeCancelledUid,
});
const { req } = createMockNextJsRequest({
method: "POST",
body: mockCancelBookingData,
await handleCancelBooking({
bookingData: {
...mockCancelBookingData,
cancellationReason: "test cancellation reason",
},
userId: organizer.id,
});
req.userId = organizer.id;
req.body.cancellationReason = "test cancellation reason";
await handleCancelBooking(req);
// Ensure that the booking has been cancelled
const cancelledBooking = await prismaMock.booking.findFirst({
where: {
@@ -2678,16 +2674,14 @@ describe("handleSeats", () => {
},
});
const { req } = createMockNextJsRequest({
method: "POST",
body: mockBookingData,
await handleCancelBooking({
bookingData: {
...mockBookingData,
cancellationReason: "test cancellation reason",
},
userId: organizer.id,
});
req.userId = organizer.id;
req.body.cancellationReason = "test cancellation reason";
await handleCancelBooking(req);
// Ensure that the booking has been cancelled
const cancelledBooking = await prismaMock.booking.findFirst({
where: {
+5 -5
View File
@@ -2297,7 +2297,7 @@ __metadata:
"@axiomhq/winston": ^1.2.0
"@calcom/platform-constants": "*"
"@calcom/platform-enums": "*"
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.160"
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.164"
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2"
"@calcom/platform-types": "*"
"@calcom/platform-utils": "*"
@@ -3335,13 +3335,13 @@ __metadata:
languageName: node
linkType: hard
"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.160":
version: 0.0.160
resolution: "@calcom/platform-libraries@npm:0.0.160"
"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.164":
version: 0.0.164
resolution: "@calcom/platform-libraries@npm:0.0.164"
dependencies:
"@calcom/features": "*"
"@calcom/lib": "*"
checksum: 483d57040ddcaa93d9a77aeb5af2778cf341986e387955363cb17266d46ce297d7a8a3184056dbda3dba539382ddd8d6f0b9086ed52b3f1c96f5c997a3216d2e
checksum: f612a3e2002950ed00d3479a121b92ee3245f9cb00b663824cac45bb5ab8f74182271377cd8866563a5d11983bc8af08072bfdb58bf459e1c7cd2ec025a50466
languageName: node
linkType: hard