From 57776b829b8b5545054e48e2f97b7d2dc5ea1495 Mon Sep 17 00:00:00 2001 From: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Date: Sat, 25 Oct 2025 13:24:48 +0300 Subject: [PATCH] fix: old rec booking endpoint api v2 (#24669) * fix: old rec booking endpoint api v2 * fixup! fix: old rec booking endpoint api v2 * fixup! fixup! fix: old rec booking endpoint api v2 --- .../bookings.controller.e2e-spec.ts | 103 ++++++++++++++++++ .../controllers/bookings.controller.ts | 5 +- .../inputs/create-recurring-booking.input.ts | 2 +- 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.e2e-spec.ts b/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.e2e-spec.ts index fe798022c2..6216f53e4e 100644 --- a/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.e2e-spec.ts +++ b/apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.e2e-spec.ts @@ -1,6 +1,7 @@ import { bootstrap } from "@/app"; import { AppModule } from "@/app.module"; import { CreateBookingInput_2024_04_15 } from "@/ee/bookings/2024-04-15/inputs/create-booking.input"; +import { CreateRecurringBookingInput_2024_04_15 } from "@/ee/bookings/2024-04-15/inputs/create-recurring-booking.input"; import { GetBookingOutput_2024_04_15 } from "@/ee/bookings/2024-04-15/outputs/get-booking.output"; import { GetBookingsOutput_2024_04_15 } from "@/ee/bookings/2024-04-15/outputs/get-bookings.output"; import { CreateScheduleInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-schedule.input"; @@ -21,6 +22,7 @@ import { randomString } from "test/utils/randomString"; import { withApiAuth } from "test/utils/withApiAuth"; import { SUCCESS_STATUS } from "@calcom/platform-constants"; +import { BookingResponse } from "@calcom/platform-libraries"; import { type RegularBookingCreateResult } from "@calcom/platform-libraries/bookings"; import type { ApiSuccessResponse, ApiErrorResponse } from "@calcom/platform-types"; import type { User } from "@calcom/prisma/client"; @@ -40,6 +42,7 @@ describe("Bookings Endpoints 2024-04-15", () => { let user: User; let eventTypeId: number; + let recEventTypeId: number; let createdBooking: RegularBookingCreateResult; @@ -81,6 +84,18 @@ describe("Bookings Endpoints 2024-04-15", () => { }, user.id ); + + const recEventType = await eventTypesRepositoryFixture.create( + { + title: `rec-bookings-2024-04-15-event-type-${randomString()}-${describe.name}`, + slug: `rec-bookings-2024-04-15-event-type-${randomString()}-${describe.name}`, + length: 60, + recurringEvent: { freq: 2, count: 4, interval: 1 }, + }, + user.id + ); + recEventTypeId = recEventType.id; + eventTypeId = event.id; app = moduleRef.createNestApplication(); @@ -404,6 +419,94 @@ describe("Bookings Endpoints 2024-04-15", () => { }); }); + it("should create recurring bookings", async () => { + const bookingEventTypeId = recEventTypeId; + const bookingTimeZone = "Europe/London"; + const bookingLanguage = "en"; + const bookingHashedLink = ""; + const bookingMetadata = { + timeFormat: "12", + meetingType: "organizer-phone", + }; + const bookingResponses = { + name: "tester", + email: "tester@example.com", + location: { + value: "link", + optionValue: "", + }, + notes: "test", + }; + + const body: CreateRecurringBookingInput_2024_04_15[] = [ + { + start: "2040-06-21T09:30:00.000Z", + end: "2040-06-21T10:30:00.000Z", + eventTypeId: bookingEventTypeId, + timeZone: bookingTimeZone, + language: bookingLanguage, + metadata: bookingMetadata, + hashedLink: bookingHashedLink, + responses: bookingResponses, + recurringEventId: "test-recurring-event-id", + }, + { + start: "2040-06-27T09:30:00.000Z", + end: "2040-06-27T10:30:00.000Z", + eventTypeId: bookingEventTypeId, + timeZone: bookingTimeZone, + language: bookingLanguage, + metadata: bookingMetadata, + hashedLink: bookingHashedLink, + responses: bookingResponses, + recurringEventId: "test-recurring-event-id-2", + }, + { + start: "2040-06-04T09:30:00.000Z", + end: "2040-06-04T10:30:00.000Z", + eventTypeId: bookingEventTypeId, + timeZone: bookingTimeZone, + language: bookingLanguage, + metadata: bookingMetadata, + hashedLink: bookingHashedLink, + responses: bookingResponses, + recurringEventId: "test-recurring-event-id-3", + }, + { + start: "2040-06-11T09:30:00.000Z", + end: "2040-06-11T10:30:00.000Z", + eventTypeId: bookingEventTypeId, + timeZone: bookingTimeZone, + language: bookingLanguage, + metadata: bookingMetadata, + hashedLink: bookingHashedLink, + responses: bookingResponses, + recurringEventId: "test-recurring-event-id-4", + }, + ]; + + return request(app.getHttpServer()) + .post("/v2/bookings/recurring") + .send(body) + .expect(201) + .then(async (response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + expect(responseBody.data).toBeDefined(); + responseBody.data.forEach((booking) => { + expect(booking.userPrimaryEmail).toBeDefined(); + expect(booking.userPrimaryEmail).toEqual(userEmail); + expect(booking.id).toBeDefined(); + expect(booking.uid).toBeDefined(); + expect(booking.eventTypeId).toEqual(bookingEventTypeId); + expect(booking.user.timeZone).toEqual(bookingTimeZone); + expect(booking.metadata).toEqual(bookingMetadata); + expect(booking.responses).toEqual(bookingResponses); + expect(booking.creationSource).toEqual("API_V2"); + }); + }); + }); + afterAll(async () => { await userRepositoryFixture.deleteByEmail(user.email); await bookingsRepositoryFixture.deleteAllBookings(user.id, user.email); 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 f02fdff352..96ae495ced 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 @@ -318,11 +318,9 @@ export class BookingsController_2024_04_15 { recurringEvent.recurringEventId = recurringEventId; } } - const bookingRequest = await this.createNextApiBookingRequest(req, oAuthClientId, undefined, isEmbed); - const createdBookings: BookingResponse[] = await this.recurringBookingService.createBooking({ - bookingData: bookingRequest.body, + bookingData: body.map((booking) => ({ ...booking, creationSource: CreationSource.API_V2 })), bookingMeta: { userId: bookingRequest.userId, hostname: bookingRequest.headers?.host || "", @@ -331,6 +329,7 @@ export class BookingsController_2024_04_15 { platformCancelUrl: bookingRequest.platformCancelUrl, platformBookingUrl: bookingRequest.platformBookingUrl, platformBookingLocation: bookingRequest.platformBookingLocation, + noEmail: bookingRequest.body.noEmail, }, }); diff --git a/apps/api/v2/src/ee/bookings/2024-04-15/inputs/create-recurring-booking.input.ts b/apps/api/v2/src/ee/bookings/2024-04-15/inputs/create-recurring-booking.input.ts index c92dd1ed30..22abf23052 100644 --- a/apps/api/v2/src/ee/bookings/2024-04-15/inputs/create-recurring-booking.input.ts +++ b/apps/api/v2/src/ee/bookings/2024-04-15/inputs/create-recurring-booking.input.ts @@ -21,7 +21,7 @@ export class CreateRecurringBookingInput_2024_04_15 extends CreateBookingInput_2 @IsOptional() @ApiPropertyOptional({ type: [Object] }) - allRecurringDates?: Record[]; + allRecurringDates?: { start: string; end: string | undefined }[]; @IsOptional() @IsNumber()