fix: v2 event type locations (#17288)
* refactor: split internal locations in separate file * refactor: rename TransformedLocationsSchema to InternalLocationsSchema * feat: add missing locations in internal schema * refactor: explicit input locations only for input * refactor: explicit output locations only for output * fix: v2 * fix: atoms * test: internal to api locations transformation * e2e tests * upgrade platform libraries
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
"dependencies": {
|
||||
"@calcom/platform-constants": "*",
|
||||
"@calcom/platform-enums": "*",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.51",
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.52",
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
|
||||
"@calcom/platform-types": "*",
|
||||
"@calcom/platform-utils": "*",
|
||||
|
||||
+150
@@ -1251,4 +1251,154 @@ describe("Event types Endpoints", () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Handle event-types locations", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let oAuthClient: PlatformOAuthClient;
|
||||
let organization: Team;
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
|
||||
let teamRepositoryFixture: TeamRepositoryFixture;
|
||||
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
|
||||
|
||||
const userEmail = "locations-event-types-test-e2e@api.com";
|
||||
const name = "bob-the-locations-builder";
|
||||
const username = name;
|
||||
let user: User;
|
||||
let legacyEventTypeId1: number;
|
||||
let legacyEventTypeId2: number;
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await withApiAuth(
|
||||
userEmail,
|
||||
Test.createTestingModule({
|
||||
providers: [PrismaExceptionFilter, HttpExceptionFilter],
|
||||
imports: [AppModule, UsersModule, EventTypesModule_2024_06_14, TokensModule],
|
||||
})
|
||||
)
|
||||
.overrideGuard(PermissionsGuard)
|
||||
.useValue({
|
||||
canActivate: () => true,
|
||||
})
|
||||
.compile();
|
||||
|
||||
app = moduleRef.createNestApplication();
|
||||
bootstrap(app as NestExpressApplication);
|
||||
|
||||
oauthClientRepositoryFixture = new OAuthClientRepositoryFixture(moduleRef);
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
teamRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
|
||||
|
||||
organization = await teamRepositoryFixture.create({ name: "organization" });
|
||||
oAuthClient = await createOAuthClient(organization.id);
|
||||
user = await userRepositoryFixture.create({
|
||||
email: userEmail,
|
||||
name,
|
||||
username,
|
||||
});
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
async function createOAuthClient(organizationId: number) {
|
||||
const data = {
|
||||
logo: "logo-url",
|
||||
name: "name",
|
||||
redirectUris: ["redirect-uri"],
|
||||
permissions: 32,
|
||||
};
|
||||
const secret = "secret";
|
||||
|
||||
const client = await oauthClientRepositoryFixture.create(organizationId, data, secret);
|
||||
return client;
|
||||
}
|
||||
|
||||
it("should return integration location with link and credentialId", async () => {
|
||||
const eventTypeInput = {
|
||||
title: "event type discord",
|
||||
description: "event type description",
|
||||
length: 40,
|
||||
hidden: false,
|
||||
slug: "discord-event-type",
|
||||
locations: [
|
||||
{
|
||||
type: "integrations:discord_video",
|
||||
link: "https://discord.com/users/100",
|
||||
credentialId: 100,
|
||||
},
|
||||
],
|
||||
schedulingType: SchedulingType.ROUND_ROBIN,
|
||||
bookingFields: [],
|
||||
};
|
||||
const legacyEventType = await eventTypesRepositoryFixture.create(eventTypeInput, user.id);
|
||||
legacyEventTypeId1 = legacyEventType.id;
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types/${legacyEventTypeId1}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14> = response.body;
|
||||
const fetchedEventType = responseBody.data;
|
||||
expect(fetchedEventType.locations).toEqual([
|
||||
{
|
||||
type: "integration",
|
||||
integration: "discord-video",
|
||||
link: eventTypeInput.locations[0].link,
|
||||
credentialId: eventTypeInput.locations[0].credentialId,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it("should return unsupported location", async () => {
|
||||
const eventTypeInput = {
|
||||
title: "event type not existing",
|
||||
description: "event type description",
|
||||
length: 40,
|
||||
hidden: false,
|
||||
slug: "not-existing-event-type",
|
||||
locations: [
|
||||
{
|
||||
type: "this-type-does-not-exist",
|
||||
},
|
||||
],
|
||||
schedulingType: SchedulingType.ROUND_ROBIN,
|
||||
bookingFields: [],
|
||||
};
|
||||
const legacyEventType = await eventTypesRepositoryFixture.create(eventTypeInput, user.id);
|
||||
legacyEventTypeId1 = legacyEventType.id;
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.get(`/api/v2/event-types/${legacyEventTypeId1}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14> = response.body;
|
||||
const fetchedEventType = responseBody.data;
|
||||
expect(fetchedEventType.locations).toEqual([
|
||||
{ type: "unknown", location: JSON.stringify(eventTypeInput.locations[0]) },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await oauthClientRepositoryFixture.delete(oAuthClient.id);
|
||||
await teamRepositoryFixture.delete(organization.id);
|
||||
try {
|
||||
await eventTypesRepositoryFixture.delete(legacyEventTypeId1);
|
||||
await eventTypesRepositoryFixture.delete(legacyEventTypeId2);
|
||||
} catch (e) {
|
||||
// Event type might have been deleted by the test
|
||||
}
|
||||
try {
|
||||
await userRepositoryFixture.delete(user.id);
|
||||
} catch (e) {
|
||||
// User might have been deleted by the test
|
||||
}
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+17
-2
@@ -7,7 +7,7 @@ import {
|
||||
transformLocationsInternalToApi,
|
||||
transformBookingFieldsInternalToApi,
|
||||
parseRecurringEvent,
|
||||
TransformedLocationsSchema,
|
||||
InternalLocationSchema,
|
||||
BookingFieldsSchema,
|
||||
SystemField,
|
||||
CustomField,
|
||||
@@ -20,12 +20,14 @@ import {
|
||||
transformEventTypeColorsInternalToApi,
|
||||
parseEventTypeColor,
|
||||
transformSeatsInternalToApi,
|
||||
InternalLocation,
|
||||
} from "@calcom/platform-libraries";
|
||||
import {
|
||||
TransformFutureBookingsLimitSchema_2024_06_14,
|
||||
BookerLayoutsTransformedSchema,
|
||||
NoticeThresholdTransformedSchema,
|
||||
EventTypeOutput_2024_06_14,
|
||||
OutputUnknownLocation_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
type EventTypeRelations = {
|
||||
@@ -190,7 +192,20 @@ export class OutputEventTypesService_2024_06_14 {
|
||||
|
||||
transformLocations(locations: any) {
|
||||
if (!locations) return [];
|
||||
return transformLocationsInternalToApi(TransformedLocationsSchema.parse(locations));
|
||||
|
||||
const knownLocations: InternalLocation[] = [];
|
||||
const unknownLocations: OutputUnknownLocation_2024_06_14[] = [];
|
||||
|
||||
const parsedLocations = locations.map((location: any) => {
|
||||
const result = InternalLocationSchema.safeParse(location);
|
||||
if (result.success) {
|
||||
return knownLocations.push(result.data);
|
||||
} else {
|
||||
return unknownLocations.push({ type: "unknown", location: JSON.stringify(location) });
|
||||
}
|
||||
});
|
||||
|
||||
return [...transformLocationsInternalToApi(knownLocations), ...unknownLocations];
|
||||
}
|
||||
|
||||
transformDestinationCalendar(destinationCalendar?: DestinationCalendar | null) {
|
||||
|
||||
@@ -5485,6 +5485,9 @@
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/CreateManagedUserData"
|
||||
},
|
||||
"error": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -5849,7 +5852,7 @@
|
||||
"refreshToken"
|
||||
]
|
||||
},
|
||||
"AddressLocation_2024_06_14": {
|
||||
"InputAddressLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -5871,7 +5874,7 @@
|
||||
"public"
|
||||
]
|
||||
},
|
||||
"LinkLocation_2024_06_14": {
|
||||
"InputLinkLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -5893,7 +5896,7 @@
|
||||
"public"
|
||||
]
|
||||
},
|
||||
"IntegrationLocation_2024_06_14": {
|
||||
"InputIntegrationLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -5914,7 +5917,7 @@
|
||||
"integration"
|
||||
]
|
||||
},
|
||||
"PhoneLocation_2024_06_14": {
|
||||
"InputPhoneLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -6606,7 +6609,7 @@
|
||||
"showAvailabilityCount"
|
||||
]
|
||||
},
|
||||
"AttendeeAddressLocation_2024_06_14": {
|
||||
"InputAttendeeAddressLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -6619,7 +6622,7 @@
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"AttendeePhoneLocation_2024_06_14": {
|
||||
"InputAttendeePhoneLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -6632,7 +6635,7 @@
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"AttendeeDefinedLocation_2024_06_14": {
|
||||
"InputAttendeeDefinedLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
@@ -6734,25 +6737,25 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/LinkLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputLinkLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/IntegrationLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputIntegrationLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputPhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeAddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeePhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeePhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeDefinedLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeDefinedLocation_2024_06_14"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6943,6 +6946,219 @@
|
||||
"slug"
|
||||
]
|
||||
},
|
||||
"OutputAddressLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"address",
|
||||
"link",
|
||||
"integration",
|
||||
"phone",
|
||||
"attendeeAddress",
|
||||
"attendeePhone",
|
||||
"attendeeDefined"
|
||||
],
|
||||
"example": "address",
|
||||
"description": "only allowed value for type is `address`"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"example": "123 Example St, City, Country"
|
||||
},
|
||||
"public": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"address",
|
||||
"public"
|
||||
]
|
||||
},
|
||||
"OutputLinkLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"address",
|
||||
"link",
|
||||
"integration",
|
||||
"phone",
|
||||
"attendeeAddress",
|
||||
"attendeePhone",
|
||||
"attendeeDefined"
|
||||
],
|
||||
"example": "link",
|
||||
"description": "only allowed value for type is `link`"
|
||||
},
|
||||
"link": {
|
||||
"type": "string",
|
||||
"example": "https://customvideo.com/join/123456"
|
||||
},
|
||||
"public": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"link",
|
||||
"public"
|
||||
]
|
||||
},
|
||||
"OutputIntegrationLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"address",
|
||||
"link",
|
||||
"integration",
|
||||
"phone",
|
||||
"attendeeAddress",
|
||||
"attendeePhone",
|
||||
"attendeeDefined",
|
||||
"conferencing",
|
||||
"unknown"
|
||||
],
|
||||
"example": "integration",
|
||||
"description": "only allowed value for type is `integration`"
|
||||
},
|
||||
"integration": {
|
||||
"type": "string",
|
||||
"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",
|
||||
"campsite-conferencing",
|
||||
"campfire-video",
|
||||
"around-video"
|
||||
],
|
||||
"example": "cal-video"
|
||||
},
|
||||
"link": {
|
||||
"type": "string"
|
||||
},
|
||||
"credentialdId": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"integration"
|
||||
]
|
||||
},
|
||||
"OutputPhoneLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"address",
|
||||
"link",
|
||||
"integration",
|
||||
"phone",
|
||||
"attendeeAddress",
|
||||
"attendeePhone",
|
||||
"attendeeDefined"
|
||||
],
|
||||
"example": "phone",
|
||||
"description": "only allowed value for type is `phone`"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"example": "+37120993151"
|
||||
},
|
||||
"public": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"phone",
|
||||
"public"
|
||||
]
|
||||
},
|
||||
"OutputConferencingLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"address",
|
||||
"link",
|
||||
"integration",
|
||||
"phone",
|
||||
"attendeeAddress",
|
||||
"attendeePhone",
|
||||
"attendeeDefined",
|
||||
"conferencing",
|
||||
"unknown"
|
||||
],
|
||||
"example": "conferencing",
|
||||
"description": "only allowed value for type is `conferencing`"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"OutputUnknownLocation_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"address",
|
||||
"link",
|
||||
"integration",
|
||||
"phone",
|
||||
"attendeeAddress",
|
||||
"attendeePhone",
|
||||
"attendeeDefined",
|
||||
"conferencing",
|
||||
"unknown"
|
||||
],
|
||||
"example": "unknown",
|
||||
"description": "only allowed value for type is `unknown`"
|
||||
},
|
||||
"location": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"location"
|
||||
]
|
||||
},
|
||||
"EmailDefaultFieldOutput_2024_06_14": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7885,16 +8101,22 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/LinkLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputLinkLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/IntegrationLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputIntegrationLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputPhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/OutputConferencingLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/OutputUnknownLocation_2024_06_14"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8218,25 +8440,25 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/LinkLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputLinkLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/IntegrationLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputIntegrationLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputPhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeAddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeePhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeePhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeDefinedLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeDefinedLocation_2024_06_14"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9697,25 +9919,25 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/LinkLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputLinkLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/IntegrationLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputIntegrationLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputPhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeAddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeePhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeePhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeDefinedLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeDefinedLocation_2024_06_14"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10013,16 +10235,22 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/LinkLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputLinkLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/IntegrationLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputIntegrationLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/OutputPhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/OutputConferencingLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/OutputUnknownLocation_2024_06_14"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10433,25 +10661,25 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/LinkLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputLinkLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/IntegrationLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputIntegrationLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/PhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputPhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeAddressLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeAddressLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeePhoneLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeePhoneLocation_2024_06_14"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/AttendeeDefinedLocation_2024_06_14"
|
||||
"$ref": "#/components/schemas/InputAttendeeDefinedLocation_2024_06_14"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11425,7 +11653,8 @@
|
||||
"RECORDING_TRANSCRIPTION_GENERATED",
|
||||
"OOO_CREATED",
|
||||
"AFTER_HOSTS_CAL_VIDEO_NO_SHOW",
|
||||
"AFTER_GUESTS_CAL_VIDEO_NO_SHOW"
|
||||
"AFTER_GUESTS_CAL_VIDEO_NO_SHOW",
|
||||
"FORM_SUBMITTED_NO_EVENT"
|
||||
]
|
||||
},
|
||||
"active": {
|
||||
@@ -11501,7 +11730,8 @@
|
||||
"RECORDING_TRANSCRIPTION_GENERATED",
|
||||
"OOO_CREATED",
|
||||
"AFTER_HOSTS_CAL_VIDEO_NO_SHOW",
|
||||
"AFTER_GUESTS_CAL_VIDEO_NO_SHOW"
|
||||
"AFTER_GUESTS_CAL_VIDEO_NO_SHOW",
|
||||
"FORM_SUBMITTED_NO_EVENT"
|
||||
]
|
||||
},
|
||||
"active": {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from "@calcom/platform-enums/monorepo";
|
||||
import type {
|
||||
InputBookingField_2024_06_14,
|
||||
Location_2024_06_14,
|
||||
InputLocation_2024_06_14,
|
||||
BookingLimitsCount_2024_06_14,
|
||||
BookingWindow_2024_06_14,
|
||||
BookerLayouts_2024_06_14,
|
||||
@@ -19,9 +19,9 @@ import type {
|
||||
CreateEventTypeInput_2024_06_14,
|
||||
SeatOptionsTransformedSchema,
|
||||
SeatOptionsDisabledSchema,
|
||||
AttendeeAddressLocation_2024_06_14,
|
||||
AttendeePhoneLocation_2024_06_14,
|
||||
AttendeeDefinedLocation_2024_06_14,
|
||||
InputAttendeeAddressLocation_2024_06_14,
|
||||
InputAttendeePhoneLocation_2024_06_14,
|
||||
InputAttendeeDefinedLocation_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
import {
|
||||
@@ -45,7 +45,7 @@ import {
|
||||
|
||||
describe("transformLocationsApiToInternal", () => {
|
||||
it("should transform address", () => {
|
||||
const input: Location_2024_06_14[] = [
|
||||
const input: InputLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "address",
|
||||
address: "London road 10-1",
|
||||
@@ -61,7 +61,7 @@ describe("transformLocationsApiToInternal", () => {
|
||||
});
|
||||
|
||||
it("should transform link", () => {
|
||||
const input: Location_2024_06_14[] = [
|
||||
const input: InputLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "link",
|
||||
link: "https://customvideo.com/join/123456",
|
||||
@@ -79,7 +79,7 @@ describe("transformLocationsApiToInternal", () => {
|
||||
});
|
||||
|
||||
it("should transform integration", () => {
|
||||
const input: Location_2024_06_14[] = [
|
||||
const input: InputLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
@@ -94,7 +94,7 @@ describe("transformLocationsApiToInternal", () => {
|
||||
});
|
||||
|
||||
it("should transform phone", () => {
|
||||
const input: Location_2024_06_14[] = [
|
||||
const input: InputLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "phone",
|
||||
phone: "+37120993151",
|
||||
@@ -112,7 +112,7 @@ describe("transformLocationsApiToInternal", () => {
|
||||
});
|
||||
|
||||
it("should transform attendee address", () => {
|
||||
const input: AttendeeAddressLocation_2024_06_14[] = [
|
||||
const input: InputAttendeeAddressLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "attendeeAddress",
|
||||
},
|
||||
@@ -125,7 +125,7 @@ describe("transformLocationsApiToInternal", () => {
|
||||
});
|
||||
|
||||
it("should transform attendee phone", () => {
|
||||
const input: AttendeePhoneLocation_2024_06_14[] = [
|
||||
const input: InputAttendeePhoneLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "attendeePhone",
|
||||
},
|
||||
@@ -138,7 +138,7 @@ describe("transformLocationsApiToInternal", () => {
|
||||
});
|
||||
|
||||
it("should transform attendee defined", () => {
|
||||
const input: AttendeeDefinedLocation_2024_06_14[] = [
|
||||
const input: InputAttendeeDefinedLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "attendeeDefined",
|
||||
},
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { z } from "zod";
|
||||
import type { InputLocation_2024_06_14 } from "@calcom/platform-types";
|
||||
import { type Integration_2024_06_14 } from "@calcom/platform-types";
|
||||
|
||||
import { type CreateEventTypeInput_2024_06_14, type Integration_2024_06_14 } from "@calcom/platform-types";
|
||||
import type {
|
||||
AttendeeAddressLocation,
|
||||
AttendeeDefinedLocation,
|
||||
AttendeePhoneLocation,
|
||||
OrganizerAddressLocation,
|
||||
OrganizerIntegrationLocation,
|
||||
OrganizerLinkLocation,
|
||||
OrganizerPhoneLocation,
|
||||
} from "../internal/locations";
|
||||
|
||||
const integrationsMapping: Record<Integration_2024_06_14, "integrations:daily"> = {
|
||||
const apiToInternalintegrationsMapping: Record<Integration_2024_06_14, "integrations:daily"> = {
|
||||
"cal-video": "integrations:daily",
|
||||
};
|
||||
|
||||
export function transformLocationsApiToInternal(
|
||||
inputLocations: CreateEventTypeInput_2024_06_14["locations"]
|
||||
) {
|
||||
export function transformLocationsApiToInternal(inputLocations: InputLocation_2024_06_14[] | undefined) {
|
||||
if (!inputLocations) {
|
||||
return [];
|
||||
}
|
||||
@@ -31,7 +38,7 @@ export function transformLocationsApiToInternal(
|
||||
displayLocationPublicly: location.public,
|
||||
} satisfies OrganizerLinkLocation;
|
||||
case "integration":
|
||||
const integrationLabel = integrationsMapping[location.integration];
|
||||
const integrationLabel = apiToInternalintegrationsMapping[location.integration];
|
||||
return { type: integrationLabel } satisfies OrganizerIntegrationLocation;
|
||||
case "phone":
|
||||
return {
|
||||
@@ -44,69 +51,7 @@ export function transformLocationsApiToInternal(
|
||||
case "attendeeDefined":
|
||||
return { type: "somewhereElse" } satisfies AttendeeDefinedLocation;
|
||||
default:
|
||||
throw new Error(`Unsupported location type '${type}'`);
|
||||
throw new Error(`Unsupported input location type '${type}'`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const integrationsMappingSchema = {
|
||||
"cal-video": z.literal("integrations:daily"),
|
||||
};
|
||||
|
||||
const OrganizerAddressSchema = z.object({
|
||||
type: z.literal("inPerson"),
|
||||
address: z.string(),
|
||||
displayLocationPublicly: z.boolean().default(false),
|
||||
});
|
||||
|
||||
const OrganizerLinkSchema = z.object({
|
||||
type: z.literal("link"),
|
||||
link: z.string().url(),
|
||||
displayLocationPublicly: z.boolean().default(false),
|
||||
});
|
||||
|
||||
const OrganizerIntegrationSchema = z.object({
|
||||
type: z.union([integrationsMappingSchema["cal-video"], integrationsMappingSchema["cal-video"]]),
|
||||
});
|
||||
|
||||
const OrganizerPhoneSchema = z.object({
|
||||
type: z.literal("userPhone"),
|
||||
hostPhoneNumber: z.string(),
|
||||
displayLocationPublicly: z.boolean().default(false),
|
||||
});
|
||||
|
||||
const OrganizerConferencingSchema = z.object({
|
||||
type: z.literal("conferencing"),
|
||||
});
|
||||
|
||||
const AttendeeAddressSchema = z.object({
|
||||
type: z.literal("attendeeInPerson"),
|
||||
});
|
||||
|
||||
const AttendeePhoneSchema = z.object({
|
||||
type: z.literal("phone"),
|
||||
});
|
||||
|
||||
const AttendeeDefinedSchema = z.object({
|
||||
type: z.literal("somewhereElse"),
|
||||
});
|
||||
|
||||
type OrganizerAddressLocation = z.infer<typeof OrganizerAddressSchema>;
|
||||
type OrganizerLinkLocation = z.infer<typeof OrganizerLinkSchema>;
|
||||
export type OrganizerIntegrationLocation = z.infer<typeof OrganizerIntegrationSchema>;
|
||||
type OrganizerPhoneLocation = z.infer<typeof OrganizerPhoneSchema>;
|
||||
type AttendeeAddressLocation = z.infer<typeof AttendeeAddressSchema>;
|
||||
type AttendeePhoneLocation = z.infer<typeof AttendeePhoneSchema>;
|
||||
type AttendeeDefinedLocation = z.infer<typeof AttendeeDefinedSchema>;
|
||||
|
||||
const TransformedLocationSchema = z.union([
|
||||
OrganizerAddressSchema,
|
||||
OrganizerLinkSchema,
|
||||
OrganizerIntegrationSchema,
|
||||
OrganizerPhoneSchema,
|
||||
OrganizerConferencingSchema,
|
||||
AttendeeAddressSchema,
|
||||
AttendeePhoneSchema,
|
||||
AttendeeDefinedSchema,
|
||||
]);
|
||||
export const TransformedLocationsSchema = z.array(TransformedLocationSchema);
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./api-to-internal";
|
||||
export * from "./internal-to-api";
|
||||
export * from "./internal/locations";
|
||||
|
||||
@@ -7,10 +7,6 @@ import {
|
||||
NoticeThresholdUnitEnum,
|
||||
} from "@calcom/platform-enums/monorepo";
|
||||
import type {
|
||||
AddressLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
TransformBookingLimitsSchema_2024_06_14,
|
||||
TransformFutureBookingsLimitSchema_2024_06_14,
|
||||
BookerLayoutsTransformedSchema,
|
||||
@@ -18,9 +14,14 @@ import type {
|
||||
TransformRecurringEventSchema_2024_06_14,
|
||||
SeatOptionsTransformedSchema,
|
||||
SeatOptionsDisabledSchema,
|
||||
AttendeeAddressLocation_2024_06_14,
|
||||
AttendeePhoneLocation_2024_06_14,
|
||||
AttendeeDefinedLocation_2024_06_14,
|
||||
OutputAddressLocation_2024_06_14,
|
||||
OutputAttendeeAddressLocation_2024_06_14,
|
||||
OutputAttendeeDefinedLocation_2024_06_14,
|
||||
OutputAttendeePhoneLocation_2024_06_14,
|
||||
OutputIntegrationLocation_2024_06_14,
|
||||
OutputLinkLocation_2024_06_14,
|
||||
OutputPhoneLocation_2024_06_14,
|
||||
OutputUnknownLocation_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
import {
|
||||
@@ -51,7 +52,7 @@ describe("transformLocationsInternalToApi", () => {
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: AddressLocation_2024_06_14[] = [
|
||||
const expectedOutput: OutputAddressLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "address",
|
||||
address: "1234 Main St",
|
||||
@@ -73,7 +74,7 @@ describe("transformLocationsInternalToApi", () => {
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: LinkLocation_2024_06_14[] = [
|
||||
const expectedOutput: OutputLinkLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "link",
|
||||
link: "https://example.com",
|
||||
@@ -95,7 +96,7 @@ describe("transformLocationsInternalToApi", () => {
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: PhoneLocation_2024_06_14[] = [
|
||||
const expectedOutput: OutputPhoneLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "phone",
|
||||
phone: "123456789",
|
||||
@@ -115,7 +116,7 @@ describe("transformLocationsInternalToApi", () => {
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: IntegrationLocation_2024_06_14[] = [
|
||||
const expectedOutput: OutputIntegrationLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "cal-video",
|
||||
@@ -127,6 +128,91 @@ describe("transformLocationsInternalToApi", () => {
|
||||
expect(result).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("should transform integration location", () => {
|
||||
const transformedLocation = [
|
||||
{
|
||||
type: "integrations:discord_video" as const,
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: OutputIntegrationLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "discord-video",
|
||||
},
|
||||
];
|
||||
|
||||
const result = transformLocationsInternalToApi(transformedLocation);
|
||||
|
||||
expect(result).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("should transform integration location with link and credentialId", () => {
|
||||
const transformedLocation = [
|
||||
{
|
||||
type: "integrations:discord_video" as const,
|
||||
link: "https://discord.com/users/100",
|
||||
credentialId: 100,
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: OutputIntegrationLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "integration",
|
||||
integration: "discord-video",
|
||||
link: "https://discord.com/users/100",
|
||||
credentialId: 100,
|
||||
},
|
||||
];
|
||||
|
||||
const result = transformLocationsInternalToApi(transformedLocation);
|
||||
|
||||
expect(result).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("should transform unknown location", () => {
|
||||
const transformedLocation = [
|
||||
{
|
||||
type: "unknown" as const,
|
||||
location: "unknown location",
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: OutputUnknownLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "unknown",
|
||||
location: JSON.stringify(transformedLocation[0]),
|
||||
},
|
||||
];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const result = transformLocationsInternalToApi(transformedLocation);
|
||||
|
||||
expect(result).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("should transform unknown integration location", () => {
|
||||
const transformedLocation = [
|
||||
{
|
||||
type: "integrations:unknown_video" as const,
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: OutputUnknownLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "unknown",
|
||||
location: JSON.stringify(transformedLocation[0]),
|
||||
},
|
||||
];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const result = transformLocationsInternalToApi(transformedLocation);
|
||||
|
||||
expect(result).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it("should reverse transform attendee address location", () => {
|
||||
const transformedLocation = [
|
||||
{
|
||||
@@ -134,7 +220,7 @@ describe("transformLocationsInternalToApi", () => {
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: AttendeeAddressLocation_2024_06_14[] = [
|
||||
const expectedOutput: OutputAttendeeAddressLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "attendeeAddress",
|
||||
},
|
||||
@@ -151,7 +237,7 @@ describe("transformLocationsInternalToApi", () => {
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: AttendeePhoneLocation_2024_06_14[] = [
|
||||
const expectedOutput: OutputAttendeePhoneLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "attendeePhone",
|
||||
},
|
||||
@@ -168,7 +254,7 @@ describe("transformLocationsInternalToApi", () => {
|
||||
},
|
||||
];
|
||||
|
||||
const expectedOutput: AttendeeDefinedLocation_2024_06_14[] = [
|
||||
const expectedOutput: OutputAttendeeDefinedLocation_2024_06_14[] = [
|
||||
{
|
||||
type: "attendeeDefined",
|
||||
},
|
||||
@@ -208,11 +294,11 @@ describe("transformBookingFieldsInternalToApi", () => {
|
||||
fullName: {
|
||||
fields: [
|
||||
{
|
||||
name: "fullName",
|
||||
name: "fullName" as const,
|
||||
label: "custom label",
|
||||
placeholder: "custom placeholder",
|
||||
type: "text",
|
||||
required: true,
|
||||
type: "text" as const,
|
||||
required: true as const,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,34 +1,64 @@
|
||||
import type {
|
||||
AddressLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
Integration_2024_06_14,
|
||||
AttendeePhoneLocation_2024_06_14,
|
||||
AttendeeAddressLocation_2024_06_14,
|
||||
AttendeeDefinedLocation_2024_06_14,
|
||||
OutputConferencingLocation_2024_06_14,
|
||||
OutputIntegration_2024_06_14,
|
||||
OutputIntegrationLocation_2024_06_14,
|
||||
OutputAddressLocation_2024_06_14,
|
||||
OutputAttendeeAddressLocation_2024_06_14,
|
||||
OutputAttendeeDefinedLocation_2024_06_14,
|
||||
OutputAttendeePhoneLocation_2024_06_14,
|
||||
OutputLinkLocation_2024_06_14,
|
||||
OutputPhoneLocation_2024_06_14,
|
||||
OutputUnknownLocation_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
import type { transformLocationsApiToInternal } from "../api-to-internal";
|
||||
import type { InternalLocation } from "../internal/locations";
|
||||
|
||||
const reverseIntegrationsMapping: Record<string, Integration_2024_06_14> = {
|
||||
const internalToApiIntegrationsMapping: Record<string, OutputIntegration_2024_06_14> = {
|
||||
"integrations:daily": "cal-video",
|
||||
"integrations:google:meet": "google-meet",
|
||||
"integrations:zoom": "zoom",
|
||||
"integrations:whereby_video": "whereby-video",
|
||||
"integrations:whatsapp_video": "whatsapp-video",
|
||||
"integrations:webex_video": "webex-video",
|
||||
"integrations:telegram_video": "telegram-video",
|
||||
"integrations:tandem": "tandem",
|
||||
"integrations:sylaps_video": "sylaps-video",
|
||||
"integrations:skype_video": "skype-video",
|
||||
"integrations:sirius_video_video": "sirius-video",
|
||||
"integrations:signal_video": "signal-video",
|
||||
"integrations:shimmer_video": "shimmer-video",
|
||||
"integrations:salesroom_video": "salesroom-video",
|
||||
"integrations:roam_video": "roam-video",
|
||||
"integrations:riverside_video": "riverside-video",
|
||||
"integrations:ping_video": "ping-video",
|
||||
"integrations:office365_video": "office365-video",
|
||||
"integrations:mirotalk_video": "mirotalk-video",
|
||||
"integrations:jitsi": "jitsi",
|
||||
"integrations:jelly_video": "jelly-video",
|
||||
"integrations:jelly_conferencing": "jelly-conferencing",
|
||||
"integrations:huddle01": "huddle",
|
||||
"integrations:facetime_video": "facetime-video",
|
||||
"integrations:element-call_video": "element-call-video",
|
||||
"integrations:eightxeight_video": "eightxeight-video",
|
||||
"integrations:discord_video": "discord-video",
|
||||
"integrations:demodesk_video": "demodesk-video",
|
||||
"integrations:campsite_conferencing": "campsite-conferencing",
|
||||
"integrations:campfire_video": "campfire-video",
|
||||
"integrations:around_video": "around-video",
|
||||
};
|
||||
|
||||
export function transformLocationsInternalToApi(
|
||||
transformedLocations: ReturnType<typeof transformLocationsApiToInternal>
|
||||
) {
|
||||
if (!transformedLocations) {
|
||||
export function transformLocationsInternalToApi(internalLocations: InternalLocation[] | undefined) {
|
||||
if (!internalLocations) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return transformedLocations.map((location) => {
|
||||
return internalLocations.map((location) => {
|
||||
switch (location.type) {
|
||||
case "inPerson": {
|
||||
if (!location.address) {
|
||||
throw new Error("Address location must have an address");
|
||||
}
|
||||
const addressLocation: AddressLocation_2024_06_14 = {
|
||||
const addressLocation: OutputAddressLocation_2024_06_14 = {
|
||||
type: "address",
|
||||
address: location.address,
|
||||
public: location.displayLocationPublicly,
|
||||
@@ -36,7 +66,7 @@ export function transformLocationsInternalToApi(
|
||||
return addressLocation;
|
||||
}
|
||||
case "attendeeInPerson": {
|
||||
const attendeeAddressLocation: AttendeeAddressLocation_2024_06_14 = {
|
||||
const attendeeAddressLocation: OutputAttendeeAddressLocation_2024_06_14 = {
|
||||
type: "attendeeAddress",
|
||||
};
|
||||
return attendeeAddressLocation;
|
||||
@@ -45,7 +75,7 @@ export function transformLocationsInternalToApi(
|
||||
if (!location.link) {
|
||||
throw new Error("Link location must have a link");
|
||||
}
|
||||
const linkLocation: LinkLocation_2024_06_14 = {
|
||||
const linkLocation: OutputLinkLocation_2024_06_14 = {
|
||||
type: "link",
|
||||
link: location.link,
|
||||
public: location.displayLocationPublicly,
|
||||
@@ -56,7 +86,7 @@ export function transformLocationsInternalToApi(
|
||||
if (!location.hostPhoneNumber) {
|
||||
throw new Error("Phone location must have a phone number");
|
||||
}
|
||||
const phoneLocation: PhoneLocation_2024_06_14 = {
|
||||
const phoneLocation: OutputPhoneLocation_2024_06_14 = {
|
||||
type: "phone",
|
||||
phone: location.hostPhoneNumber,
|
||||
public: location.displayLocationPublicly,
|
||||
@@ -64,25 +94,37 @@ export function transformLocationsInternalToApi(
|
||||
return phoneLocation;
|
||||
}
|
||||
case "phone": {
|
||||
const attendeePhoneLocation: AttendeePhoneLocation_2024_06_14 = {
|
||||
const attendeePhoneLocation: OutputAttendeePhoneLocation_2024_06_14 = {
|
||||
type: "attendeePhone",
|
||||
};
|
||||
return attendeePhoneLocation;
|
||||
}
|
||||
case "somewhereElse": {
|
||||
const attendeeDefinedLocation: AttendeeDefinedLocation_2024_06_14 = {
|
||||
const attendeeDefinedLocation: OutputAttendeeDefinedLocation_2024_06_14 = {
|
||||
type: "attendeeDefined",
|
||||
};
|
||||
return attendeeDefinedLocation;
|
||||
}
|
||||
case "conferencing": {
|
||||
const conferencingLocation: OutputConferencingLocation_2024_06_14 = {
|
||||
type: "conferencing",
|
||||
};
|
||||
return conferencingLocation;
|
||||
}
|
||||
default: {
|
||||
const integrationType = reverseIntegrationsMapping[location.type];
|
||||
const integrationType = internalToApiIntegrationsMapping[location.type];
|
||||
if (!integrationType) {
|
||||
throw new Error(`Unsupported integration type '${location.type}'.`);
|
||||
const unknown: OutputUnknownLocation_2024_06_14 = {
|
||||
type: "unknown",
|
||||
location: JSON.stringify(location),
|
||||
};
|
||||
return unknown;
|
||||
}
|
||||
const integration: IntegrationLocation_2024_06_14 = {
|
||||
const integration: OutputIntegrationLocation_2024_06_14 = {
|
||||
type: "integration",
|
||||
integration: integrationType,
|
||||
link: location.link,
|
||||
credentialId: location.credentialId,
|
||||
};
|
||||
return integration;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const integrationsApiAvailable = {
|
||||
"cal-video": z.literal("integrations:daily"),
|
||||
};
|
||||
|
||||
// note(Lauris): these are read only aka they exist in database and are to be returned by a READ operation
|
||||
const integrationsApiUnavailable = {
|
||||
"google-meet": z.literal("integrations:google:meet"),
|
||||
zoom: z.literal("integrations:zoom"),
|
||||
"whereby-video": z.literal("integrations:whereby_video"),
|
||||
"whatsapp-video": z.literal("integrations:whatsapp_video"),
|
||||
"webex-video": z.literal("integrations:webex_video"),
|
||||
"telegram-video": z.literal("integrations:telegram_video"),
|
||||
tandem: z.literal("integrations:tandem"),
|
||||
"sylaps-video": z.literal("integrations:sylaps_video"),
|
||||
"skype-video": z.literal("integrations:skype_video"),
|
||||
"sirius-video": z.literal("integrations:sirius_video_video"),
|
||||
"signal-video": z.literal("integrations:signal_video"),
|
||||
"shimmer-video": z.literal("integrations:shimmer_video"),
|
||||
"salesroom-video": z.literal("integrations:salesroom_video"),
|
||||
"roam-video": z.literal("integrations:roam_video"),
|
||||
"riverside-video": z.literal("integrations:riverside_video"),
|
||||
"ping-video": z.literal("integrations:ping_video"),
|
||||
"office365-video": z.literal("integrations:office365_video"),
|
||||
"mirotalk-video": z.literal("integrations:mirotalk_video"),
|
||||
jitsi: z.literal("integrations:jitsi"),
|
||||
"jelly-video": z.literal("integrations:jelly_video"),
|
||||
"jelly-conferencing": z.literal("integrations:jelly_conferencing"),
|
||||
huddle: z.literal("integrations:huddle01"),
|
||||
"facetime-video": z.literal("integrations:facetime_video"),
|
||||
"element-call-video": z.literal("integrations:element-call_video"),
|
||||
"eightxeight-video": z.literal("integrations:eightxeight_video"),
|
||||
"discord-video": z.literal("integrations:discord_video"),
|
||||
"demodesk-video": z.literal("integrations:demodesk_video"),
|
||||
"campsite-conferencing": z.literal("integrations:campsite_conferencing"),
|
||||
"campfire-video": z.literal("integrations:campfire_video"),
|
||||
"around-video": z.literal("integrations:around_video"),
|
||||
};
|
||||
|
||||
export const integrationsApiToInternalMappingSchema = {
|
||||
...integrationsApiAvailable,
|
||||
...integrationsApiUnavailable,
|
||||
};
|
||||
|
||||
const OrganizerIntegrationSchema = z.object({
|
||||
type: z.union([
|
||||
integrationsApiToInternalMappingSchema["cal-video"],
|
||||
integrationsApiToInternalMappingSchema["google-meet"],
|
||||
integrationsApiToInternalMappingSchema["zoom"],
|
||||
integrationsApiToInternalMappingSchema["whereby-video"],
|
||||
integrationsApiToInternalMappingSchema["whatsapp-video"],
|
||||
integrationsApiToInternalMappingSchema["webex-video"],
|
||||
integrationsApiToInternalMappingSchema["telegram-video"],
|
||||
integrationsApiToInternalMappingSchema["tandem"],
|
||||
integrationsApiToInternalMappingSchema["sylaps-video"],
|
||||
integrationsApiToInternalMappingSchema["skype-video"],
|
||||
integrationsApiToInternalMappingSchema["sirius-video"],
|
||||
integrationsApiToInternalMappingSchema["signal-video"],
|
||||
integrationsApiToInternalMappingSchema["shimmer-video"],
|
||||
integrationsApiToInternalMappingSchema["salesroom-video"],
|
||||
integrationsApiToInternalMappingSchema["roam-video"],
|
||||
integrationsApiToInternalMappingSchema["riverside-video"],
|
||||
integrationsApiToInternalMappingSchema["ping-video"],
|
||||
integrationsApiToInternalMappingSchema["office365-video"],
|
||||
integrationsApiToInternalMappingSchema["mirotalk-video"],
|
||||
integrationsApiToInternalMappingSchema["jitsi"],
|
||||
integrationsApiToInternalMappingSchema["jelly-video"],
|
||||
integrationsApiToInternalMappingSchema["jelly-conferencing"],
|
||||
integrationsApiToInternalMappingSchema["huddle"],
|
||||
integrationsApiToInternalMappingSchema["facetime-video"],
|
||||
integrationsApiToInternalMappingSchema["element-call-video"],
|
||||
integrationsApiToInternalMappingSchema["eightxeight-video"],
|
||||
integrationsApiToInternalMappingSchema["discord-video"],
|
||||
integrationsApiToInternalMappingSchema["demodesk-video"],
|
||||
integrationsApiToInternalMappingSchema["campsite-conferencing"],
|
||||
integrationsApiToInternalMappingSchema["campfire-video"],
|
||||
integrationsApiToInternalMappingSchema["around-video"],
|
||||
]),
|
||||
link: z.string().url().optional(),
|
||||
credentialId: z.number().optional(),
|
||||
});
|
||||
|
||||
const OrganizerAddressSchema = z.object({
|
||||
type: z.literal("inPerson"),
|
||||
address: z.string(),
|
||||
displayLocationPublicly: z.boolean().default(false),
|
||||
});
|
||||
|
||||
const OrganizerLinkSchema = z.object({
|
||||
type: z.literal("link"),
|
||||
link: z.string().url(),
|
||||
displayLocationPublicly: z.boolean().default(false),
|
||||
});
|
||||
|
||||
const OrganizerPhoneSchema = z.object({
|
||||
type: z.literal("userPhone"),
|
||||
hostPhoneNumber: z.string(),
|
||||
displayLocationPublicly: z.boolean().default(false),
|
||||
});
|
||||
|
||||
const OrganizerConferencingSchema = z.object({
|
||||
type: z.literal("conferencing"),
|
||||
});
|
||||
|
||||
const AttendeeAddressSchema = z.object({
|
||||
type: z.literal("attendeeInPerson"),
|
||||
});
|
||||
|
||||
const AttendeePhoneSchema = z.object({
|
||||
type: z.literal("phone"),
|
||||
});
|
||||
|
||||
const AttendeeDefinedSchema = z.object({
|
||||
type: z.literal("somewhereElse"),
|
||||
});
|
||||
|
||||
export type OrganizerAddressLocation = z.infer<typeof OrganizerAddressSchema>;
|
||||
export type OrganizerLinkLocation = z.infer<typeof OrganizerLinkSchema>;
|
||||
export type OrganizerIntegrationLocation = z.infer<typeof OrganizerIntegrationSchema>;
|
||||
export type OrganizerPhoneLocation = z.infer<typeof OrganizerPhoneSchema>;
|
||||
export type OrganizerConferencingSchema = z.infer<typeof OrganizerConferencingSchema>;
|
||||
export type AttendeeAddressLocation = z.infer<typeof AttendeeAddressSchema>;
|
||||
export type AttendeePhoneLocation = z.infer<typeof AttendeePhoneSchema>;
|
||||
export type AttendeeDefinedLocation = z.infer<typeof AttendeeDefinedSchema>;
|
||||
|
||||
export const InternalLocationSchema = z.union([
|
||||
OrganizerAddressSchema,
|
||||
OrganizerLinkSchema,
|
||||
OrganizerIntegrationSchema,
|
||||
OrganizerPhoneSchema,
|
||||
OrganizerConferencingSchema,
|
||||
AttendeeAddressSchema,
|
||||
AttendeePhoneSchema,
|
||||
AttendeeDefinedSchema,
|
||||
]);
|
||||
export type InternalLocation = z.infer<typeof InternalLocationSchema>;
|
||||
|
||||
export const InternalLocationsSchema = z.array(InternalLocationSchema);
|
||||
+18
-1
@@ -14,6 +14,7 @@ import type {
|
||||
CustomFieldOutput_2024_06_14,
|
||||
EmailDefaultFieldOutput_2024_06_14,
|
||||
EventTypeOutput_2024_06_14,
|
||||
InputLocation_2024_06_14,
|
||||
NameDefaultFieldOutput_2024_06_14,
|
||||
TeamEventTypeOutput_2024_06_14,
|
||||
} from "@calcom/platform-types";
|
||||
@@ -199,7 +200,9 @@ function isDefaultEvent(eventSlug: string) {
|
||||
}
|
||||
|
||||
function getLocations(locations: EventTypeOutput_2024_06_14["locations"]) {
|
||||
const transformed = transformLocationsApiToInternal(locations);
|
||||
const transformed = transformLocationsApiToInternal(
|
||||
locations.filter((location) => isAtomSupportedLocation(location))
|
||||
);
|
||||
|
||||
const withPrivateHidden = transformed.map((location) => {
|
||||
const { displayLocationPublicly, type } = location;
|
||||
@@ -224,6 +227,20 @@ function getLocations(locations: EventTypeOutput_2024_06_14["locations"]) {
|
||||
return withPrivateHidden;
|
||||
}
|
||||
|
||||
function isAtomSupportedLocation(
|
||||
location: EventTypeOutput_2024_06_14["locations"][number]
|
||||
): location is InputLocation_2024_06_14 {
|
||||
return (
|
||||
location.type === "address" ||
|
||||
location.type === "attendeeAddress" ||
|
||||
location.type === "link" ||
|
||||
location.type === "phone" ||
|
||||
location.type === "attendeePhone" ||
|
||||
location.type === "attendeeDefined" ||
|
||||
(location.type === "integration" && location.integration === "cal-video")
|
||||
);
|
||||
}
|
||||
|
||||
function getBookingFields(
|
||||
bookingFields: EventTypeOutput_2024_06_14["bookingFields"],
|
||||
defaultFormValues: BookerPlatformWrapperAtomProps["defaultFormValues"] | undefined
|
||||
|
||||
@@ -126,7 +126,8 @@ export {
|
||||
transformEventTypeColorsInternalToApi,
|
||||
transformSeatsInternalToApi,
|
||||
// note(Lauris): schemas
|
||||
TransformedLocationsSchema,
|
||||
InternalLocationsSchema,
|
||||
InternalLocationSchema,
|
||||
BookingFieldsSchema,
|
||||
// note(Lauris): constants
|
||||
systemBeforeFieldName,
|
||||
@@ -140,6 +141,7 @@ export type {
|
||||
CustomField,
|
||||
NameSystemField,
|
||||
EmailSystemField,
|
||||
InternalLocation,
|
||||
} from "@calcom/lib/event-types/transformers";
|
||||
|
||||
export { parseBookingLimit, parseEventTypeColor } from "@calcom/lib";
|
||||
|
||||
+23
-23
@@ -54,16 +54,16 @@ import { DestinationCalendar_2024_06_14 } from "./destination-calendar.input";
|
||||
import { Disabled_2024_06_14 } from "./disabled.input";
|
||||
import { EventTypeColor_2024_06_14 } from "./event-type-color.input";
|
||||
import {
|
||||
AddressLocation_2024_06_14,
|
||||
AttendeeAddressLocation_2024_06_14,
|
||||
AttendeeDefinedLocation_2024_06_14,
|
||||
AttendeePhoneLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
InputAddressLocation_2024_06_14,
|
||||
InputAttendeeAddressLocation_2024_06_14,
|
||||
InputAttendeeDefinedLocation_2024_06_14,
|
||||
InputAttendeePhoneLocation_2024_06_14,
|
||||
InputIntegrationLocation_2024_06_14,
|
||||
InputLinkLocation_2024_06_14,
|
||||
InputPhoneLocation_2024_06_14,
|
||||
ValidateLocations_2024_06_14,
|
||||
} from "./locations.input";
|
||||
import type { Location_2024_06_14 } from "./locations.input";
|
||||
import type { InputLocation_2024_06_14 } from "./locations.input";
|
||||
import { Recurrence_2024_06_14 } from "./recurrence.input";
|
||||
import { Seats_2024_06_14 } from "./seats.input";
|
||||
|
||||
@@ -74,10 +74,10 @@ export const CREATE_EVENT_DESCRIPTION_EXAMPLE =
|
||||
export const CREATE_EVENT_SLUG_EXAMPLE = "learn-the-secrets-of-masterchief";
|
||||
|
||||
@ApiExtraModels(
|
||||
AddressLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
InputAddressLocation_2024_06_14,
|
||||
InputLinkLocation_2024_06_14,
|
||||
InputIntegrationLocation_2024_06_14,
|
||||
InputPhoneLocation_2024_06_14,
|
||||
PhoneFieldInput_2024_06_14,
|
||||
AddressFieldInput_2024_06_14,
|
||||
TextFieldInput_2024_06_14,
|
||||
@@ -98,9 +98,9 @@ export const CREATE_EVENT_SLUG_EXAMPLE = "learn-the-secrets-of-masterchief";
|
||||
Recurrence_2024_06_14,
|
||||
BaseConfirmationPolicy_2024_06_14,
|
||||
Seats_2024_06_14,
|
||||
AttendeeAddressLocation_2024_06_14,
|
||||
AttendeePhoneLocation_2024_06_14,
|
||||
AttendeeDefinedLocation_2024_06_14
|
||||
InputAttendeeAddressLocation_2024_06_14,
|
||||
InputAttendeePhoneLocation_2024_06_14,
|
||||
InputAttendeeDefinedLocation_2024_06_14
|
||||
)
|
||||
export class CreateEventTypeInput_2024_06_14 {
|
||||
@IsInt()
|
||||
@@ -127,18 +127,18 @@ export class CreateEventTypeInput_2024_06_14 {
|
||||
description:
|
||||
"Locations where the event will take place. If not provided, cal video link will be used as the location.",
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(AddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(LinkLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(IntegrationLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(PhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(AttendeeAddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(AttendeePhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(AttendeeDefinedLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputLinkLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputIntegrationLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputPhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAttendeeAddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAttendeePhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAttendeeDefinedLocation_2024_06_14) },
|
||||
],
|
||||
type: "array",
|
||||
})
|
||||
@Type(() => Object)
|
||||
locations?: Location_2024_06_14[];
|
||||
locations?: InputLocation_2024_06_14[];
|
||||
|
||||
@IsOptional()
|
||||
@ValidateInputBookingFields_2024_06_14()
|
||||
|
||||
+33
-33
@@ -5,7 +5,7 @@ import { IsString, IsUrl, IsIn, IsPhoneNumber, IsBoolean } from "class-validator
|
||||
import type { ValidationOptions, ValidatorConstraintInterface } from "class-validator";
|
||||
import { registerDecorator, validate, ValidatorConstraint } from "class-validator";
|
||||
|
||||
const locations = [
|
||||
export const inputLocations = [
|
||||
"address",
|
||||
"link",
|
||||
"integration",
|
||||
@@ -15,8 +15,8 @@ const locations = [
|
||||
"attendeeDefined",
|
||||
] as const;
|
||||
|
||||
export class AddressLocation_2024_06_14 {
|
||||
@IsIn(locations)
|
||||
export class InputAddressLocation_2024_06_14 {
|
||||
@IsIn(inputLocations)
|
||||
@DocsProperty({ example: "address", description: "only allowed value for type is `address`" })
|
||||
type!: "address";
|
||||
|
||||
@@ -29,8 +29,8 @@ export class AddressLocation_2024_06_14 {
|
||||
public!: boolean;
|
||||
}
|
||||
|
||||
export class LinkLocation_2024_06_14 {
|
||||
@IsIn(locations)
|
||||
export class InputLinkLocation_2024_06_14 {
|
||||
@IsIn(inputLocations)
|
||||
@DocsProperty({ example: "link", description: "only allowed value for type is `link`" })
|
||||
type!: "link";
|
||||
|
||||
@@ -46,8 +46,8 @@ export class LinkLocation_2024_06_14 {
|
||||
const integrations = ["cal-video"] as const;
|
||||
export type Integration_2024_06_14 = (typeof integrations)[number];
|
||||
|
||||
export class IntegrationLocation_2024_06_14 {
|
||||
@IsIn(locations)
|
||||
export class InputIntegrationLocation_2024_06_14 {
|
||||
@IsIn(inputLocations)
|
||||
@DocsProperty({ example: "integration", description: "only allowed value for type is `integration`" })
|
||||
type!: "integration";
|
||||
|
||||
@@ -56,8 +56,8 @@ export class IntegrationLocation_2024_06_14 {
|
||||
integration!: Integration_2024_06_14;
|
||||
}
|
||||
|
||||
export class PhoneLocation_2024_06_14 {
|
||||
@IsIn(locations)
|
||||
export class InputPhoneLocation_2024_06_14 {
|
||||
@IsIn(inputLocations)
|
||||
@DocsProperty({ example: "phone", description: "only allowed value for type is `phone`" })
|
||||
type!: "phone";
|
||||
|
||||
@@ -70,22 +70,22 @@ export class PhoneLocation_2024_06_14 {
|
||||
public!: boolean;
|
||||
}
|
||||
|
||||
export class AttendeeAddressLocation_2024_06_14 {
|
||||
@IsIn(locations)
|
||||
export class InputAttendeeAddressLocation_2024_06_14 {
|
||||
@IsIn(inputLocations)
|
||||
@DocsProperty({
|
||||
example: "attendeeAddress",
|
||||
description: "only allowed value for type is `attendeeAddress`",
|
||||
})
|
||||
type!: "attendeeAddress";
|
||||
}
|
||||
export class AttendeePhoneLocation_2024_06_14 {
|
||||
@IsIn(locations)
|
||||
export class InputAttendeePhoneLocation_2024_06_14 {
|
||||
@IsIn(inputLocations)
|
||||
@DocsProperty({ example: "attendeePhone", description: "only allowed value for type is `attendeePhone`" })
|
||||
type!: "attendeePhone";
|
||||
}
|
||||
|
||||
export class AttendeeDefinedLocation_2024_06_14 {
|
||||
@IsIn(locations)
|
||||
export class InputAttendeeDefinedLocation_2024_06_14 {
|
||||
@IsIn(inputLocations)
|
||||
@DocsProperty({
|
||||
example: "attendeeDefined",
|
||||
description: "only allowed value for type is `attendeeDefined`",
|
||||
@@ -93,25 +93,25 @@ export class AttendeeDefinedLocation_2024_06_14 {
|
||||
type!: "attendeeDefined";
|
||||
}
|
||||
|
||||
export type Location_2024_06_14 =
|
||||
| AddressLocation_2024_06_14
|
||||
| LinkLocation_2024_06_14
|
||||
| IntegrationLocation_2024_06_14
|
||||
| PhoneLocation_2024_06_14
|
||||
| AttendeeAddressLocation_2024_06_14
|
||||
| AttendeePhoneLocation_2024_06_14
|
||||
| AttendeeDefinedLocation_2024_06_14;
|
||||
export type InputLocation_2024_06_14 =
|
||||
| InputAddressLocation_2024_06_14
|
||||
| InputLinkLocation_2024_06_14
|
||||
| InputIntegrationLocation_2024_06_14
|
||||
| InputPhoneLocation_2024_06_14
|
||||
| InputAttendeeAddressLocation_2024_06_14
|
||||
| InputAttendeePhoneLocation_2024_06_14
|
||||
| InputAttendeeDefinedLocation_2024_06_14;
|
||||
|
||||
@ValidatorConstraint({ async: true })
|
||||
class LocationValidator_2024_06_14 implements ValidatorConstraintInterface {
|
||||
private classTypeMap: { [key: string]: new () => Location_2024_06_14 } = {
|
||||
address: AddressLocation_2024_06_14,
|
||||
link: LinkLocation_2024_06_14,
|
||||
integration: IntegrationLocation_2024_06_14,
|
||||
phone: PhoneLocation_2024_06_14,
|
||||
attendeePhone: AttendeePhoneLocation_2024_06_14,
|
||||
attendeeAddress: AttendeeAddressLocation_2024_06_14,
|
||||
attendeeDefined: AttendeeDefinedLocation_2024_06_14,
|
||||
class InputLocationValidator_2024_06_14 implements ValidatorConstraintInterface {
|
||||
private classTypeMap: { [key: string]: new () => InputLocation_2024_06_14 } = {
|
||||
address: InputAddressLocation_2024_06_14,
|
||||
link: InputLinkLocation_2024_06_14,
|
||||
integration: InputIntegrationLocation_2024_06_14,
|
||||
phone: InputPhoneLocation_2024_06_14,
|
||||
attendeePhone: InputAttendeePhoneLocation_2024_06_14,
|
||||
attendeeAddress: InputAttendeeAddressLocation_2024_06_14,
|
||||
attendeeDefined: InputAttendeeDefinedLocation_2024_06_14,
|
||||
};
|
||||
|
||||
async validate(locations: { type: string }[]) {
|
||||
@@ -160,7 +160,7 @@ export function ValidateLocations_2024_06_14(validationOptions?: ValidationOptio
|
||||
target: object.constructor,
|
||||
propertyName: propertyName,
|
||||
options: validationOptions,
|
||||
validator: new LocationValidator_2024_06_14(),
|
||||
validator: new InputLocationValidator_2024_06_14(),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
+23
-23
@@ -50,24 +50,24 @@ import { DestinationCalendar_2024_06_14 } from "./destination-calendar.input";
|
||||
import { Disabled_2024_06_14 } from "./disabled.input";
|
||||
import { EventTypeColor_2024_06_14 } from "./event-type-color.input";
|
||||
import {
|
||||
AddressLocation_2024_06_14,
|
||||
AttendeeAddressLocation_2024_06_14,
|
||||
AttendeeDefinedLocation_2024_06_14,
|
||||
AttendeePhoneLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
InputAddressLocation_2024_06_14,
|
||||
InputAttendeeAddressLocation_2024_06_14,
|
||||
InputAttendeeDefinedLocation_2024_06_14,
|
||||
InputAttendeePhoneLocation_2024_06_14,
|
||||
InputIntegrationLocation_2024_06_14,
|
||||
InputLinkLocation_2024_06_14,
|
||||
InputPhoneLocation_2024_06_14,
|
||||
ValidateLocations_2024_06_14,
|
||||
} from "./locations.input";
|
||||
import type { Location_2024_06_14 } from "./locations.input";
|
||||
import type { InputLocation_2024_06_14 } from "./locations.input";
|
||||
import { Recurrence_2024_06_14 } from "./recurrence.input";
|
||||
import { Seats_2024_06_14 } from "./seats.input";
|
||||
|
||||
@ApiExtraModels(
|
||||
AddressLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
InputAddressLocation_2024_06_14,
|
||||
InputLinkLocation_2024_06_14,
|
||||
InputIntegrationLocation_2024_06_14,
|
||||
InputPhoneLocation_2024_06_14,
|
||||
PhoneFieldInput_2024_06_14,
|
||||
AddressFieldInput_2024_06_14,
|
||||
TextFieldInput_2024_06_14,
|
||||
@@ -88,9 +88,9 @@ import { Seats_2024_06_14 } from "./seats.input";
|
||||
Recurrence_2024_06_14,
|
||||
BaseConfirmationPolicy_2024_06_14,
|
||||
Seats_2024_06_14,
|
||||
AttendeeAddressLocation_2024_06_14,
|
||||
AttendeePhoneLocation_2024_06_14,
|
||||
AttendeeDefinedLocation_2024_06_14
|
||||
InputAttendeeAddressLocation_2024_06_14,
|
||||
InputAttendeePhoneLocation_2024_06_14,
|
||||
InputAttendeeDefinedLocation_2024_06_14
|
||||
)
|
||||
export class UpdateEventTypeInput_2024_06_14 {
|
||||
@IsOptional()
|
||||
@@ -120,18 +120,18 @@ export class UpdateEventTypeInput_2024_06_14 {
|
||||
description:
|
||||
"Locations where the event will take place. If not provided, cal video link will be used as the location.",
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(AddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(LinkLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(IntegrationLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(PhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(AttendeeAddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(AttendeePhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(AttendeeDefinedLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputLinkLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputIntegrationLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputPhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAttendeeAddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAttendeePhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(InputAttendeeDefinedLocation_2024_06_14) },
|
||||
],
|
||||
type: "array",
|
||||
})
|
||||
@Type(() => Object)
|
||||
locations?: Location_2024_06_14[];
|
||||
locations?: InputLocation_2024_06_14[];
|
||||
|
||||
@IsOptional()
|
||||
@ValidateInputBookingFields_2024_06_14()
|
||||
|
||||
+25
-22
@@ -11,11 +11,7 @@ import {
|
||||
ValidateNested,
|
||||
} from "class-validator";
|
||||
|
||||
import type {
|
||||
Location_2024_06_14,
|
||||
BookingWindow_2024_06_14,
|
||||
BookingLimitsDuration_2024_06_14,
|
||||
} from "../inputs";
|
||||
import type { BookingWindow_2024_06_14, BookingLimitsDuration_2024_06_14 } from "../inputs";
|
||||
import {
|
||||
EventTypeColor_2024_06_14,
|
||||
Seats_2024_06_14,
|
||||
@@ -30,13 +26,6 @@ import { BookerLayouts_2024_06_14 } from "../inputs/booker-layouts.input";
|
||||
import type { BookingLimitsCount_2024_06_14 } from "../inputs/booking-limits-count.input";
|
||||
import type { ConfirmationPolicy_2024_06_14 } from "../inputs/confirmation-policy.input";
|
||||
import { DestinationCalendar_2024_06_14 } from "../inputs/destination-calendar.input";
|
||||
import {
|
||||
AddressLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
ValidateLocations_2024_06_14,
|
||||
} from "../inputs/locations.input";
|
||||
import {
|
||||
EmailDefaultFieldOutput_2024_06_14,
|
||||
NameDefaultFieldOutput_2024_06_14,
|
||||
@@ -59,6 +48,16 @@ import {
|
||||
} from "../outputs/booking-fields.output";
|
||||
import type { OutputBookingField_2024_06_14 } from "./booking-fields.output";
|
||||
import { ValidateOutputBookingFields_2024_06_14 } from "./booking-fields.output";
|
||||
import type { OutputLocation_2024_06_14 } from "./locations.output";
|
||||
import {
|
||||
OutputAddressLocation_2024_06_14,
|
||||
OutputConferencingLocation_2024_06_14,
|
||||
OutputIntegrationLocation_2024_06_14,
|
||||
OutputLinkLocation_2024_06_14,
|
||||
OutputPhoneLocation_2024_06_14,
|
||||
OutputUnknownLocation_2024_06_14,
|
||||
ValidateOutputLocations_2024_06_14,
|
||||
} from "./locations.output";
|
||||
|
||||
enum SchedulingTypeEnum {
|
||||
ROUND_ROBIN = "ROUND_ROBIN",
|
||||
@@ -95,10 +94,12 @@ class User_2024_06_14 {
|
||||
}
|
||||
|
||||
@ApiExtraModels(
|
||||
AddressLocation_2024_06_14,
|
||||
LinkLocation_2024_06_14,
|
||||
IntegrationLocation_2024_06_14,
|
||||
PhoneLocation_2024_06_14,
|
||||
OutputAddressLocation_2024_06_14,
|
||||
OutputLinkLocation_2024_06_14,
|
||||
OutputIntegrationLocation_2024_06_14,
|
||||
OutputPhoneLocation_2024_06_14,
|
||||
OutputConferencingLocation_2024_06_14,
|
||||
OutputUnknownLocation_2024_06_14,
|
||||
EmailDefaultFieldOutput_2024_06_14,
|
||||
NameDefaultFieldOutput_2024_06_14,
|
||||
LocationDefaultFieldOutput_2024_06_14,
|
||||
@@ -146,18 +147,20 @@ class BaseEventTypeOutput_2024_06_14 {
|
||||
})
|
||||
description!: string;
|
||||
|
||||
@ValidateLocations_2024_06_14()
|
||||
@ValidateOutputLocations_2024_06_14()
|
||||
@DocsProperty({
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(AddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(LinkLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(IntegrationLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(PhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(OutputAddressLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(OutputLinkLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(OutputIntegrationLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(OutputPhoneLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(OutputConferencingLocation_2024_06_14) },
|
||||
{ $ref: getSchemaPath(OutputUnknownLocation_2024_06_14) },
|
||||
],
|
||||
type: "array",
|
||||
})
|
||||
@Type(() => Object)
|
||||
locations!: Location_2024_06_14[];
|
||||
locations!: OutputLocation_2024_06_14[];
|
||||
|
||||
@ValidateOutputBookingFields_2024_06_14()
|
||||
@DocsProperty()
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./event-type.output";
|
||||
export * from "./booking-fields.output";
|
||||
export * from "./locations.output";
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
import { BadRequestException } from "@nestjs/common";
|
||||
import { ApiProperty as DocsProperty } from "@nestjs/swagger";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
import { IsUrl, IsIn, IsOptional, IsNumber, IsString } from "class-validator";
|
||||
import type { ValidationOptions, ValidatorConstraintInterface } from "class-validator";
|
||||
import { registerDecorator, validate, ValidatorConstraint } from "class-validator";
|
||||
|
||||
import {
|
||||
InputAddressLocation_2024_06_14,
|
||||
InputAttendeeAddressLocation_2024_06_14,
|
||||
InputAttendeeDefinedLocation_2024_06_14,
|
||||
InputAttendeePhoneLocation_2024_06_14,
|
||||
InputLinkLocation_2024_06_14,
|
||||
inputLocations,
|
||||
InputPhoneLocation_2024_06_14,
|
||||
} from "../inputs";
|
||||
|
||||
const outputLocations = [...inputLocations, "conferencing", "unknown"] as const;
|
||||
|
||||
export class OutputAddressLocation_2024_06_14 extends InputAddressLocation_2024_06_14 {}
|
||||
export class OutputLinkLocation_2024_06_14 extends InputLinkLocation_2024_06_14 {}
|
||||
export class OutputPhoneLocation_2024_06_14 extends InputPhoneLocation_2024_06_14 {}
|
||||
export class OutputAttendeeAddressLocation_2024_06_14 extends InputAttendeeAddressLocation_2024_06_14 {}
|
||||
export class OutputAttendeePhoneLocation_2024_06_14 extends InputAttendeePhoneLocation_2024_06_14 {}
|
||||
export class OutputAttendeeDefinedLocation_2024_06_14 extends InputAttendeeDefinedLocation_2024_06_14 {}
|
||||
|
||||
const integrationsValues = [
|
||||
"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",
|
||||
"campsite-conferencing",
|
||||
"campfire-video",
|
||||
"around-video",
|
||||
] as const;
|
||||
export type OutputIntegration_2024_06_14 = (typeof integrationsValues)[number];
|
||||
|
||||
export class OutputIntegrationLocation_2024_06_14 {
|
||||
@IsIn(outputLocations)
|
||||
@DocsProperty({ example: "integration", description: "only allowed value for type is `integration`" })
|
||||
type!: "integration";
|
||||
|
||||
@IsIn(integrationsValues)
|
||||
@DocsProperty({ example: integrationsValues[0], enum: integrationsValues })
|
||||
integration!: OutputIntegration_2024_06_14;
|
||||
|
||||
@IsUrl()
|
||||
@IsOptional()
|
||||
link?: string;
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
credentialId?: number;
|
||||
}
|
||||
|
||||
export class OutputConferencingLocation_2024_06_14 {
|
||||
@IsIn(outputLocations)
|
||||
@DocsProperty({ example: "conferencing", description: "only allowed value for type is `conferencing`" })
|
||||
type!: "conferencing";
|
||||
}
|
||||
|
||||
export class OutputUnknownLocation_2024_06_14 {
|
||||
@IsIn(outputLocations)
|
||||
@DocsProperty({ example: "unknown", description: "only allowed value for type is `unknown`" })
|
||||
type!: "unknown";
|
||||
|
||||
@IsString()
|
||||
location!: string;
|
||||
}
|
||||
|
||||
export type OutputLocation_2024_06_14 =
|
||||
| OutputAddressLocation_2024_06_14
|
||||
| OutputLinkLocation_2024_06_14
|
||||
| OutputIntegrationLocation_2024_06_14
|
||||
| OutputPhoneLocation_2024_06_14
|
||||
| OutputAttendeeAddressLocation_2024_06_14
|
||||
| OutputAttendeePhoneLocation_2024_06_14
|
||||
| OutputAttendeeDefinedLocation_2024_06_14
|
||||
| OutputConferencingLocation_2024_06_14
|
||||
| OutputUnknownLocation_2024_06_14;
|
||||
|
||||
@ValidatorConstraint({ async: true })
|
||||
class OutputLocationValidator_2024_06_14 implements ValidatorConstraintInterface {
|
||||
private classTypeMap: { [key: string]: new () => OutputLocation_2024_06_14 } = {
|
||||
address: OutputAddressLocation_2024_06_14,
|
||||
link: OutputLinkLocation_2024_06_14,
|
||||
integration: OutputIntegrationLocation_2024_06_14,
|
||||
phone: OutputPhoneLocation_2024_06_14,
|
||||
attendeePhone: OutputAttendeePhoneLocation_2024_06_14,
|
||||
attendeeAddress: OutputAttendeeAddressLocation_2024_06_14,
|
||||
attendeeDefined: OutputAttendeeDefinedLocation_2024_06_14,
|
||||
conferencing: OutputConferencingLocation_2024_06_14,
|
||||
unknown: OutputUnknownLocation_2024_06_14,
|
||||
};
|
||||
|
||||
async validate(locations: { type: string }[]) {
|
||||
if (!Array.isArray(locations)) {
|
||||
throw new BadRequestException(`'locations' must be an array.`);
|
||||
}
|
||||
|
||||
if (!locations.length) {
|
||||
throw new BadRequestException(`'locations' must contain at least 1 location.`);
|
||||
}
|
||||
|
||||
for (const location of locations) {
|
||||
const { type } = location;
|
||||
if (!type) {
|
||||
throw new BadRequestException(`Each object in 'locations' must have a 'type' property.`);
|
||||
}
|
||||
|
||||
const ClassType = this.classTypeMap[type];
|
||||
if (!ClassType) {
|
||||
throw new BadRequestException(`Unsupported output type '${type}'.`);
|
||||
}
|
||||
|
||||
const instance = plainToInstance(ClassType, location);
|
||||
const errors = await validate(instance);
|
||||
if (errors.length > 0) {
|
||||
const message = errors.flatMap((error) => Object.values(error.constraints || {})).join(", ");
|
||||
throw new BadRequestException(`Validation failed for ${type} location: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
defaultMessage() {
|
||||
return `Validation failed for one or more location entries.`;
|
||||
}
|
||||
}
|
||||
|
||||
export function ValidateOutputLocations_2024_06_14(validationOptions?: ValidationOptions) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return function (object: any, propertyName: string) {
|
||||
registerDecorator({
|
||||
name: "ValidateLocation",
|
||||
target: object.constructor,
|
||||
propertyName: propertyName,
|
||||
options: validationOptions,
|
||||
validator: new OutputLocationValidator_2024_06_14(),
|
||||
});
|
||||
};
|
||||
}
|
||||
+2
-2
@@ -7,7 +7,7 @@ import type {
|
||||
transformRecurrenceApiToInternal,
|
||||
transformSeatsApiToInternal,
|
||||
transformBookingFieldsApiToInternal,
|
||||
TransformedLocationsSchema,
|
||||
InternalLocationsSchema,
|
||||
} from "@calcom/lib/event-types/transformers";
|
||||
|
||||
import type { CreateEventTypeInput_2024_06_14, ConfirmationPolicyTransformedSchema } from "../inputs";
|
||||
@@ -32,7 +32,7 @@ export type InputEventTransformed_2024_06_14 = Omit<
|
||||
slug: string;
|
||||
eventName?: string;
|
||||
bookingLimits?: ReturnType<typeof transformIntervalLimitsApiToInternal>;
|
||||
locations?: z.infer<typeof TransformedLocationsSchema>;
|
||||
locations?: z.infer<typeof InternalLocationsSchema>;
|
||||
bookingFields?: ReturnType<typeof transformBookingFieldsApiToInternal>;
|
||||
durationLimits?: ReturnType<typeof transformIntervalLimitsApiToInternal>;
|
||||
recurringEvent?: ReturnType<typeof transformRecurrenceApiToInternal>;
|
||||
|
||||
@@ -4125,7 +4125,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@calcom/platform-constants": "*"
|
||||
"@calcom/platform-enums": "*"
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.51"
|
||||
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.52"
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2"
|
||||
"@calcom/platform-types": "*"
|
||||
"@calcom/platform-utils": "*"
|
||||
@@ -4559,6 +4559,15 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/dialpad@workspace:packages/app-store/dialpad":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/dialpad@workspace:packages/app-store/dialpad"
|
||||
dependencies:
|
||||
"@calcom/lib": "*"
|
||||
"@calcom/types": "*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/discord@workspace:packages/app-store/discord":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/discord@workspace:packages/app-store/discord"
|
||||
@@ -5132,14 +5141,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.51":
|
||||
version: 0.0.51
|
||||
resolution: "@calcom/platform-libraries@npm:0.0.51"
|
||||
"@calcom/platform-libraries@npm:@calcom/platform-libraries@0.0.52":
|
||||
version: 0.0.52
|
||||
resolution: "@calcom/platform-libraries@npm:0.0.52"
|
||||
dependencies:
|
||||
"@calcom/core": "*"
|
||||
"@calcom/features": "*"
|
||||
"@calcom/lib": "*"
|
||||
checksum: f7b97302730da01067e7417da94aa3e1a3e0e967698516edd15d72be1f2d57f40c382f5b70401aa3758a46f3a9a5a4f29e0fc4b7c8565a9cb4a4ff10ed4b5dc2
|
||||
checksum: 35d86bd7f99885f5960a1d1b4c45e1f8e8c0d945dcfded1a3be53b1e931cba04aaad252e433decb6f650b376fbb788e2f6bab2b88e5455b7a39065f84fdec1ff
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user