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 8138d7e133..54c5ca7f53 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 @@ -34,6 +34,7 @@ import { SchedulingType } from "@calcom/platform-libraries"; import { BaseConfirmationPolicy_2024_06_14, TeamEventTypeOutput_2024_06_14, + supportedIntegrations, type ApiSuccessResponse, type CreateEventTypeInput_2024_06_14, type EventTypeOutput_2024_06_14, @@ -2901,6 +2902,119 @@ describe("Event types Endpoints", () => { }); }); + it("should accept newly supported integration locations in input validation", async () => { + // Test that the API accepts various newly supported integrations by creating event types + // with these location types directly in the database and then retrieving them + // Note: Database uses underscores in integration types, API returns hyphens + const integrationTests = [ + { internal: "integrations:jitsi", api: "jitsi" }, + { internal: "integrations:whereby_video", api: "whereby-video" }, + { internal: "integrations:huddle01", api: "huddle" }, + { internal: "integrations:tandem", api: "tandem" }, + { internal: "integrations:element-call_video", api: "element-call-video" }, + ]; + + for (const { internal, api } of integrationTests) { + const eventTypeInput = { + title: `event type ${api}`, + description: "event type description", + length: 30, + hidden: false, + slug: `event-type-${api}`, + locations: [ + { + type: internal, + link: `https://example.com/${api}/meeting`, + }, + ], + schedulingType: SchedulingType.ROUND_ROBIN, + bookingFields: [], + }; + + const legacyEventType = await eventTypesRepositoryFixture.create(eventTypeInput, user.id); + + const response = await request(app.getHttpServer()) + .get(`/api/v2/event-types/${legacyEventType.id}`) + .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) + .expect(200); + + const responseBody: ApiSuccessResponse = response.body; + const fetchedEventType = responseBody.data; + + // Verify the integration location is returned correctly + expect(fetchedEventType.locations).toHaveLength(1); + expect(fetchedEventType.locations[0]).toMatchObject({ + type: "integration", + integration: api, + }); + + // Clean up + await eventTypesRepositoryFixture.delete(legacyEventType.id); + } + }); + + it("should reject with 400 if creating event type with unsupported integration location", async () => { + const createPayload = { + title: "Event with unsupported integration", + slug: "event-with-unsupported-integration", + lengthInMinutes: 30, + locations: [ + { + type: "integration", + integration: "unsupported-integration", + }, + ], + }; + + const response = await request(app.getHttpServer()) + .post("/api/v2/event-types") + .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) + .send(createPayload); + + expect(response.status).toBe(400); + expect(response.body.error.message).toBe( + `Validation failed for integration location: integration must be one of the following values: ${supportedIntegrations.join( + ", " + )}` + ); + }); + + it("should reject with 400 if patching event type with integration that user has not connected", async () => { + const createPayload = { + title: "Event for patch test", + slug: "event-patch-test-unconnected-integration", + lengthInMinutes: 30, + }; + + const createResponse = await request(app.getHttpServer()) + .post("/api/v2/event-types") + .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) + .send(createPayload) + .expect(201); + + const createdEventType = createResponse.body.data; + + const patchPayload = { + locations: [ + { + type: "integration", + integration: "jitsi", + }, + ], + }; + + const patchResponse = await request(app.getHttpServer()) + .patch(`/api/v2/event-types/${createdEventType.id}`) + .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) + .send(patchPayload); + + expect(patchResponse.status).toBe(400); + expect(patchResponse.body.error.message).toBe("jitsi not connected."); + + // Cleanup + await eventTypesRepositoryFixture.delete(createdEventType.id); + }); + describe("EventType Hidden Property", () => { let createdEventTypeId: number; diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts index 879ba789a3..e6653e3656 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts @@ -39,6 +39,7 @@ import { InputBookingField_2024_06_14, OutputUnknownLocation_2024_06_14, UpdateEventTypeInput_2024_06_14, + supportedIntegrations, } from "@calcom/platform-types"; import { BookerLayouts } from "@calcom/prisma/zod-utils"; @@ -542,14 +543,40 @@ export class InputEventTypesService_2024_06_14 { } async checkAppIsValidAndConnected(user: UserWithProfile, appSlug: string) { - const conferencingApps = ["google-meet", "office365-video", "zoom"]; + const conferencingApps = supportedIntegrations as readonly string[]; if (!conferencingApps.includes(appSlug)) { throw new BadRequestException("Invalid app, available apps are: ", conferencingApps.join(", ")); } - if (appSlug === "office365-video") { - appSlug = "msteams"; - } + // Map API integration names to actual app slugs + const slugMap: Record = { + "office365-video": "msteams", + "facetime-video": "facetime", + "whereby-video": "whereby", + "whatsapp-video": "whatsapp", + "webex-video": "webex", + "telegram-video": "telegram", + "sylaps-video": "sylapsvideo", + "skype-video": "skype", + "sirius-video": "sirius_video", + "signal-video": "signal", + "shimmer-video": "shimmervideo", + "salesroom-video": "salesroom", + "roam-video": "roam", + "riverside-video": "riverside", + "ping-video": "ping", + "mirotalk-video": "mirotalk", + "jelly-video": "jelly", + "jelly-conferencing": "jelly", + "huddle": "huddle01", + "element-call-video": "element-call", + "eightxeight-video": "eightxeight", + "discord-video": "discord", + "demodesk-video": "demodesk", + "campfire-video": "campfire", + }; + + appSlug = slugMap[appSlug] || appSlug; const credentials = await getUsersCredentialsIncludeServiceAccountKey(user); diff --git a/docs/api-reference/v2/openapi.json b/docs/api-reference/v2/openapi.json index c9c9ab32f0..374cdea614 100644 --- a/docs/api-reference/v2/openapi.json +++ b/docs/api-reference/v2/openapi.json @@ -2819,6 +2819,7 @@ "organization.attributes.update", "organization.attributes.delete", "organization.attributes.create", + "organization.attributes.editUsers", "routingForm.create", "routingForm.read", "routingForm.update", @@ -16824,7 +16825,37 @@ "integration": { "type": "string", "example": "cal-video", - "enum": ["cal-video", "google-meet", "office365-video", "zoom"] + "enum": [ + "cal-video", + "google-meet", + "zoom", + "whereby-video", + "whatsapp-video", + "webex-video", + "telegram-video", + "tandem", + "sylaps-video", + "skype-video", + "sirius-video", + "signal-video", + "shimmer-video", + "salesroom-video", + "roam-video", + "riverside-video", + "ping-video", + "office365-video", + "mirotalk-video", + "jitsi", + "jelly-video", + "jelly-conferencing", + "huddle", + "facetime-video", + "element-call-video", + "eightxeight-video", + "discord-video", + "demodesk-video", + "campfire-video" + ] } }, "required": ["type", "integration"] @@ -18032,7 +18063,7 @@ }, "locations": { "type": "array", - "description": "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "description": "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", "items": { "oneOf": [ { @@ -19963,7 +19994,7 @@ }, "locations": { "type": "array", - "description": "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "description": "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", "items": { "oneOf": [ { @@ -21604,7 +21635,7 @@ }, "locations": { "type": "array", - "description": "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "description": "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", "items": { "oneOf": [ { @@ -22067,7 +22098,7 @@ }, "locations": { "type": "array", - "description": "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "description": "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", "items": { "oneOf": [ { @@ -26337,6 +26368,7 @@ "organization.attributes.update", "organization.attributes.delete", "organization.attributes.create", + "organization.attributes.editUsers", "routingForm.create", "routingForm.read", "routingForm.update", @@ -26440,6 +26472,7 @@ "organization.attributes.update", "organization.attributes.delete", "organization.attributes.create", + "organization.attributes.editUsers", "routingForm.create", "routingForm.read", "routingForm.update", @@ -26571,6 +26604,7 @@ "organization.attributes.update", "organization.attributes.delete", "organization.attributes.create", + "organization.attributes.editUsers", "routingForm.create", "routingForm.read", "routingForm.update", @@ -26673,6 +26707,7 @@ "organization.attributes.update", "organization.attributes.delete", "organization.attributes.create", + "organization.attributes.editUsers", "routingForm.create", "routingForm.read", "routingForm.update", diff --git a/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts b/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts index 2615896219..6c7031052c 100644 --- a/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts +++ b/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts @@ -518,7 +518,7 @@ export class CreateEventTypeInput_2024_06_14 extends BaseCreateEventTypeInput { @ValidateLocations_2024_06_14() @DocsPropertyOptional({ description: - "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", oneOf: [ { $ref: getSchemaPath(InputAddressLocation_2024_06_14) }, { $ref: getSchemaPath(InputLinkLocation_2024_06_14) }, @@ -607,7 +607,7 @@ export class CreateTeamEventTypeInput_2024_06_14 extends BaseCreateEventTypeInpu @ValidateTeamLocations_2024_06_14() @DocsPropertyOptional({ description: - "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", oneOf: [ { $ref: getSchemaPath(InputAddressLocation_2024_06_14) }, { $ref: getSchemaPath(InputLinkLocation_2024_06_14) }, diff --git a/packages/platform/types/event-types/event-types_2024_06_14/inputs/locations.input.ts b/packages/platform/types/event-types/event-types_2024_06_14/inputs/locations.input.ts index e6d280ab69..e5c9075404 100644 --- a/packages/platform/types/event-types/event-types_2024_06_14/inputs/locations.input.ts +++ b/packages/platform/types/event-types/event-types_2024_06_14/inputs/locations.input.ts @@ -54,7 +54,37 @@ export class InputLinkLocation_2024_06_14 { public!: boolean; } -export const supportedIntegrations = ["cal-video", "google-meet", "office365-video", "zoom"] as const; +export const supportedIntegrations = [ + "cal-video", + "google-meet", + "zoom", + "whereby-video", + "whatsapp-video", + "webex-video", + "telegram-video", + "tandem", + "sylaps-video", + "skype-video", + "sirius-video", + "signal-video", + "shimmer-video", + "salesroom-video", + "roam-video", + "riverside-video", + "ping-video", + "office365-video", + "mirotalk-video", + "jitsi", + "jelly-video", + "jelly-conferencing", + "huddle", + "facetime-video", + "element-call-video", + "eightxeight-video", + "discord-video", + "demodesk-video", + "campfire-video", +] as const; export type Integration_2024_06_14 = (typeof supportedIntegrations)[number]; export class InputIntegrationLocation_2024_06_14 { diff --git a/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts b/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts index 550c1c3e0b..12e67b972e 100644 --- a/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts +++ b/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts @@ -462,7 +462,7 @@ export class UpdateEventTypeInput_2024_06_14 extends BaseUpdateEventTypeInput { @ValidateLocations_2024_06_14() @DocsPropertyOptional({ description: - "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", oneOf: [ { $ref: getSchemaPath(InputAddressLocation_2024_06_14) }, { $ref: getSchemaPath(InputLinkLocation_2024_06_14) }, @@ -521,7 +521,7 @@ export class UpdateTeamEventTypeInput_2024_06_14 extends BaseUpdateEventTypeInpu @ValidateTeamLocations_2024_06_14() @DocsPropertyOptional({ description: - "Locations where the event will take place. If not provided, cal video link will be used as the location.", + "Locations where the event will take place. If not provided, cal video link will be used as the location. Note: Setting a location to a conferencing app does not install the app - the app must already be installed. Via API, only Google Meet (google-meet), Microsoft Teams (office365-video), and Zoom (zoom) can be installed. Cal Video (cal-video) is installed by default. All other conferencing apps must be connected via the Cal.com web app and are not available for Platform plan customers. You can only set an event type location to an app that has already been installed or connected.", oneOf: [ { $ref: getSchemaPath(InputAddressLocation_2024_06_14) }, { $ref: getSchemaPath(InputLinkLocation_2024_06_14) },