Skip to content

Commit fbfa277

Browse files
feat: add validation for null values in bookingFieldsResponses (calcom#25272)
* feat: add validation for null values in bookingFieldsResponses - Add test case to verify 400 error when bookingFieldsResponses contains null values - Create ValidateBookingFieldsResponses decorator to reject null values in booking field responses - Apply validator to CreateBookingInput_2024_08_13.bookingFieldsResponses property - Ensure all booking field response values are non-null strings * feat: transform null values to empty strings in bookingFieldsResponses - Remove ValidateBookingFieldsResponses validator that rejected null values - Add Transform decorator to convert null values to empty strings in bookingFieldsResponses - Update test to verify null values are transformed to empty strings instead of returning 400 error * remove extra spaces * test: add rescheduleReason null value test case --------- Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
1 parent 37c2679 commit fbfa277

2 files changed

Lines changed: 37 additions & 8 deletions

File tree

apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/booking-fields.e2e-spec.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ import { randomString } from "test/utils/randomString";
2020
import { withApiAuth } from "test/utils/withApiAuth";
2121

2222
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
23-
import {
24-
CreateBookingInput_2024_08_13,
25-
GetBookingOutput_2024_08_13,
26-
GetSeatedBookingOutput_2024_08_13,
27-
} from "@calcom/platform-types";
23+
import { CreateBookingInput_2024_08_13, GetBookingOutput_2024_08_13, GetSeatedBookingOutput_2024_08_13 } from "@calcom/platform-types";
2824
import { BookingOutput_2024_08_13 } from "@calcom/platform-types";
2925
import type { Booking, PlatformOAuthClient, Team, User, EventType } from "@calcom/prisma/client";
3026

@@ -854,7 +850,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
854850

855851
describe("Booking Field Type Validation", () => {
856852
const basePayload = {
857-
start: "2025-06-19T11:00:00.000Z",
853+
start: new Date(Date.UTC(2030, 5, 19, 11, 0, 0)).toISOString(),
858854
attendee: {
859855
name: "Charlie TypeTest",
860856
email: "charlie.typetest@example.com",
@@ -1162,6 +1158,31 @@ describe("Bookings Endpoints 2024-08-13", () => {
11621158
`One or more invalid options for booking field '${fieldName}'. Allowed options are: blue, red.`
11631159
);
11641160
});
1161+
1162+
it("should transform null values to empty strings in bookingFieldsResponses", async () => {
1163+
const payload = {
1164+
...basePayload,
1165+
eventTypeId: eventTypeWithBookingFields.id,
1166+
bookingFieldsResponses: {
1167+
"favorite-movie": "The Matrix",
1168+
rescheduleReason: null,
1169+
notes: null,
1170+
},
1171+
};
1172+
const response = await request(app.getHttpServer())
1173+
.post(`/v2/bookings`)
1174+
.send(payload)
1175+
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13);
1176+
expect(response.status).toBe(201);
1177+
expect(response.body.status).toEqual(SUCCESS_STATUS);
1178+
1179+
if (responseDataIsBooking(response.body.data)) {
1180+
const data: BookingOutput_2024_08_13 = response.body.data;
1181+
expect(data.bookingFieldsResponses.notes).toBe("");
1182+
expect(data.bookingFieldsResponses.rescheduleReason).toBe("");
1183+
expect(data.bookingFieldsResponses["favorite-movie"]).toBe("The Matrix");
1184+
}
1185+
});
11651186
});
11661187

11671188
afterAll(async () => {
@@ -1176,4 +1197,4 @@ describe("Bookings Endpoints 2024-08-13", () => {
11761197
function responseDataIsBooking(data: any): data is BookingOutput_2024_08_13 {
11771198
return !Array.isArray(data) && typeof data === "object" && data && "id" in data;
11781199
}
1179-
});
1200+
});

packages/platform/types/bookings/2024-08-13/inputs/create-booking.input.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ApiExtraModels, ApiProperty, ApiPropertyOptional, getSchemaPath } from "@nestjs/swagger";
2-
import { Type } from "class-transformer";
2+
import { Transform, Type } from "class-transformer";
33
import type { ValidationArguments, ValidationOptions } from "class-validator";
44
import {
55
IsInt,
@@ -239,6 +239,14 @@ export class CreateBookingInput_2024_08_13 {
239239
})
240240
@IsObject()
241241
@IsOptional()
242+
@Transform(({ value }) => {
243+
if (!value || typeof value !== "object") return value;
244+
const transformed: Record<string, unknown> = {};
245+
for (const [key, val] of Object.entries(value)) {
246+
transformed[key] = val === null ? "" : val;
247+
}
248+
return transformed;
249+
})
242250
bookingFieldsResponses?: Record<string, unknown>;
243251

244252
@ApiPropertyOptional({

0 commit comments

Comments
 (0)