feat: v2 API enable updating event type schedule (#15803)

* refactor: event-types CREATE, UPDATE accept scheduleId and return scheduleId

* chore: enable passing scheduleId to event-types create handler

* chore: use platform-libraries at version 0.0.20

* fix: remove team output schedule

* finish merge main into this branch

* fix: dont allow adding scheduleId to event-type if user does not own schedule
This commit is contained in:
Lauris Skraucis authored and GitHub committed 2024-07-22 20:09:54 +03:00
1 parent 35110892c1
commit de2f51e104
38 files changed
+199 -89

No files matched your search

+1 -1
View File
@@ -25,8 +25,8 @@
},
"dependencies": {
"@calcom/platform-constants": "*",
"@calcom/platform-libraries-0.0.19": "npm:@calcom/platform-libraries@0.0.19",
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
"@calcom/platform-libraries-0.0.20": "npm:@calcom/platform-libraries@0.0.20",
"@calcom/platform-types": "*",
"@calcom/platform-utils": "*",
"@calcom/prisma": "*",
@@ -19,7 +19,7 @@ import { UserRepositoryFixture } from "test/fixtures/repository/users.repository
import { withApiAuth } from "test/utils/withApiAuth";
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
import { handleNewBooking } from "@calcom/platform-libraries-0.0.19";
import { handleNewBooking } from "@calcom/platform-libraries-0.0.20";
import { ApiSuccessResponse, ApiResponse } from "@calcom/platform-types";
describe("Bookings Endpoints", () => {
@@ -46,7 +46,7 @@ import {
getBookingInfo,
handleCancelBooking,
getBookingForReschedule,
} from "@calcom/platform-libraries-0.0.19";
} from "@calcom/platform-libraries-0.0.20";
import { GetBookingsInput, CancelBookingInput, Status } from "@calcom/platform-types";
import { ApiResponse } from "@calcom/platform-types";
import { PrismaClient } from "@calcom/prisma";
@@ -1,7 +1,7 @@
import { CreateBookingInput } from "@/ee/bookings/inputs/create-booking.input";
import { IsBoolean, IsNumber, IsOptional } from "class-validator";
import type { AppsStatus } from "@calcom/platform-libraries-0.0.19";
import type { AppsStatus } from "@calcom/platform-libraries-0.0.20";
export class CreateRecurringBookingInput extends CreateBookingInput {
@IsBoolean()
@@ -5,7 +5,7 @@ import { BadRequestException, UnauthorizedException } from "@nestjs/common";
import { Injectable } from "@nestjs/common";
import { SUCCESS_STATUS, APPLE_CALENDAR_TYPE, APPLE_CALENDAR_ID } from "@calcom/platform-constants";
import { symmetricEncrypt, CalendarService } from "@calcom/platform-libraries-0.0.19";
import { symmetricEncrypt, CalendarService } from "@calcom/platform-libraries-0.0.20";
@Injectable()
export class AppleCalendarService implements CredentialSyncCalendarApp {
@@ -17,7 +17,7 @@ import { User } from "@prisma/client";
import { DateTime } from "luxon";
import { z } from "zod";
import { getConnectedDestinationCalendars, getBusyCalendarTimes } from "@calcom/platform-libraries-0.0.19";
import { getConnectedDestinationCalendars, getBusyCalendarTimes } from "@calcom/platform-libraries-0.0.20";
import { Calendar } from "@calcom/platform-types";
import { PrismaClient } from "@calcom/prisma";
@@ -35,7 +35,7 @@ import {
EventTypesPublic,
eventTypeBookingFields,
eventTypeLocations,
} from "@calcom/platform-libraries-0.0.19";
} from "@calcom/platform-libraries-0.0.20";
import { ApiSuccessResponse } from "@calcom/platform-types";
describe("Event types Endpoints", () => {
@@ -40,6 +40,7 @@ import { ApiTags as DocsTags } from "@nestjs/swagger";
import { EVENT_TYPE_READ, EVENT_TYPE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
import { getPublicEvent, getEventTypesByViewer } from "@calcom/platform-libraries-0.0.2";
import { PrismaClient } from "@calcom/prisma";
@Controller({
@@ -4,7 +4,7 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { UserWithProfile } from "@/modules/users/users.repository";
import { Injectable } from "@nestjs/common";
import { getEventTypeById } from "@calcom/platform-libraries-0.0.19";
import { getEventTypeById } from "@calcom/platform-libraries-0.0.20";
import type { PrismaClient } from "@calcom/prisma";
@Injectable()
@@ -14,7 +14,7 @@ import {
updateEventType,
EventTypesPublic,
getEventTypesPublic,
} from "@calcom/platform-libraries-0.0.19";
} from "@calcom/platform-libraries-0.0.20";
import { EventType } from "@calcom/prisma/client";
@Injectable()
@@ -9,10 +9,11 @@ import { UsersModule } from "@/modules/users/users.module";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
import { Test } from "@nestjs/testing";
import { PlatformOAuthClient, Team, User } from "@prisma/client";
import { PlatformOAuthClient, Team, User, Schedule } from "@prisma/client";
import * as request from "supertest";
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
import { SchedulesRepositoryFixture } from "test/fixtures/repository/schedules.repository.fixture";
import { TeamRepositoryFixture } from "test/fixtures/repository/team.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { withApiAuth } from "test/utils/withApiAuth";
@@ -63,12 +64,18 @@ describe("Event types Endpoints", () => {
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
let teamRepositoryFixture: TeamRepositoryFixture;
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
let schedulesRepostoryFixture: SchedulesRepositoryFixture;
const userEmail = "event-types-test-e2e@api.com";
const falseTestEmail = "false-event-types@api.com";
const name = "bob-the-builder";
const username = name;
let eventType: EventTypeOutput_2024_06_14;
let user: User;
let falseTestUser: User;
let firstSchedule: Schedule;
let secondSchedule: Schedule;
let falseTestSchedule: Schedule;
beforeAll(async () => {
const moduleRef = await withApiAuth(
@@ -91,6 +98,7 @@ describe("Event types Endpoints", () => {
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
teamRepositoryFixture = new TeamRepositoryFixture(moduleRef);
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
schedulesRepostoryFixture = new SchedulesRepositoryFixture(moduleRef);
organization = await teamRepositoryFixture.create({ name: "organization" });
oAuthClient = await createOAuthClient(organization.id);
@@ -100,6 +108,30 @@ describe("Event types Endpoints", () => {
username,
});
falseTestUser = await userRepositoryFixture.create({
email: falseTestEmail,
name: "false-test",
username: falseTestEmail,
});
firstSchedule = await schedulesRepostoryFixture.create({
userId: user.id,
name: "work",
timeZone: "Europe/Rome",
});
secondSchedule = await schedulesRepostoryFixture.create({
userId: user.id,
name: "chill",
timeZone: "Europe/Rome",
});
falseTestSchedule = await schedulesRepostoryFixture.create({
userId: falseTestUser.id,
name: "work",
timeZone: "Europe/Rome",
});
await app.init();
});
@@ -123,6 +155,40 @@ describe("Event types Endpoints", () => {
expect(user).toBeDefined();
});
it("should not allow creating an event type with schedule user does not own", async () => {
const scheduleId = falseTestSchedule.id;
const body: CreateEventTypeInput_2024_06_14 = {
title: "Coding class",
slug: "coding-class",
description: "Let's learn how to code like a pro.",
lengthInMinutes: 60,
locations: [
{
type: "integration",
integration: "cal-video",
},
],
bookingFields: [
{
type: "select",
label: "select which language you want to learn",
slug: "select-language",
required: true,
placeholder: "select language",
options: ["javascript", "python", "cobol"],
},
],
scheduleId,
};
return request(app.getHttpServer())
.post("/api/v2/event-types")
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
.send(body)
.expect(404);
});
it("should create an event type", async () => {
const body: CreateEventTypeInput_2024_06_14 = {
title: "Coding class",
@@ -145,6 +211,7 @@ describe("Event types Endpoints", () => {
options: ["javascript", "python", "cobol"],
},
],
scheduleId: firstSchedule.id,
};
return request(app.getHttpServer())
@@ -162,6 +229,7 @@ describe("Event types Endpoints", () => {
expect(createdEventType.locations).toEqual(body.locations);
expect(createdEventType.bookingFields).toEqual(body.bookingFields);
expect(createdEventType.ownerId).toEqual(user.id);
expect(createdEventType.scheduleId).toEqual(firstSchedule.id);
eventType = responseBody.data;
});
@@ -172,6 +240,7 @@ describe("Event types Endpoints", () => {
const body: UpdateEventTypeInput_2024_06_14 = {
title: newTitle,
scheduleId: secondSchedule.id,
};
return request(app.getHttpServer())
@@ -191,11 +260,25 @@ describe("Event types Endpoints", () => {
expect(updatedEventType.locations).toEqual(eventType.locations);
expect(updatedEventType.bookingFields).toEqual(eventType.bookingFields);
expect(updatedEventType.ownerId).toEqual(user.id);
expect(updatedEventType.scheduleId).toEqual(secondSchedule.id);
eventType.title = newTitle;
eventType.scheduleId = secondSchedule.id;
});
});
it("should not allow to update event type with scheduleId user does not own", async () => {
const body: UpdateEventTypeInput_2024_06_14 = {
scheduleId: falseTestSchedule.id,
};
return request(app.getHttpServer())
.patch(`/api/v2/event-types/${eventType.id}`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_14)
.send(body)
.expect(404);
});
it(`/GET/:id`, async () => {
const response = await request(app.getHttpServer())
.get(`/api/v2/event-types/${eventType.id}`)
@@ -272,7 +355,7 @@ describe("Event types Endpoints", () => {
.expect(404);
});
it("should delete schedule", async () => {
it("should delete event type", async () => {
return request(app.getHttpServer()).delete(`/api/v2/event-types/${eventType.id}`).expect(200);
});
@@ -289,6 +372,11 @@ describe("Event types Endpoints", () => {
} catch (e) {
// User might have been deleted by the test
}
try {
await userRepositoryFixture.delete(falseTestUser.id);
} catch (e) {
// User might have been deleted by the test
}
await app.close();
});
});
@@ -3,6 +3,7 @@ import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_20
import { EventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/event-types.service";
import { InputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/input-event-types.service";
import { OutputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/output-event-types.service";
import { SchedulesRepository_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.repository";
import { MembershipsModule } from "@/modules/memberships/memberships.module";
import { PrismaModule } from "@/modules/prisma/prisma.module";
import { SelectedCalendarsModule } from "@/modules/selected-calendars/selected-calendars.module";
@@ -20,6 +21,7 @@ import { Module } from "@nestjs/common";
OutputEventTypesService_2024_06_14,
UsersRepository,
UsersService,
SchedulesRepository_2024_06_11,
],
controllers: [EventTypesController_2024_06_14],
exports: [
@@ -7,7 +7,7 @@ import {
getEventTypeById,
transformApiEventTypeBookingFields,
transformApiEventTypeLocations,
} from "@calcom/platform-libraries-0.0.19";
} from "@calcom/platform-libraries-0.0.20";
import { CreateEventTypeInput_2024_06_14 } from "@calcom/platform-types";
import type { PrismaClient } from "@calcom/prisma";
@@ -2,6 +2,7 @@ import { DEFAULT_EVENT_TYPES } from "@/ee/event-types/event-types_2024_06_14/con
import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.repository";
import { InputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/input-event-types.service";
import { OutputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/output-event-types.service";
import { SchedulesRepository_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.repository";
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository";
@@ -9,9 +10,9 @@ import { UsersService } from "@/modules/users/services/users.service";
import { UserWithProfile, UsersRepository } from "@/modules/users/users.repository";
import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.19";
import { getEventTypesPublic, EventTypesPublic } from "@calcom/platform-libraries-0.0.19";
import { dynamicEvent } from "@calcom/platform-libraries-0.0.19";
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.20";
import { getEventTypesPublic, EventTypesPublic } from "@calcom/platform-libraries-0.0.20";
import { dynamicEvent } from "@calcom/platform-libraries-0.0.20";
import {
CreateEventTypeInput_2024_06_14,
UpdateEventTypeInput_2024_06_14,
@@ -30,7 +31,8 @@ export class EventTypesService_2024_06_14 {
private readonly usersRepository: UsersRepository,
private readonly usersService: UsersService,
private readonly selectedCalendarsRepository: SelectedCalendarsRepository,
private readonly dbWrite: PrismaWriteService
private readonly dbWrite: PrismaWriteService,
private readonly schedulesRepository: SchedulesRepository_2024_06_11
) {}
async createUserEventType(user: UserWithProfile, body: CreateEventTypeInput_2024_06_14) {
@@ -61,6 +63,7 @@ export class EventTypesService_2024_06_14 {
if (existsWithSlug) {
throw new BadRequestException("User already has an event type with this slug.");
}
await this.checkUserOwnsSchedule(userId, body.scheduleId);
}
async getEventTypeByUsernameAndSlug(username: string, eventTypeSlug: string) {
@@ -203,7 +206,7 @@ export class EventTypesService_2024_06_14 {
}
async updateEventType(eventTypeId: number, body: UpdateEventTypeInput_2024_06_14, user: UserWithProfile) {
this.checkCanUpdateEventType(user.id, eventTypeId);
await this.checkCanUpdateEventType(user.id, eventTypeId, body.scheduleId);
const eventTypeUser = await this.getUserToUpdateEvent(user);
const bodyTransformed = this.inputEventTypesService.transformInputUpdateEventType(body);
await updateEventType({
@@ -225,12 +228,13 @@ export class EventTypesService_2024_06_14 {
return this.outputEventTypesService.getResponseEventType(user.id, eventType);
}
async checkCanUpdateEventType(userId: number, eventTypeId: number) {
async checkCanUpdateEventType(userId: number, eventTypeId: number, scheduleId: number | undefined) {
const existingEventType = await this.getUserEventType(userId, eventTypeId);
if (!existingEventType) {
throw new NotFoundException(`Event type with id ${eventTypeId} not found`);
}
this.checkUserOwnsEventType(userId, { id: eventTypeId, userId: existingEventType.ownerId });
await this.checkUserOwnsSchedule(userId, scheduleId);
}
async getUserToUpdateEvent(user: UserWithProfile) {
@@ -255,4 +259,16 @@ export class EventTypesService_2024_06_14 {
throw new ForbiddenException(`User with ID=${userId} does not own event type with ID=${eventType.id}`);
}
}
async checkUserOwnsSchedule(userId: number, scheduleId: number | null | undefined) {
if (!scheduleId) {
return;
}
const schedule = await this.schedulesRepository.getScheduleByIdAndUserId(scheduleId, userId);
if (!schedule) {
throw new NotFoundException(`User with ID=${userId} does not own schedule with ID=${scheduleId}`);
}
}
}
@@ -3,7 +3,7 @@ import { Injectable } from "@nestjs/common";
import {
transformApiEventTypeBookingFields,
transformApiEventTypeLocations,
} from "@calcom/platform-libraries-0.0.19";
} from "@calcom/platform-libraries-0.0.20";
import { CreateEventTypeInput_2024_06_14, UpdateEventTypeInput_2024_06_14 } from "@calcom/platform-types";
@Injectable()
@@ -29,13 +29,14 @@ export class InputEventTypesService_2024_06_14 {
}
transformInputUpdateEventType(inputEventType: UpdateEventTypeInput_2024_06_14) {
const { lengthInMinutes, locations, bookingFields, ...rest } = inputEventType;
const { lengthInMinutes, locations, bookingFields, scheduleId, ...rest } = inputEventType;
const eventType = {
...rest,
length: lengthInMinutes,
locations: locations ? this.transformInputLocations(locations) : undefined,
bookingFields: bookingFields ? this.transformInputBookingFields(bookingFields) : undefined,
schedule: scheduleId,
};
return eventType;
@@ -9,7 +9,7 @@ import {
parseRecurringEvent,
TransformedLocationsSchema,
BookingFieldsSchema,
} from "@calcom/platform-libraries-0.0.19";
} from "@calcom/platform-libraries-0.0.20";
type EventTypeRelations = { users: User[]; schedule: Schedule | null };
type DatabaseEventType = EventType & EventTypeRelations;
@@ -41,7 +41,7 @@ type Input = Pick<
| "recurringEvent"
| "metadata"
| "users"
| "schedule"
| "scheduleId"
>;
@Injectable()
@@ -68,13 +68,13 @@ export class OutputEventTypesService_2024_06_14 {
successRedirectUrl,
seatsShowAvailabilityCount,
isInstantEvent,
scheduleId,
} = databaseEventType;
const locations = this.transformLocations(databaseEventType.locations);
const bookingFields = this.transformBookingFields(databaseEventType.bookingFields);
const recurringEvent = this.transformRecurringEvent(databaseEventType.recurringEvent);
const metadata = this.transformMetadata(databaseEventType.metadata) || {};
const schedule = await this.getSchedule(databaseEventType);
const users = this.transformUsers(databaseEventType.users);
return {
@@ -104,7 +104,7 @@ export class OutputEventTypesService_2024_06_14 {
seatsShowAvailabilityCount,
isInstantEvent,
users,
schedule,
scheduleId,
};
}
@@ -128,10 +128,6 @@ export class OutputEventTypesService_2024_06_14 {
return EventTypeMetaDataSchema.parse(metadata);
}
async getSchedule(databaseEventType: Input) {
return databaseEventType.schedule || null;
}
transformUsers(users: User[]) {
return users.map((user) => {
const metadata = user.metadata ? userMetadata.parse(user.metadata) : {};
@@ -96,6 +96,17 @@ export class SchedulesRepository_2024_06_11 {
return schedule;
}
async getScheduleByIdAndUserId(scheduleId: number, userId: number) {
const schedule = await this.dbRead.prisma.schedule.findUnique({
where: {
id: scheduleId,
userId,
},
});
return schedule;
}
async updateSchedule(
userId: number,
scheduleId: number,
@@ -3,7 +3,7 @@ import { Injectable } from "@nestjs/common";
import {
transformApiScheduleOverrides,
transformApiScheduleAvailability,
} from "@calcom/platform-libraries-0.0.19";
} from "@calcom/platform-libraries-0.0.20";
import { CreateScheduleInput_2024_06_11, ScheduleAvailabilityInput_2024_06_11 } from "@calcom/platform-types";
import { ScheduleOverrideInput_2024_06_11 } from "@calcom/platform-types";
@@ -2,7 +2,7 @@ import { ArgumentsHost, Catch, ExceptionFilter, Logger } from "@nestjs/common";
import { Request } from "express";
import { ERROR_STATUS } from "@calcom/platform-constants";
import { TRPCError } from "@calcom/platform-libraries-0.0.19";
import { TRPCError } from "@calcom/platform-libraries-0.0.20";
import { Response } from "@calcom/platform-types";
@Catch(TRPCError)
@@ -1,6 +1,6 @@
import { Injectable } from "@nestjs/common";
import { sendSignupToOrganizationEmail, getTranslation } from "@calcom/platform-libraries-0.0.19";
import { sendSignupToOrganizationEmail, getTranslation } from "@calcom/platform-libraries-0.0.20";
@Injectable()
export class EmailService {
@@ -7,7 +7,7 @@ import { UsersRepository } from "@/modules/users/users.repository";
import { BadRequestException, Injectable } from "@nestjs/common";
import { User } from "@prisma/client";
import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries-0.0.19";
import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries-0.0.20";
@Injectable()
export class OAuthClientUsersService {
@@ -587,6 +587,7 @@ describe("Organizations Event Types Endpoints", () => {
await userRepositoryFixture.deleteByEmail(userAdmin.email);
await userRepositoryFixture.deleteByEmail(teammate1.email);
await userRepositoryFixture.deleteByEmail(teammate2.email);
await userRepositoryFixture.deleteByEmail(falseTestUser.email);
await teamsRepositoryFixture.delete(team.id);
await organizationsRepositoryFixture.delete(org.id);
await app.close();
@@ -9,7 +9,7 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { UserWithProfile } from "@/modules/users/users.repository";
import { Injectable, NotFoundException } from "@nestjs/common";
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.19";
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.20";
import {
CreateTeamEventTypeInput_2024_06_14,
UpdateTeamEventTypeInput_2024_06_14,
@@ -35,7 +35,7 @@ type Input = Pick<
| "recurringEvent"
| "metadata"
| "users"
| "schedule"
| "scheduleId"
| "hosts"
| "teamId"
| "userId"
@@ -6,7 +6,7 @@ import { CreateUserInput } from "@/modules/users/inputs/create-user.input";
import { Injectable, ConflictException } from "@nestjs/common";
import { plainToInstance } from "class-transformer";
import { createNewUsersConnectToOrgIfExists } from "@calcom/platform-libraries-0.0.19";
import { createNewUsersConnectToOrgIfExists } from "@calcom/platform-libraries-0.0.20";
import { Team } from "@calcom/prisma/client";
@Injectable()
@@ -5,8 +5,8 @@ import { ApiTags as DocsTags } from "@nestjs/swagger";
import { Response as ExpressResponse, Request as ExpressRequest } from "express";
import { SUCCESS_STATUS } from "@calcom/platform-constants";
import { getAvailableSlots } from "@calcom/platform-libraries-0.0.19";
import type { AvailableSlotsType } from "@calcom/platform-libraries-0.0.19";
import { getAvailableSlots } from "@calcom/platform-libraries-0.0.20";
import type { AvailableSlotsType } from "@calcom/platform-libraries-0.0.20";
import { RemoveSelectedSlotInput, ReserveSlotInput } from "@calcom/platform-types";
import { ApiResponse, GetAvailableSlotsInput } from "@calcom/platform-types";
@@ -3,7 +3,7 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { Injectable } from "@nestjs/common";
import { DateTime } from "luxon";
import { MINUTES_TO_BOOK } from "@calcom/platform-libraries-0.0.19";
import { MINUTES_TO_BOOK } from "@calcom/platform-libraries-0.0.20";
import { ReserveSlotInput } from "@calcom/platform-types";
@Injectable()
@@ -4,7 +4,7 @@ import { Controller, Get } from "@nestjs/common";
import { ApiTags as DocsTags } from "@nestjs/swagger";
import { SUCCESS_STATUS } from "@calcom/platform-constants";
import type { CityTimezones } from "@calcom/platform-libraries-0.0.19";
import type { CityTimezones } from "@calcom/platform-libraries-0.0.20";
import { ApiResponse } from "@calcom/platform-types";
@Controller({
@@ -1,8 +1,8 @@
import { RedisService } from "@/modules/redis/redis.service";
import { Injectable } from "@nestjs/common";
import { cityTimezonesHandler } from "@calcom/platform-libraries-0.0.19";
import type { CityTimezones } from "@calcom/platform-libraries-0.0.19";
import { cityTimezonesHandler } from "@calcom/platform-libraries-0.0.20";
import type { CityTimezones } from "@calcom/platform-libraries-0.0.20";
@Injectable()
export class TimezonesService {
+4 -24
View File
@@ -5961,22 +5961,6 @@
"freq"
]
},
"Schedule_2024_06_14": {
"type": "object",
"properties": {
"id": {
"type": "number"
},
"timeZone": {
"type": "string",
"nullable": true
}
},
"required": [
"id",
"timeZone"
]
},
"Host": {
"type": "object",
"properties": {
@@ -6091,13 +6075,9 @@
"isInstantEvent": {
"type": "boolean"
},
"schedule": {
"nullable": true,
"allOf": [
{
"$ref": "#/components/schemas/Schedule_2024_06_14"
}
]
"scheduleId": {
"type": "number",
"nullable": true
},
"teamId": {
"type": "number",
@@ -6142,7 +6122,7 @@
"successRedirectUrl",
"seatsShowAvailabilityCount",
"isInstantEvent",
"schedule",
"scheduleId",
"hosts"
]
},
@@ -3,6 +3,8 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { TestingModule } from "@nestjs/testing";
import { Schedule } from "@prisma/client";
import { Prisma } from "@calcom/prisma/client";
export class SchedulesRepositoryFixture {
private primaReadClient: PrismaReadService["prisma"];
private prismaWriteClient: PrismaWriteService["prisma"];
@@ -12,6 +14,10 @@ export class SchedulesRepositoryFixture {
this.prismaWriteClient = module.get(PrismaWriteService).prisma;
}
async create(schedule: Prisma.ScheduleCreateArgs["data"]) {
return this.prismaWriteClient.schedule.create({ data: schedule });
}
async getById(scheduleId: Schedule["id"]) {
return this.primaReadClient.schedule.findFirst({ where: { id: scheduleId } });
}
+4
View File
@@ -1,3 +1,7 @@
## 0.0.20
In event-types create handler (packages/trpc/server/routers/viewer/eventTypes/create.handler.ts) enable passing scheduleId so that when an event type is created it can be connected
to a specific schedule.
## 0.0.19
Added - create event type handler was [updated](https://github.com/calcom/cal.com/pull/15774) for system admins not to be required
to be part of org team when creating event type for team. Update libraries to include these changes.
@@ -68,6 +68,10 @@ export class CreateEventTypeInput_2024_06_14 {
@IsInt()
@IsOptional()
afterEventBuffer?: number;
@IsInt()
@IsOptional()
scheduleId?: number;
}
export enum HostPriority {
@@ -54,6 +54,10 @@ export class UpdateEventTypeInput_2024_06_14 {
@IsInt()
@IsOptional()
afterEventBuffer?: number;
@IsInt()
@IsOptional()
scheduleId?: number;
}
export class UpdateTeamEventTypeInput_2024_06_14 {
@IsOptional()
@@ -25,14 +25,6 @@ enum SchedulingTypeEnum {
export type SchedulingType = "ROUND_ROBIN" | "COLLECTIVE" | "MANAGED";
class Schedule_2024_06_14 {
@IsInt()
id!: number;
@IsString()
timeZone!: string | null;
}
class User_2024_06_14 {
@IsInt()
id!: number;
@@ -143,7 +135,8 @@ export class EventTypeOutput_2024_06_14 {
users!: User_2024_06_14[];
schedule!: Schedule_2024_06_14 | null;
@IsInt()
scheduleId!: number | null;
}
export class TeamEventTypeOutput_2024_06_14 {
@@ -226,7 +219,8 @@ export class TeamEventTypeOutput_2024_06_14 {
@IsBoolean()
isInstantEvent!: boolean;
schedule!: Schedule_2024_06_14 | null;
@IsInt()
scheduleId!: number | null;
@IsInt()
@IsOptional()
+1
View File
@@ -19,6 +19,7 @@ export const createEventTypeInput = z.object({
minimumBookingNotice: z.number().int().min(0).optional(),
beforeEventBuffer: z.number().int().min(0).optional(),
afterEventBuffer: z.number().int().min(0).optional(),
scheduleId: z.number().int().optional()
})
.partial({ hidden: true, locations: true })
.refine((data) => (data.teamId ? data.teamId && data.schedulingType : true), {
@@ -35,7 +35,7 @@ type CreateOptions = {
};
export const createHandler = async ({ ctx, input }: CreateOptions) => {
const { schedulingType, teamId, metadata, locations: inputLocations, ...rest } = input;
const { schedulingType, teamId, metadata, locations: inputLocations, scheduleId, ...rest } = input;
const userId = ctx.user.id;
const isManagedEventType = schedulingType === SchedulingType.MANAGED;
@@ -51,6 +51,7 @@ export const createHandler = async ({ ctx, input }: CreateOptions) => {
// Only connecting the current user for non-managed event types and non team event types
users: isManagedEventType || schedulingType ? undefined : { connect: { id: userId } },
locations,
schedule: scheduleId ? { connect: { id: scheduleId } } : undefined,
};
if (teamId && schedulingType) {
+13 -13
View File
@@ -4065,8 +4065,8 @@ __metadata:
resolution: "@calcom/api-v2@workspace:apps/api/v2"
dependencies:
"@calcom/platform-constants": "*"
"@calcom/platform-libraries-0.0.19": "npm:@calcom/platform-libraries@0.0.19"
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2"
"@calcom/platform-libraries-0.0.20": "npm:@calcom/platform-libraries@0.0.20"
"@calcom/platform-types": "*"
"@calcom/platform-utils": "*"
"@calcom/prisma": "*"
@@ -5025,14 +5025,14 @@ __metadata:
languageName: unknown
linkType: soft
"@calcom/platform-libraries-0.0.19@npm:@calcom/platform-libraries@0.0.19":
version: 0.0.19
resolution: "@calcom/platform-libraries@npm:0.0.19"
"@calcom/platform-libraries-0.0.20@npm:@calcom/platform-libraries@0.0.20":
version: 0.0.20
resolution: "@calcom/platform-libraries@npm:0.0.20"
dependencies:
"@calcom/core": "*"
"@calcom/features": "*"
"@calcom/lib": "*"
checksum: e5c4f2ca63c927e811232d3c83b5341e306d33f3fd0bfdeaf6dcdbca7f31ae02892bd4f8244273cd411fc0b725d2ff7690b58498ae29f6556c22d19159943b08
checksum: f17e9bd51429a1a70240944b8f3836be41790a8c0eba34ddeaa7336c4f98503c0ff8c70c4d79b15809895c3af8462cbf10cff14ca4ba0453cc751febf4dd86cb
languageName: node
linkType: hard
@@ -9012,14 +9012,14 @@ __metadata:
linkType: hard
"@langchain/core@npm:>0.1.56 <0.3.0, @langchain/core@npm:>0.2.0 <0.3.0":
version: 0.2.17
resolution: "@langchain/core@npm:0.2.17"
version: 0.2.18
resolution: "@langchain/core@npm:0.2.18"
dependencies:
ansi-styles: ^5.0.0
camelcase: 6
decamelize: 1.2.0
js-tiktoken: ^1.0.12
langsmith: ~0.1.30
langsmith: ~0.1.39
ml-distance: ^4.0.0
mustache: ^4.2.0
p-queue: ^6.6.2
@@ -9027,7 +9027,7 @@ __metadata:
uuid: ^10.0.0
zod: ^3.22.4
zod-to-json-schema: ^3.22.3
checksum: 76d77a71b7f97ee5383a2d93b9b528349452105a35b0bec181bb5e318a27f95cc75a605975aa604ad176d490fb71d214d43f4ac9be69fbd8312fe6c8e417397a
checksum: f1090a300825a8cefdf873a38926f5a3a8f1208ebcdd9f65c4858e851082b8f89b7b7d7dba50c3907de997b0f2fad2856d611adf61096dffcf240e959809e4fc
languageName: node
linkType: hard
@@ -32993,9 +32993,9 @@ __metadata:
languageName: node
linkType: hard
"langsmith@npm:~0.1.1, langsmith@npm:~0.1.30, langsmith@npm:~0.1.7":
version: 0.1.38
resolution: "langsmith@npm:0.1.38"
"langsmith@npm:~0.1.1, langsmith@npm:~0.1.39, langsmith@npm:~0.1.7":
version: 0.1.39
resolution: "langsmith@npm:0.1.39"
dependencies:
"@types/uuid": ^9.0.1
commander: ^10.0.1
@@ -33013,7 +33013,7 @@ __metadata:
optional: true
openai:
optional: true
checksum: 25e9f68589ef935791258c25c0ac0473f6d45cb6d50970266e3f9ed25eb84530dd5cb8c1a6c13d8ddadf81d2364a56081d5d3798dadb75e685d7c93afac9f903
checksum: df21332662ec3a2d2d5cf915acede52b96aedf2a286259435d683f230af5926500b129cab1f0275450e0d3de6d9d8476e410ac46f5e994beb43f2e2df8a1965f
languageName: node
linkType: hard