Skip to content

Commit

Permalink
feat: extend api/v2/event-types (calcom#16128)
Browse files Browse the repository at this point in the history
* feat: extended api/v2/event-types to add more attributes

- additional attributes added
* bookingLimits
* onlyShowFirstAvailableSlot
* durationLimits
* offsetStart
* bookingWindow

* add swagger docs

* type fix

* extend api/v2/teams/[teamId]/event-types

* added tests

* extend api/v2/orgs/[orgId]/teams/[teamid]/event-types

* update: added tests to get and update event-type as well

* rename variables

- bookingLimits -> bookingLimitsCount
- durationLimits -> bookingLimitsDuration

* refactor: rename bookingLimits and durationLimits, add descriptions

- Renamed `bookingLimits` to `bookingLimitsCount`
- Renamed `durationLimits` to `bookingLimitsDuration`
- Added descriptions with examples to `bookingLimitsCount` and `bookingLimitsDuration`

* feat: add unit tests for transformation logic in api-request and api-response

- Added tests for `transformApiEventTypeIntervalLimits`
- Added tests for `transformApiEventTypeFutureBookingLimits`

* fix: type errors

* feat: added custom validators for BookingLimitsCount and BookingLimitsDuration

* fix: unit-tests

* Update CHANGELOG.md

* refactor: update imports to use platform-libraries from @calcom/platform-libraries-1.2.3

* fix: prevent double transformation of bookingWindow and bookingFields

- resolving e2e test failures

---------

Co-authored-by: Morgan <[email protected]>
  • Loading branch information
SomayChauhan and ThyMinimalDev authored Aug 16, 2024
1 parent 894c0fc commit 8fbc76d
Show file tree
Hide file tree
Showing 28 changed files with 1,262 additions and 5,957 deletions.
2 changes: 1 addition & 1 deletion apps/api/v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"dependencies": {
"@calcom/platform-constants": "*",
"@calcom/platform-libraries": "npm:@calcom/[email protected].27",
"@calcom/platform-libraries": "npm:@calcom/[email protected].28",
"@calcom/platform-libraries-0.0.2": "npm:@calcom/[email protected]",
"@calcom/platform-types": "*",
"@calcom/platform-utils": "*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
EventTypeOutput_2024_06_14,
UpdateEventTypeInput_2024_06_14,
} from "@calcom/platform-types";
import { BookingWindowPeriodInputTypeEnum_2024_06_14 } from "@calcom/platform-types/dist/event-types/event-types_2024_06_14/inputs/enums/booking-window.enum";
import { SchedulingType } from "@calcom/prisma/enums";

describe("Event types Endpoints", () => {
Expand Down Expand Up @@ -214,6 +215,21 @@ describe("Event types Endpoints", () => {
},
],
scheduleId: firstSchedule.id,
bookingLimitsCount: {
day: 2,
week: 5,
},
onlyShowFirstAvailableSlot: true,
bookingLimitsDuration: {
day: 60,
week: 100,
},
offsetStart: 30,
bookingWindow: {
type: BookingWindowPeriodInputTypeEnum_2024_06_14.calendarDays,
value: 30,
rolling: true,
},
};

return request(app.getHttpServer())
Expand All @@ -232,7 +248,11 @@ describe("Event types Endpoints", () => {
expect(createdEventType.bookingFields).toEqual(body.bookingFields);
expect(createdEventType.ownerId).toEqual(user.id);
expect(createdEventType.scheduleId).toEqual(firstSchedule.id);

expect(createdEventType.bookingLimitsCount).toEqual(body.bookingLimitsCount);
expect(createdEventType.onlyShowFirstAvailableSlot).toEqual(body.onlyShowFirstAvailableSlot);
expect(createdEventType.bookingLimitsDuration).toEqual(body.bookingLimitsDuration);
expect(createdEventType.offsetStart).toEqual(body.offsetStart);
expect(createdEventType.bookingWindow).toEqual(body.bookingWindow);
eventType = responseBody.data;
});
});
Expand All @@ -243,6 +263,21 @@ describe("Event types Endpoints", () => {
const body: UpdateEventTypeInput_2024_06_14 = {
title: newTitle,
scheduleId: secondSchedule.id,
bookingLimitsCount: {
day: 4,
week: 10,
},
onlyShowFirstAvailableSlot: true,
bookingLimitsDuration: {
day: 100,
week: 200,
},
offsetStart: 50,
bookingWindow: {
type: BookingWindowPeriodInputTypeEnum_2024_06_14.businessDays,
value: 40,
rolling: false,
},
};

return request(app.getHttpServer())
Expand All @@ -263,9 +298,19 @@ describe("Event types Endpoints", () => {
expect(updatedEventType.bookingFields).toEqual(eventType.bookingFields);
expect(updatedEventType.ownerId).toEqual(user.id);
expect(updatedEventType.scheduleId).toEqual(secondSchedule.id);
expect(updatedEventType.bookingLimitsCount).toEqual(body.bookingLimitsCount);
expect(updatedEventType.onlyShowFirstAvailableSlot).toEqual(body.onlyShowFirstAvailableSlot);
expect(updatedEventType.bookingLimitsDuration).toEqual(body.bookingLimitsDuration);
expect(updatedEventType.offsetStart).toEqual(body.offsetStart);
expect(updatedEventType.bookingWindow).toEqual(body.bookingWindow);

eventType.title = newTitle;
eventType.scheduleId = secondSchedule.id;
eventType.bookingLimitsCount = updatedEventType.bookingLimitsCount;
eventType.onlyShowFirstAvailableSlot = updatedEventType.onlyShowFirstAvailableSlot;
eventType.bookingLimitsDuration = updatedEventType.bookingLimitsDuration;
eventType.offsetStart = updatedEventType.offsetStart;
eventType.bookingWindow = updatedEventType.bookingWindow;
});
});

