diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts index 44e9ddef629128..afcc028cec416e 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/controllers/event-types.controller.e2e-spec.ts @@ -368,7 +368,7 @@ describe("Event types Endpoints", () => { .expect(404); }); - it("should not be able to create phone-only event type", async () => { + it("should be able to create phone-only event type", async () => { const body: CreateEventTypeInput_2024_06_14 = { title: "Phone coding consultation", slug: "phone-coding-consultation", @@ -397,6 +397,43 @@ describe("Event types Endpoints", () => { ], }; + await request(app.getHttpServer()) + .post("/api/v2/event-types") + .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) + .set("Authorization", `Bearer ${apiKeyString}`) + .send(body) + .expect(200); + }); + + it("should throw error while both email and phone are hidden", async () => { + const body: CreateEventTypeInput_2024_06_14 = { + title: "Phone coding consultation", + slug: "phone-coding-consultation", + description: "Our team will review your codebase.", + lengthInMinutes: 60, + locations: [ + { + type: "integration", + integration: "cal-video", + }, + ], + bookingFields: [ + { + type: "email", + required: false, + label: "Email", + hidden: true, + }, + { + type: "phone", + slug: "attendeePhoneNumber", + required: false, + label: "Phone number", + hidden: true, + }, + ], + }; + const response = await request(app.getHttpServer()) .post("/api/v2/event-types") .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) @@ -405,7 +442,7 @@ describe("Event types Endpoints", () => { .expect(400); expect(response.body.error.message).toBe( - "checkIsEmailUserAccessible - Email booking field must be required and visible" + "Booking fields validation failed: visible and required email or visible and required attendee phone field is needed." ); }); diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts index 550e12f89cfc7f..2c4cae6e0ae701 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts @@ -21,6 +21,7 @@ import { updateEventType, getEventTypesPublic, EventTypesPublic, + ensureEmailOrPhoneNumberIsPresent, } from "@calcom/platform-libraries/event-types"; import type { GetEventTypesQuery_2024_06_14, SortOrderType } from "@calcom/platform-types"; import type { EventType } from "@calcom/prisma/client"; @@ -40,7 +41,7 @@ export class EventTypesService_2024_06_14 { async createUserEventType(user: UserWithProfile, body: InputEventTransformed_2024_06_14) { if (body.bookingFields) { - this.checkHasUserAccessibleEmailBookingField(body.bookingFields); + ensureEmailOrPhoneNumberIsPresent(body.bookingFields); } await this.checkCanCreateEventType(user.id, body); const eventTypeUser = await this.getUserToCreateEvent(user); @@ -117,16 +118,6 @@ export class EventTypesService_2024_06_14 { await this.checkUserOwnsSchedule(userId, body.scheduleId); } - checkHasUserAccessibleEmailBookingField(bookingFields: (SystemField | CustomField)[]) { - const emailField = bookingFields.find((field) => field.type === "email" && field.name === "email"); - const isEmailFieldRequiredAndVisible = emailField?.required && !emailField?.hidden; - if (!isEmailFieldRequiredAndVisible) { - throw new BadRequestException( - "checkIsEmailUserAccessible - Email booking field must be required and visible" - ); - } - } - async getEventTypeByUsernameAndSlug(params: { username: string; eventTypeSlug: string; @@ -307,7 +298,7 @@ export class EventTypesService_2024_06_14 { user: UserWithProfile ) { if (body.bookingFields) { - this.checkHasUserAccessibleEmailBookingField(body.bookingFields); + ensureEmailOrPhoneNumberIsPresent(body.bookingFields); } await this.checkCanUpdateEventType(user.id, eventTypeId, body.scheduleId); const eventTypeUser = await this.getUserToUpdateEvent(user); diff --git a/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts b/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts index 43a3f628650f91..249d05b32be765 100644 --- a/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts +++ b/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts @@ -232,7 +232,7 @@ describe("Organizations Event Types Endpoints", () => { return request(app.getHttpServer()).post(`/v2/teams/${team.id}/event-types`).send(body).expect(404); }); - it("should not be able to create phone-only event type", async () => { + it("should be able to create phone-only event type", async () => { const body: CreateTeamEventTypeInput_2024_06_14 = { title: "Phone coding consultation", slug: "phone-coding-consultation", @@ -273,12 +273,59 @@ describe("Organizations Event Types Endpoints", () => { ], }; + await request(app.getHttpServer()) + .post(`/v2/teams/${team.id}/event-types`) + .send(body) + .expect(200); + }); + + it("should throw error while both email and phone are hidden", async () => { + const body: CreateTeamEventTypeInput_2024_06_14 = { + title: "Phone coding consultation", + slug: "phone-coding-consultation", + description: "Our team will review your codebase.", + lengthInMinutes: 60, + locations: [ + { + type: "integration", + integration: "cal-video", + }, + { + type: "organizersDefaultApp", + }, + ], + schedulingType: "COLLECTIVE", + hosts: [ + { + userId: teamMember1.id, + }, + { + userId: teamMember2.id, + }, + ], + bookingFields: [ + { + type: "email", + required: false, + label: "Email", + hidden: true, + }, + { + type: "phone", + slug: "attendeePhoneNumber", + required: false, + label: "Phone number", + hidden: true, + }, + ], + }; + const response = await request(app.getHttpServer()) .post(`/v2/teams/${team.id}/event-types`) .send(body) .expect(400); expect(response.body.error.message).toBe( - "checkIsEmailUserAccessible - Email booking field must be required and visible" + "Booking fields validation failed: visible and required email or visible and required attendee phone field is needed." ); }); diff --git a/apps/api/v2/src/modules/teams/event-types/services/teams-event-types.service.ts b/apps/api/v2/src/modules/teams/event-types/services/teams-event-types.service.ts index 95e775d59c81e7..b82e35a7ec979d 100644 --- a/apps/api/v2/src/modules/teams/event-types/services/teams-event-types.service.ts +++ b/apps/api/v2/src/modules/teams/event-types/services/teams-event-types.service.ts @@ -13,7 +13,7 @@ import { Injectable, NotFoundException, Logger } from "@nestjs/common"; import type { SortOrderType } from "@calcom/platform-types"; -import { createEventType, updateEventType } from "@calcom/platform-libraries/event-types"; +import { createEventType, ensureEmailOrPhoneNumberIsPresent, updateEventType } from "@calcom/platform-libraries/event-types"; @Injectable() export class TeamsEventTypesService { @@ -32,9 +32,8 @@ export class TeamsEventTypesService { teamId: number, body: TransformedCreateTeamEventTypeInput ): Promise { - // note(Lauris): once phone only event types / bookings are enabled for simple users remove checkHasUserAccessibleEmailBookingField check if (body.bookingFields) { - this.eventTypesService.checkHasUserAccessibleEmailBookingField(body.bookingFields); + ensureEmailOrPhoneNumberIsPresent(body.bookingFields); } const eventTypeUser = await this.getUserToCreateTeamEvent(user); // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -116,8 +115,7 @@ export class TeamsEventTypesService { isOrg: boolean ): Promise { if (!isOrg && body.bookingFields) { - // note(Lauris): once phone only event types / bookings are enabled for simple users remove checkHasUserAccessibleEmailBookingField check - this.eventTypesService.checkHasUserAccessibleEmailBookingField(body.bookingFields); + ensureEmailOrPhoneNumberIsPresent(body.bookingFields); } await this.validateEventTypeExists(teamId, eventTypeId); const eventTypeUser = await this.eventTypesService.getUserToUpdateEvent(user); diff --git a/packages/platform/libraries/event-types.ts b/packages/platform/libraries/event-types.ts index 34a791c291b9e4..8b83570cf8a3f3 100644 --- a/packages/platform/libraries/event-types.ts +++ b/packages/platform/libraries/event-types.ts @@ -1,5 +1,7 @@ import EventManager from "@calcom/features/bookings/lib/EventManager"; +export { ensureEmailOrPhoneNumberIsPresent } from "@calcom/trpc/server/routers/viewer/eventTypes/util"; + export { getPublicEvent, type PublicEventType } from "@calcom/features/eventtypes/lib/getPublicEvent"; export { getBulkUserEventTypes, getBulkTeamEventTypes } from "@calcom/app-store/_utils/getBulkEventTypes";