feat: add validation for null values in bookingFieldsResponses (#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>
This commit is contained in:
chauhan_s
2025-11-20 10:45:22 +00:00
committed by GitHub
co-authored by Morgan
parent 37c26793f5
commit fbfa27735b
2 changed files with 37 additions and 8 deletions
@@ -20,11 +20,7 @@ import { randomString } from "test/utils/randomString";
import { withApiAuth } from "test/utils/withApiAuth";
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_08_13 } from "@calcom/platform-constants";
import {
CreateBookingInput_2024_08_13,
GetBookingOutput_2024_08_13,
GetSeatedBookingOutput_2024_08_13,
} from "@calcom/platform-types";
import { CreateBookingInput_2024_08_13, GetBookingOutput_2024_08_13, GetSeatedBookingOutput_2024_08_13 } from "@calcom/platform-types";
import { BookingOutput_2024_08_13 } from "@calcom/platform-types";
import type { Booking, PlatformOAuthClient, Team, User, EventType } from "@calcom/prisma/client";
@@ -854,7 +850,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
describe("Booking Field Type Validation", () => {
const basePayload = {
start: "2025-06-19T11:00:00.000Z",
start: new Date(Date.UTC(2030, 5, 19, 11, 0, 0)).toISOString(),
attendee: {
name: "Charlie TypeTest",
email: "charlie.typetest@example.com",
@@ -1162,6 +1158,31 @@ describe("Bookings Endpoints 2024-08-13", () => {
`One or more invalid options for booking field '${fieldName}'. Allowed options are: blue, red.`
);
});
it("should transform null values to empty strings in bookingFieldsResponses", async () => {
const payload = {
...basePayload,
eventTypeId: eventTypeWithBookingFields.id,
bookingFieldsResponses: {
"favorite-movie": "The Matrix",
rescheduleReason: null,
notes: null,
},
};
const response = await request(app.getHttpServer())
.post(`/v2/bookings`)
.send(payload)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13);
expect(response.status).toBe(201);
expect(response.body.status).toEqual(SUCCESS_STATUS);
if (responseDataIsBooking(response.body.data)) {
const data: BookingOutput_2024_08_13 = response.body.data;
expect(data.bookingFieldsResponses.notes).toBe("");
expect(data.bookingFieldsResponses.rescheduleReason).toBe("");
expect(data.bookingFieldsResponses["favorite-movie"]).toBe("The Matrix");
}
});
});
afterAll(async () => {
@@ -1176,4 +1197,4 @@ describe("Bookings Endpoints 2024-08-13", () => {
function responseDataIsBooking(data: any): data is BookingOutput_2024_08_13 {
return !Array.isArray(data) && typeof data === "object" && data && "id" in data;
}
});
});
@@ -1,5 +1,5 @@
import { ApiExtraModels, ApiProperty, ApiPropertyOptional, getSchemaPath } from "@nestjs/swagger";
import { Type } from "class-transformer";
import { Transform, Type } from "class-transformer";
import type { ValidationArguments, ValidationOptions } from "class-validator";
import {
IsInt,
@@ -239,6 +239,14 @@ export class CreateBookingInput_2024_08_13 {
})
@IsObject()
@IsOptional()
@Transform(({ value }) => {
if (!value || typeof value !== "object") return value;
const transformed: Record<string, unknown> = {};
for (const [key, val] of Object.entries(value)) {
transformed[key] = val === null ? "" : val;
}
return transformed;
})
bookingFieldsResponses?: Record<string, unknown>;
@ApiPropertyOptional({