Expand Down Expand Up @@ -301,6 +346,11 @@ describe("Event types Endpoints", () => {
expect(fetchedEventType.locations).toEqual(eventType.locations);
expect(fetchedEventType.bookingFields).toEqual(eventType.bookingFields);
expect(fetchedEventType.ownerId).toEqual(user.id);
expect(fetchedEventType.bookingLimitsCount).toEqual(eventType.bookingLimitsCount);
expect(fetchedEventType.onlyShowFirstAvailableSlot).toEqual(eventType.onlyShowFirstAvailableSlot);
expect(fetchedEventType.bookingLimitsDuration).toEqual(eventType.bookingLimitsDuration);
expect(fetchedEventType.offsetStart).toEqual(eventType.offsetStart);
expect(fetchedEventType.bookingWindow).toEqual(eventType.bookingWindow);
});

it(`/GET/even-types by username`, async () => {
Expand All @@ -326,6 +376,11 @@ describe("Event types Endpoints", () => {
expect(fetchedEventType?.locations).toEqual(eventType.locations);
expect(fetchedEventType?.bookingFields).toEqual(eventType.bookingFields);
expect(fetchedEventType?.ownerId).toEqual(user.id);
expect(fetchedEventType.bookingLimitsCount).toEqual(eventType.bookingLimitsCount);
expect(fetchedEventType.onlyShowFirstAvailableSlot).toEqual(eventType.onlyShowFirstAvailableSlot);
expect(fetchedEventType.bookingLimitsDuration).toEqual(eventType.bookingLimitsDuration);
expect(fetchedEventType.offsetStart).toEqual(eventType.offsetStart);
expect(fetchedEventType.bookingWindow).toEqual(eventType.bookingWindow);
});

it(`/GET/event-types by username and eventSlug`, async () => {
Expand All @@ -346,6 +401,11 @@ describe("Event types Endpoints", () => {
expect(fetchedEventType?.locations).toEqual(eventType.locations);
expect(fetchedEventType?.bookingFields).toEqual(eventType.bookingFields);
expect(fetchedEventType?.ownerId).toEqual(user.id);
expect(fetchedEventType.bookingLimitsCount).toEqual(eventType.bookingLimitsCount);
expect(fetchedEventType.onlyShowFirstAvailableSlot).toEqual(eventType.onlyShowFirstAvailableSlot);
expect(fetchedEventType.bookingLimitsDuration).toEqual(eventType.bookingLimitsDuration);
expect(fetchedEventType.offsetStart).toEqual(eventType.offsetStart);
expect(fetchedEventType.bookingWindow).toEqual(eventType.bookingWindow);
});

it(`/GET/:id not existing`, async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@ import type { PrismaClient } from "@calcom/prisma";

type InputEventTransformed = Omit<
CreateEventTypeInput_2024_06_14,
"lengthInMinutes" | "locations" | "bookingFields"
| "lengthInMinutes"
| "locations"
| "bookingFields"
| "bookingLimitsCount"
| "onlyShowFirstAvailableSlot"
| "bookingLimitsDuration"
| "offsetStart"
| "periodType"
| "periodDays"
| "periodCountCalendarDays"
| "periodStartDate"
| "periodEndDate"
> & {
length: number;
slug: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@ export class EventTypesService_2024_06_14 {
async createUserEventType(user: UserWithProfile, body: CreateEventTypeInput_2024_06_14) {
await this.checkCanCreateEventType(user.id, body);
const eventTypeUser = await this.getUserToCreateEvent(user);
const bodyTransformed = this.inputEventTypesService.transformInputCreateEventType(body);
const {
bookingLimits,
durationLimits,
periodType = undefined,
periodDays = undefined,
periodCountCalendarDays = undefined,
periodStartDate = undefined,
periodEndDate = undefined,
...bodyTransformed
} = this.inputEventTypesService.transformInputCreateEventType(body);
const { eventType: eventTypeCreated } = await createEventType({
input: bodyTransformed,
ctx: {
Expand All @@ -49,6 +58,26 @@ export class EventTypesService_2024_06_14 {
},
});

await updateEventType({
input: {
id: eventTypeCreated.id,
bookingLimits,
durationLimits,
periodType,
periodDays,
periodCountCalendarDays,
periodStartDate,
periodEndDate,
...bodyTransformed,
},
ctx: {
user: eventTypeUser,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
prisma: this.dbWrite.prisma,
},
});

const eventType = await this.eventTypesRepository.getEventTypeById(eventTypeCreated.id);

if (!eventType) {
Expand Down Expand Up @@ -95,13 +124,16 @@ export class EventTypesService_2024_06_14 {
? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId)
: false;
const profileId = user.movedToProfile?.id || null;
const selectedCalendars = await this.selectedCalendarsRepository.getUserSelectedCalendars(user.id);
return {
id: user.id,
role: user.role,
username: user.username,
organizationId: user.organizationId,
organization: { isOrgAdmin },
profile: { id: profileId },
metadata: user.metadata,
selectedCalendars,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Injectable } from "@nestjs/common";
import {
transformApiEventTypeBookingFields,
transformApiEventTypeLocations,
transformApiEventTypeIntervalLimits,
transformApiEventTypeFutureBookingLimits,
} from "@calcom/platform-libraries";
import { CreateEventTypeInput_2024_06_14, UpdateEventTypeInput_2024_06_14 } from "@calcom/platform-types";

Expand All @@ -16,27 +18,54 @@ export class InputEventTypesService_2024_06_14 {
},
];

const { lengthInMinutes, locations, bookingFields, ...rest } = inputEventType;
const {
lengthInMinutes,
locations,
bookingFields,
bookingLimitsCount,
bookingLimitsDuration,
bookingWindow,
...rest
} = inputEventType;

const eventType = {
...rest,
length: lengthInMinutes,
locations: this.transformInputLocations(locations || defaultLocations),
bookingFields: this.transformInputBookingFields(bookingFields),
bookingLimits: bookingLimitsCount ? this.transformInputIntervalLimits(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
? this.transformInputIntervalLimits(bookingLimitsDuration)
: undefined,
...this.transformInputBookingWindow(bookingWindow),
};

return eventType;
}

transformInputUpdateEventType(inputEventType: UpdateEventTypeInput_2024_06_14) {
const { lengthInMinutes, locations, bookingFields, scheduleId, ...rest } = inputEventType;
const {
lengthInMinutes,
locations,
bookingFields,
scheduleId,
bookingLimitsCount,
bookingLimitsDuration,
bookingWindow,
...rest
} = inputEventType;

const eventType = {
...rest,
length: lengthInMinutes,
locations: locations ? this.transformInputLocations(locations) : undefined,
bookingFields: bookingFields ? this.transformInputBookingFields(bookingFields) : undefined,
schedule: scheduleId,
bookingLimits: bookingLimitsCount ? this.transformInputIntervalLimits(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
? this.transformInputIntervalLimits(bookingLimitsDuration)
: undefined,
...this.transformInputBookingWindow(bookingWindow),
};

return eventType;
Expand All @@ -49,4 +78,13 @@ export class InputEventTypesService_2024_06_14 {
transformInputBookingFields(inputBookingFields: CreateEventTypeInput_2024_06_14["bookingFields"]) {
return transformApiEventTypeBookingFields(inputBookingFields);
}

transformInputIntervalLimits(inputBookingFields: CreateEventTypeInput_2024_06_14["bookingLimitsCount"]) {
return transformApiEventTypeIntervalLimits(inputBookingFields);
}

transformInputBookingWindow(inputBookingWindow: CreateEventTypeInput_2024_06_14["bookingWindow"]) {
const res = transformApiEventTypeFutureBookingLimits(inputBookingWindow);
return !!res ? res : {};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import {
BookingFieldsSchema,
SystemField,
UserField,
parseBookingLimit,
getResponseEventTypeIntervalLimits,
getResponseEventTypeFutureBookingLimits,
} from "@calcom/platform-libraries";
import { TransformFutureBookingsLimitSchema_2024_06_14 } from "@calcom/platform-types";

type EventTypeRelations = { users: User[]; schedule: Schedule | null };
type DatabaseEventType = EventType & EventTypeRelations;
Expand Down Expand Up @@ -44,6 +48,15 @@ type Input = Pick<
| "metadata"
| "users"
| "scheduleId"
| "bookingLimits"
| "durationLimits"
| "onlyShowFirstAvailableSlot"
| "offsetStart"
| "periodType"
| "periodDays"
| "periodCountCalendarDays"
| "periodStartDate"
| "periodEndDate"
>;

@Injectable()
Expand Down Expand Up @@ -71,6 +84,8 @@ export class OutputEventTypesService_2024_06_14 {
seatsShowAvailabilityCount,
isInstantEvent,
scheduleId,
onlyShowFirstAvailableSlot,
offsetStart,
} = databaseEventType;

const locations = this.transformLocations(databaseEventType.locations);
Expand All @@ -80,6 +95,15 @@ export class OutputEventTypesService_2024_06_14 {
const recurringEvent = this.transformRecurringEvent(databaseEventType.recurringEvent);
const metadata = this.transformMetadata(databaseEventType.metadata) || {};
const users = this.transformUsers(databaseEventType.users);
const bookingLimitsCount = this.transformIntervalLimits(databaseEventType.bookingLimits);
const bookingLimitsDuration = this.transformIntervalLimits(databaseEventType.durationLimits);
const bookingWindow = this.transformBookingWindow({
periodType: databaseEventType.periodType,
periodDays: databaseEventType.periodDays,
periodCountCalendarDays: databaseEventType.periodCountCalendarDays,
periodStartDate: databaseEventType.periodStartDate,
periodEndDate: databaseEventType.periodEndDate,
} as TransformFutureBookingsLimitSchema_2024_06_14);

return {
id,
Expand Down Expand Up @@ -109,6 +133,11 @@ export class OutputEventTypesService_2024_06_14 {
isInstantEvent,
users,
scheduleId,
bookingLimitsCount,
bookingLimitsDuration,
onlyShowFirstAvailableSlot,
offsetStart,
bookingWindow,
};
}

Expand Down Expand Up @@ -148,4 +177,13 @@ export class OutputEventTypesService_2024_06_14 {
};
});
}

transformIntervalLimits(bookingLimits: any) {
const bookingLimitsParsed = parseBookingLimit(bookingLimits);
return getResponseEventTypeIntervalLimits(bookingLimitsParsed);
}

transformBookingWindow(bookingLimits: TransformFutureBookingsLimitSchema_2024_06_14) {
return getResponseEventTypeFutureBookingLimits(bookingLimits);
}
}
Loading

0 comments on commit 8fbc76d

Please sign in to comment.