diff --git a/apps/api/v2/package.json b/apps/api/v2/package.json index 175ce3e6de..b1f5701746 100644 --- a/apps/api/v2/package.json +++ b/apps/api/v2/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@calcom/platform-constants": "*", - "@calcom/platform-libraries-0.0.18": "npm:@calcom/platform-libraries@0.0.18", + "@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-types": "*", "@calcom/platform-utils": "*", diff --git a/apps/api/v2/src/ee/bookings/controllers/bookings.controller.e2e-spec.ts b/apps/api/v2/src/ee/bookings/controllers/bookings.controller.e2e-spec.ts index 3408cbeca0..cead965ba3 100644 --- a/apps/api/v2/src/ee/bookings/controllers/bookings.controller.e2e-spec.ts +++ b/apps/api/v2/src/ee/bookings/controllers/bookings.controller.e2e-spec.ts @@ -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.18"; +import { handleNewBooking } from "@calcom/platform-libraries-0.0.19"; import { ApiSuccessResponse, ApiResponse } from "@calcom/platform-types"; describe("Bookings Endpoints", () => { diff --git a/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts b/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts index 09ed912043..315188dfb9 100644 --- a/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts +++ b/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts @@ -46,7 +46,7 @@ import { getBookingInfo, handleCancelBooking, getBookingForReschedule, -} from "@calcom/platform-libraries-0.0.18"; +} from "@calcom/platform-libraries-0.0.19"; import { GetBookingsInput, CancelBookingInput, Status } from "@calcom/platform-types"; import { ApiResponse } from "@calcom/platform-types"; import { PrismaClient } from "@calcom/prisma"; diff --git a/apps/api/v2/src/ee/bookings/inputs/create-recurring-booking.input.ts b/apps/api/v2/src/ee/bookings/inputs/create-recurring-booking.input.ts index fb403a909f..757b60dc22 100644 --- a/apps/api/v2/src/ee/bookings/inputs/create-recurring-booking.input.ts +++ b/apps/api/v2/src/ee/bookings/inputs/create-recurring-booking.input.ts @@ -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.18"; +import type { AppsStatus } from "@calcom/platform-libraries-0.0.19"; export class CreateRecurringBookingInput extends CreateBookingInput { @IsBoolean() diff --git a/apps/api/v2/src/ee/calendars/services/apple-calendar.service.ts b/apps/api/v2/src/ee/calendars/services/apple-calendar.service.ts index 1984e3a001..4c0601466d 100644 --- a/apps/api/v2/src/ee/calendars/services/apple-calendar.service.ts +++ b/apps/api/v2/src/ee/calendars/services/apple-calendar.service.ts @@ -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.18"; +import { symmetricEncrypt, CalendarService } from "@calcom/platform-libraries-0.0.19"; @Injectable() export class AppleCalendarService implements CredentialSyncCalendarApp { diff --git a/apps/api/v2/src/ee/calendars/services/calendars.service.ts b/apps/api/v2/src/ee/calendars/services/calendars.service.ts index d1b0056d23..4fbbba049e 100644 --- a/apps/api/v2/src/ee/calendars/services/calendars.service.ts +++ b/apps/api/v2/src/ee/calendars/services/calendars.service.ts @@ -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.18"; +import { getConnectedDestinationCalendars, getBusyCalendarTimes } from "@calcom/platform-libraries-0.0.19"; import { Calendar } from "@calcom/platform-types"; import { PrismaClient } from "@calcom/prisma"; diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/controllers/event-types.controller.e2e-spec.ts b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/controllers/event-types.controller.e2e-spec.ts index f27b559d66..9df8253bdd 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/controllers/event-types.controller.e2e-spec.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/controllers/event-types.controller.e2e-spec.ts @@ -35,7 +35,7 @@ import { EventTypesPublic, eventTypeBookingFields, eventTypeLocations, -} from "@calcom/platform-libraries-0.0.18"; +} from "@calcom/platform-libraries-0.0.19"; import { ApiSuccessResponse } from "@calcom/platform-types"; describe("Event types Endpoints", () => { diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts index efe2cce794..e4e7b03f60 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts @@ -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.18"; +import { getEventTypeById } from "@calcom/platform-libraries-0.0.19"; import type { PrismaClient } from "@calcom/prisma"; @Injectable() diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts index 5de73a413a..dc4f4b881c 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts @@ -14,7 +14,7 @@ import { updateEventType, EventTypesPublic, getEventTypesPublic, -} from "@calcom/platform-libraries-0.0.18"; +} from "@calcom/platform-libraries-0.0.19"; import { EventType } from "@calcom/prisma/client"; @Injectable() diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.module.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.module.ts index cc28b9d0d7..43fbc3e044 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.module.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.module.ts @@ -22,6 +22,11 @@ import { Module } from "@nestjs/common"; UsersService, ], controllers: [EventTypesController_2024_06_14], - exports: [EventTypesService_2024_06_14, EventTypesRepository_2024_06_14], + exports: [ + EventTypesService_2024_06_14, + EventTypesRepository_2024_06_14, + InputEventTypesService_2024_06_14, + OutputEventTypesService_2024_06_14, + ], }) export class EventTypesModule_2024_06_14 {} diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts index bec574cfd7..b410385852 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts @@ -7,7 +7,7 @@ import { getEventTypeById, transformApiEventTypeBookingFields, transformApiEventTypeLocations, -} from "@calcom/platform-libraries-0.0.18"; +} from "@calcom/platform-libraries-0.0.19"; import { CreateEventTypeInput_2024_06_14 } from "@calcom/platform-types"; import type { PrismaClient } from "@calcom/prisma"; diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts index 2d721c19f5..6a93b282a2 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts @@ -9,9 +9,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.18"; -import { getEventTypesPublic, EventTypesPublic } from "@calcom/platform-libraries-0.0.18"; -import { dynamicEvent } from "@calcom/platform-libraries-0.0.18"; +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 { CreateEventTypeInput_2024_06_14, UpdateEventTypeInput_2024_06_14, diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts index f6aace9d3f..0cae1baf8c 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/input-event-types.service.ts @@ -3,7 +3,7 @@ import { Injectable } from "@nestjs/common"; import { transformApiEventTypeBookingFields, transformApiEventTypeLocations, -} from "@calcom/platform-libraries-0.0.18"; +} from "@calcom/platform-libraries-0.0.19"; import { CreateEventTypeInput_2024_06_14, UpdateEventTypeInput_2024_06_14 } from "@calcom/platform-types"; @Injectable() @@ -29,10 +29,11 @@ export class InputEventTypesService_2024_06_14 { } transformInputUpdateEventType(inputEventType: UpdateEventTypeInput_2024_06_14) { - const { locations, bookingFields, ...rest } = inputEventType; + const { lengthInMinutes, locations, bookingFields, ...rest } = inputEventType; const eventType = { ...rest, + length: lengthInMinutes, locations: locations ? this.transformInputLocations(locations) : undefined, bookingFields: bookingFields ? this.transformInputBookingFields(bookingFields) : undefined, }; diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts index f145935b9f..a5c2335e8b 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts @@ -9,7 +9,7 @@ import { parseRecurringEvent, TransformedLocationsSchema, BookingFieldsSchema, -} from "@calcom/platform-libraries-0.0.18"; +} from "@calcom/platform-libraries-0.0.19"; type EventTypeRelations = { users: User[]; schedule: Schedule | null }; type DatabaseEventType = EventType & EventTypeRelations; diff --git a/apps/api/v2/src/ee/schedules/schedules_2024_06_11/services/input-schedules.service.ts b/apps/api/v2/src/ee/schedules/schedules_2024_06_11/services/input-schedules.service.ts index 0b33e9bcb3..fe8adc8b4c 100644 --- a/apps/api/v2/src/ee/schedules/schedules_2024_06_11/services/input-schedules.service.ts +++ b/apps/api/v2/src/ee/schedules/schedules_2024_06_11/services/input-schedules.service.ts @@ -3,7 +3,7 @@ import { Injectable } from "@nestjs/common"; import { transformApiScheduleOverrides, transformApiScheduleAvailability, -} from "@calcom/platform-libraries-0.0.18"; +} from "@calcom/platform-libraries-0.0.19"; import { CreateScheduleInput_2024_06_11, ScheduleAvailabilityInput_2024_06_11 } from "@calcom/platform-types"; import { ScheduleOverrideInput_2024_06_11 } from "@calcom/platform-types"; diff --git a/apps/api/v2/src/filters/trpc-exception.filter.ts b/apps/api/v2/src/filters/trpc-exception.filter.ts index cf32853c29..07360463eb 100644 --- a/apps/api/v2/src/filters/trpc-exception.filter.ts +++ b/apps/api/v2/src/filters/trpc-exception.filter.ts @@ -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.18"; +import { TRPCError } from "@calcom/platform-libraries-0.0.19"; import { Response } from "@calcom/platform-types"; @Catch(TRPCError) diff --git a/apps/api/v2/src/modules/email/email.service.ts b/apps/api/v2/src/modules/email/email.service.ts index a05965b8af..0e004974ad 100644 --- a/apps/api/v2/src/modules/email/email.service.ts +++ b/apps/api/v2/src/modules/email/email.service.ts @@ -1,7 +1,6 @@ -import { UserWithProfile } from "@/modules/users/users.repository"; import { Injectable } from "@nestjs/common"; -import { sendSignupToOrganizationEmail, getTranslation } from "@calcom/platform-libraries-0.0.18"; +import { sendSignupToOrganizationEmail, getTranslation } from "@calcom/platform-libraries-0.0.19"; @Injectable() export class EmailService { diff --git a/apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts b/apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts index 44a28567f4..0577fe3e36 100644 --- a/apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts +++ b/apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts @@ -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.18"; +import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries-0.0.19"; @Injectable() export class OAuthClientUsersService { diff --git a/apps/api/v2/src/modules/organizations/controllers/event-types/organizations-event-types.controller.ts b/apps/api/v2/src/modules/organizations/controllers/event-types/organizations-event-types.controller.ts new file mode 100644 index 0000000000..f2008a31a1 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/controllers/event-types/organizations-event-types.controller.ts @@ -0,0 +1,156 @@ +import { API_VERSIONS_VALUES } from "@/lib/api-versions"; +import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator"; +import { Roles } from "@/modules/auth/decorators/roles/roles.decorator"; +import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard"; +import { IsOrgGuard } from "@/modules/auth/guards/organizations/is-org.guard"; +import { RolesGuard } from "@/modules/auth/guards/roles/roles.guard"; +import { IsTeamInOrg } from "@/modules/auth/guards/teams/is-team-in-org.guard"; +import { CreateTeamEventTypeOutput } from "@/modules/organizations/controllers/event-types/outputs/teams/create-team-event-type.output"; +import { DeleteTeamEventTypeOutput } from "@/modules/organizations/controllers/event-types/outputs/teams/delete-team-event-type.output"; +import { GetTeamEventTypeOutput } from "@/modules/organizations/controllers/event-types/outputs/teams/get-team-event-type.output"; +import { GetTeamEventTypesOutput } from "@/modules/organizations/controllers/event-types/outputs/teams/get-team-event-types.output"; +import { UpdateTeamEventTypeOutput } from "@/modules/organizations/controllers/event-types/outputs/teams/update-team-event-type.output"; +import { OrganizationsEventTypesService } from "@/modules/organizations/services/event-types/organizations-event-types.service"; +import { UserWithProfile } from "@/modules/users/users.repository"; +import { + Controller, + UseGuards, + Get, + Post, + Param, + ParseIntPipe, + Body, + Patch, + Delete, + HttpCode, + HttpStatus, + NotFoundException, + Query, +} from "@nestjs/common"; +import { ApiTags as DocsTags } from "@nestjs/swagger"; + +import { SUCCESS_STATUS } from "@calcom/platform-constants"; +import { + CreateTeamEventTypeInput_2024_06_14, + SkipTakePagination, + UpdateTeamEventTypeInput_2024_06_14, +} from "@calcom/platform-types"; + +@Controller({ + path: "/v2/organizations/:orgId", + version: API_VERSIONS_VALUES, +}) +@UseGuards(ApiAuthGuard, IsOrgGuard, RolesGuard) +@DocsTags("Organizations Event Types") +export class OrganizationsEventTypesController { + constructor(private readonly organizationsEventTypesService: OrganizationsEventTypesService) {} + + @Roles("TEAM_ADMIN") + @UseGuards(IsTeamInOrg) + @Post("/teams/:teamId/event-types") + async createTeamEventType( + @GetUser() user: UserWithProfile, + @Param("teamId", ParseIntPipe) teamId: number, + @Param("orgId", ParseIntPipe) orgId: number, + @Body() bodyEventType: CreateTeamEventTypeInput_2024_06_14 + ): Promise { + const eventType = await this.organizationsEventTypesService.createTeamEventType( + user, + teamId, + orgId, + bodyEventType + ); + + return { + status: SUCCESS_STATUS, + data: eventType, + }; + } + + @Roles("TEAM_ADMIN") + @UseGuards(IsTeamInOrg) + @Get("/teams/:teamId/event-types/:eventTypeId") + async getTeamEventType( + @Param("teamId", ParseIntPipe) teamId: number, + @Param("eventTypeId") eventTypeId: number + ): Promise { + const eventType = await this.organizationsEventTypesService.getTeamEventType(teamId, eventTypeId); + + if (!eventType) { + throw new NotFoundException(`Event type with id ${eventTypeId} not found`); + } + + return { + status: SUCCESS_STATUS, + data: eventType, + }; + } + + @Roles("TEAM_ADMIN") + @UseGuards(IsTeamInOrg) + @Get("/teams/:teamId/event-types") + async getTeamEventTypes(@Param("teamId", ParseIntPipe) teamId: number): Promise { + const eventTypes = await this.organizationsEventTypesService.getTeamEventTypes(teamId); + + return { + status: SUCCESS_STATUS, + data: eventTypes, + }; + } + + @Roles("TEAM_ADMIN") + @Get("/teams/event-types") + async getTeamsEventTypes( + @Param("orgId", ParseIntPipe) orgId: number, + @Query() queryParams: SkipTakePagination + ): Promise { + const { skip, take } = queryParams; + const eventTypes = await this.organizationsEventTypesService.getTeamsEventTypes(orgId, skip, take); + + return { + status: SUCCESS_STATUS, + data: eventTypes, + }; + } + + @Roles("TEAM_ADMIN") + @UseGuards(IsTeamInOrg) + @Patch("/teams/:teamId/event-types/:eventTypeId") + async updateTeamEventType( + @Param("teamId", ParseIntPipe) teamId: number, + @Param("eventTypeId") eventTypeId: number, + @GetUser() user: UserWithProfile, + @Body() bodyEventType: UpdateTeamEventTypeInput_2024_06_14 + ): Promise { + const eventType = await this.organizationsEventTypesService.updateTeamEventType( + eventTypeId, + teamId, + bodyEventType, + user + ); + + return { + status: SUCCESS_STATUS, + data: eventType, + }; + } + + @Roles("TEAM_ADMIN") + @UseGuards(IsTeamInOrg) + @Delete("/teams/:teamId/event-types/:eventTypeId") + @HttpCode(HttpStatus.OK) + async deleteTeamEventType( + @Param("teamId", ParseIntPipe) teamId: number, + @Param("eventTypeId") eventTypeId: number + ): Promise { + const eventType = await this.organizationsEventTypesService.deleteTeamEventType(teamId, eventTypeId); + + return { + status: SUCCESS_STATUS, + data: { + id: eventTypeId, + title: eventType.title, + }, + }; + } +} diff --git a/apps/api/v2/src/modules/organizations/controllers/event-types/organizations-event-types.e2e-spec.ts b/apps/api/v2/src/modules/organizations/controllers/event-types/organizations-event-types.e2e-spec.ts new file mode 100644 index 0000000000..0f18a9b4a6 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/controllers/event-types/organizations-event-types.e2e-spec.ts @@ -0,0 +1,595 @@ +import { bootstrap } from "@/app"; +import { AppModule } from "@/app.module"; +import { PrismaModule } from "@/modules/prisma/prisma.module"; +import { TokensModule } from "@/modules/tokens/tokens.module"; +import { UsersModule } from "@/modules/users/users.module"; +import { INestApplication } from "@nestjs/common"; +import { NestExpressApplication } from "@nestjs/platform-express"; +import { Test } from "@nestjs/testing"; +import { User } from "@prisma/client"; +import * as request from "supertest"; +import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture"; +import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture"; +import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.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"; + +import { SUCCESS_STATUS } from "@calcom/platform-constants"; +import { + ApiSuccessResponse, + CreateTeamEventTypeInput_2024_06_14, + Host, + TeamEventTypeOutput_2024_06_14, + UpdateTeamEventTypeInput_2024_06_14, +} from "@calcom/platform-types"; +import { Team } from "@calcom/prisma/client"; + +describe("Organizations Event Types Endpoints", () => { + describe("User Authentication - User is Org Admin", () => { + let app: INestApplication; + + let userRepositoryFixture: UserRepositoryFixture; + let organizationsRepositoryFixture: TeamRepositoryFixture; + let teamsRepositoryFixture: TeamRepositoryFixture; + let membershipsRepositoryFixture: MembershipRepositoryFixture; + let profileRepositoryFixture: ProfileRepositoryFixture; + let eventTypesRepositoryFixture: EventTypesRepositoryFixture; + + let org: Team; + let team: Team; + let falseTestOrg: Team; + let falseTestTeam: Team; + + const userEmail = "org-admin-event-types-controller-e222e@api.com"; + let userAdmin: User; + + const teammate1Email = "teammate111@team.com"; + const teammate2Email = "teammate221@team.com"; + const falseTestUserEmail = "false-user@false-team.com"; + let teammate1: User; + let teammate2: User; + let falseTestUser: User; + + let collectiveEventType: TeamEventTypeOutput_2024_06_14; + let managedEventType: TeamEventTypeOutput_2024_06_14; + + beforeAll(async () => { + const moduleRef = await withApiAuth( + userEmail, + Test.createTestingModule({ + imports: [AppModule, PrismaModule, UsersModule, TokensModule], + }) + ).compile(); + + userRepositoryFixture = new UserRepositoryFixture(moduleRef); + organizationsRepositoryFixture = new TeamRepositoryFixture(moduleRef); + teamsRepositoryFixture = new TeamRepositoryFixture(moduleRef); + membershipsRepositoryFixture = new MembershipRepositoryFixture(moduleRef); + profileRepositoryFixture = new ProfileRepositoryFixture(moduleRef); + eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef); + + userAdmin = await userRepositoryFixture.create({ + email: userEmail, + username: userEmail, + role: "ADMIN", + }); + + teammate1 = await userRepositoryFixture.create({ + email: teammate1Email, + username: teammate1Email, + }); + + teammate2 = await userRepositoryFixture.create({ + email: teammate2Email, + username: teammate2Email, + }); + + falseTestUser = await userRepositoryFixture.create({ + email: falseTestUserEmail, + username: falseTestUserEmail, + }); + + org = await organizationsRepositoryFixture.create({ + name: "Test Organization", + isOrganization: true, + }); + + falseTestOrg = await organizationsRepositoryFixture.create({ + name: "False test org", + isOrganization: true, + }); + + team = await teamsRepositoryFixture.create({ + name: "Test org team", + isOrganization: false, + parent: { connect: { id: org.id } }, + }); + + falseTestTeam = await teamsRepositoryFixture.create({ + name: "Outside org team", + isOrganization: false, + parent: { connect: { id: falseTestOrg.id } }, + }); + + await profileRepositoryFixture.create({ + uid: `usr-${userAdmin.id}`, + username: userEmail, + organization: { + connect: { + id: org.id, + }, + }, + user: { + connect: { + id: userAdmin.id, + }, + }, + }); + + await membershipsRepositoryFixture.create({ + role: "ADMIN", + user: { connect: { id: userAdmin.id } }, + team: { connect: { id: org.id } }, + accepted: true, + }); + + await membershipsRepositoryFixture.create({ + role: "MEMBER", + user: { connect: { id: teammate1.id } }, + team: { connect: { id: team.id } }, + accepted: true, + }); + + await membershipsRepositoryFixture.create({ + role: "MEMBER", + user: { connect: { id: teammate2.id } }, + team: { connect: { id: team.id } }, + accepted: true, + }); + + await membershipsRepositoryFixture.create({ + role: "MEMBER", + user: { connect: { id: falseTestUser.id } }, + team: { connect: { id: falseTestTeam.id } }, + accepted: true, + }); + + app = moduleRef.createNestApplication(); + bootstrap(app as NestExpressApplication); + + await app.init(); + }); + + it("should be defined", () => { + expect(userRepositoryFixture).toBeDefined(); + expect(organizationsRepositoryFixture).toBeDefined(); + expect(userAdmin).toBeDefined(); + expect(org).toBeDefined(); + }); + + it("should not be able to create event-type for team outside org", async () => { + const body: CreateTeamEventTypeInput_2024_06_14 = { + title: "Coding consultation", + slug: "coding-consultation", + description: "Our team will review your codebase.", + lengthInMinutes: 60, + locations: [ + { + type: "integration", + integration: "cal-video", + }, + ], + schedulingType: "COLLECTIVE", + hosts: [ + { + userId: teammate1.id, + mandatory: true, + priority: "high", + }, + ], + }; + + return request(app.getHttpServer()) + .post(`/v2/organizations/${org.id}/teams/${falseTestTeam.id}/event-types`) + .send(body) + .expect(404); + }); + + it("should not be able to create event-type for user outside org", async () => { + const userId = falseTestUser.id; + + const body: CreateTeamEventTypeInput_2024_06_14 = { + title: "Coding consultation", + slug: "coding-consultation", + description: "Our team will review your codebase.", + lengthInMinutes: 60, + locations: [ + { + type: "integration", + integration: "cal-video", + }, + ], + schedulingType: "COLLECTIVE", + hosts: [ + { + userId, + mandatory: true, + priority: "high", + }, + ], + }; + + return request(app.getHttpServer()) + .post(`/v2/organizations/${org.id}/teams/${team.id}/event-types`) + .send(body) + .expect(404); + }); + + it("should create a collective team event-type", async () => { + const body: CreateTeamEventTypeInput_2024_06_14 = { + title: "Coding consultation collective", + slug: "coding-consultation collective", + description: "Our team will review your codebase.", + lengthInMinutes: 60, + locations: [ + { + type: "integration", + integration: "cal-video", + }, + ], + bookingFields: [ + { + type: "select", + label: "select which language is your codebase in", + slug: "select-language", + required: true, + placeholder: "select language", + options: ["javascript", "python", "cobol"], + }, + ], + schedulingType: "COLLECTIVE", + hosts: [ + { + userId: teammate1.id, + mandatory: true, + priority: "high", + }, + { + userId: teammate2.id, + mandatory: false, + priority: "low", + }, + ], + }; + + return request(app.getHttpServer()) + .post(`/v2/organizations/${org.id}/teams/${team.id}/event-types`) + .send(body) + .expect(201) + .then((response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + + const data = responseBody.data; + expect(data.title).toEqual(body.title); + expect(data.hosts.length).toEqual(2); + evaluateHost(body.hosts[0], data.hosts[0]); + evaluateHost(body.hosts[1], data.hosts[1]); + + collectiveEventType = responseBody.data; + }); + }); + + it("should create a managed team event-type", async () => { + const body: CreateTeamEventTypeInput_2024_06_14 = { + title: "Coding consultation managed", + slug: "coding-consultation-managed", + description: "Our team will review your codebase.", + lengthInMinutes: 60, + locations: [ + { + type: "integration", + integration: "cal-video", + }, + ], + schedulingType: "MANAGED", + hosts: [ + { + userId: teammate1.id, + mandatory: true, + priority: "high", + }, + { + userId: teammate2.id, + mandatory: false, + priority: "low", + }, + ], + }; + + return request(app.getHttpServer()) + .post(`/v2/organizations/${org.id}/teams/${team.id}/event-types`) + .send(body) + .expect(201) + .then(async (response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + + const data = responseBody.data; + expect(data.length).toEqual(3); + + const teammate1EventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(teammate1.id); + const teammate2EventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(teammate2.id); + const teamEventTypes = await eventTypesRepositoryFixture.getAllTeamEventTypes(team.id); + + expect(teammate1EventTypes.length).toEqual(1); + expect(teammate2EventTypes.length).toEqual(1); + expect(teamEventTypes.filter((eventType) => eventType.schedulingType === "MANAGED").length).toEqual( + 1 + ); + + const responseTeamEvent = responseBody.data[0]; + expect(responseTeamEvent?.teamId).toEqual(team.id); + + const responseTeammate1Event = responseBody.data[1]; + expect(responseTeammate1Event?.ownerId).toEqual(teammate1.id); + expect(responseTeammate1Event?.parentEventTypeId).toEqual(responseTeamEvent?.id); + + const responseTeammate2Event = responseBody.data[2]; + expect(responseTeammate2Event?.ownerId).toEqual(teammate2.id); + expect(responseTeammate2Event?.parentEventTypeId).toEqual(responseTeamEvent?.id); + + managedEventType = responseTeamEvent; + }); + }); + + it("should not get an event-type of team outside org", async () => { + return request(app.getHttpServer()) + .get(`/v2/organizations/${org.id}/teams/${falseTestTeam.id}/event-types/${collectiveEventType.id}`) + .expect(404); + }); + + it("should not get a non existing event-type", async () => { + return request(app.getHttpServer()) + .get(`/v2/organizations/${org.id}/teams/${team.id}/event-types/999999`) + .expect(404); + }); + + it("should get a team event-type", async () => { + return request(app.getHttpServer()) + .get(`/v2/organizations/${org.id}/teams/${team.id}/event-types/${collectiveEventType.id}`) + .expect(200) + .then((response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + + const data = responseBody.data; + expect(data.title).toEqual(collectiveEventType.title); + expect(data.hosts.length).toEqual(2); + evaluateHost(collectiveEventType.hosts[0], data.hosts[0]); + evaluateHost(collectiveEventType.hosts[1], data.hosts[1]); + + collectiveEventType = responseBody.data; + }); + }); + + it("should not get event-types of team outside org", async () => { + return request(app.getHttpServer()) + .get(`/v2/organizations/${org.id}/teams/${falseTestTeam.id}/event-types`) + .expect(404); + }); + + it("should get team event-types", async () => { + return request(app.getHttpServer()) + .get(`/v2/organizations/${org.id}/teams/${team.id}/event-types`) + .expect(200) + .then((response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + + const data = responseBody.data; + console.log("asap responseBody.data", JSON.stringify(responseBody.data, null, 2)); + expect(data.length).toEqual(2); + + const eventTypeCollective = data.find((eventType) => eventType.schedulingType === "COLLECTIVE"); + const eventTypeManaged = data.find((eventType) => eventType.schedulingType === "MANAGED"); + + expect(eventTypeCollective?.title).toEqual(collectiveEventType.title); + expect(eventTypeCollective?.hosts.length).toEqual(2); + + expect(eventTypeManaged?.title).toEqual(managedEventType.title); + expect(eventTypeManaged?.hosts.length).toEqual(2); + evaluateHost(collectiveEventType.hosts[0], eventTypeCollective?.hosts[0]); + evaluateHost(collectiveEventType.hosts[1], eventTypeCollective?.hosts[1]); + }); + }); + + it("should not be able to update event-type for incorrect team", async () => { + const body: UpdateTeamEventTypeInput_2024_06_14 = { + title: "Clean code consultation", + }; + + return request(app.getHttpServer()) + .patch(`/v2/organizations/${org.id}/teams/${falseTestTeam.id}/event-types/${collectiveEventType.id}`) + .send(body) + .expect(404); + }); + + it("should not be able to update non existing event-type", async () => { + const body: UpdateTeamEventTypeInput_2024_06_14 = { + title: "Clean code consultation", + }; + + return request(app.getHttpServer()) + .patch(`/v2/organizations/${org.id}/teams/${team.id}/event-types/999999`) + .send(body) + .expect(404); + }); + + it("should update collective event-type", async () => { + const newHosts: UpdateTeamEventTypeInput_2024_06_14["hosts"] = [ + { + userId: teammate1.id, + mandatory: true, + priority: "medium", + }, + ]; + + const body: UpdateTeamEventTypeInput_2024_06_14 = { + hosts: newHosts, + }; + + return request(app.getHttpServer()) + .patch(`/v2/organizations/${org.id}/teams/${team.id}/event-types/${collectiveEventType.id}`) + .send(body) + .expect(200) + .then((response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + + const eventType = responseBody.data; + expect(eventType.title).toEqual(collectiveEventType.title); + expect(eventType.hosts.length).toEqual(1); + evaluateHost(eventType.hosts[0], newHosts[0]); + }); + }); + + it("should update managed event-type", async () => { + const newTitle = "Coding consultation managed updated"; + const newHosts: UpdateTeamEventTypeInput_2024_06_14["hosts"] = [ + { + userId: teammate1.id, + mandatory: true, + priority: "medium", + }, + ]; + + const body: UpdateTeamEventTypeInput_2024_06_14 = { + title: newTitle, + hosts: newHosts, + }; + + return request(app.getHttpServer()) + .patch(`/v2/organizations/${org.id}/teams/${team.id}/event-types/${managedEventType.id}`) + .send(body) + .expect(200) + .then(async (response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + + const data = responseBody.data; + expect(data.length).toEqual(2); + + const teammate1EventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(teammate1.id); + const teammate2EventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(teammate2.id); + const teamEventTypes = await eventTypesRepositoryFixture.getAllTeamEventTypes(team.id); + const managedTeamEventTypes = teamEventTypes.filter( + (eventType) => eventType.schedulingType === "MANAGED" + ); + + expect(teammate1EventTypes.length).toEqual(1); + expect(teammate2EventTypes.length).toEqual(0); + expect(managedTeamEventTypes.length).toEqual(1); + expect(managedTeamEventTypes[0].assignAllTeamMembers).toEqual(false); + + const responseTeamEvent = responseBody.data[0]; + expect(responseTeamEvent.title).toEqual(newTitle); + expect(responseTeamEvent.assignAllTeamMembers).toEqual(false); + + const responseTeammate1Event = responseBody.data[1]; + expect(responseTeammate1Event.title).toEqual(newTitle); + + expect(teammate1EventTypes[0].title).toEqual(newTitle); + expect( + teamEventTypes.filter((eventType) => eventType.schedulingType === "MANAGED")?.[0]?.title + ).toEqual(newTitle); + + managedEventType = responseBody.data[0]; + }); + }); + + it("should assign all members to managed event-type", async () => { + const body: UpdateTeamEventTypeInput_2024_06_14 = { + assignAllTeamMembers: true, + }; + + return request(app.getHttpServer()) + .patch(`/v2/organizations/${org.id}/teams/${team.id}/event-types/${managedEventType.id}`) + .send(body) + .expect(200) + .then(async (response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.status).toEqual(SUCCESS_STATUS); + + const data = responseBody.data; + expect(data.length).toEqual(3); + + const teammate1EventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(teammate1.id); + const teammate2EventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(teammate2.id); + const teamEventTypes = await eventTypesRepositoryFixture.getAllTeamEventTypes(team.id); + const managedTeamEventTypes = teamEventTypes.filter( + (eventType) => eventType.schedulingType === "MANAGED" + ); + + expect(teammate1EventTypes.length).toEqual(1); + expect(teammate2EventTypes.length).toEqual(1); + expect(managedTeamEventTypes.length).toEqual(1); + expect(managedTeamEventTypes[0].assignAllTeamMembers).toEqual(true); + + const responseTeamEvent = responseBody.data[0]; + expect(responseTeamEvent?.teamId).toEqual(team.id); + expect(responseTeamEvent.assignAllTeamMembers).toEqual(true); + + const responseTeammate1Event = responseBody.data[1]; + expect(responseTeammate1Event?.ownerId).toEqual(teammate1.id); + expect(responseTeammate1Event?.parentEventTypeId).toEqual(responseTeamEvent?.id); + + const responseTeammate2Event = responseBody.data[2]; + expect(responseTeammate2Event?.ownerId).toEqual(teammate2.id); + expect(responseTeammate2Event?.parentEventTypeId).toEqual(responseTeamEvent?.id); + + managedEventType = responseTeamEvent; + }); + }); + + it("should not delete event-type of team outside org", async () => { + return request(app.getHttpServer()) + .delete(`/v2/organizations/${org.id}/teams/${falseTestTeam.id}/event-types/${collectiveEventType.id}`) + .expect(404); + }); + + it("should delete event-type not part of the team", async () => { + return request(app.getHttpServer()) + .delete(`/v2/organizations/${org.id}/teams/${team.id}/event-types/99999`) + .expect(404); + }); + + it("should delete collective event-type", async () => { + return request(app.getHttpServer()) + .delete(`/v2/organizations/${org.id}/teams/${team.id}/event-types/${collectiveEventType.id}`) + .expect(200); + }); + + it("should delete managed event-type", async () => { + return request(app.getHttpServer()) + .delete(`/v2/organizations/${org.id}/teams/${team.id}/event-types/${managedEventType.id}`) + .expect(200); + }); + + function evaluateHost(expected: Host, received: Host | undefined) { + expect(expected.userId).toEqual(received?.userId); + expect(expected.mandatory).toEqual(received?.mandatory); + expect(expected.priority).toEqual(received?.priority); + } + + afterAll(async () => { + await userRepositoryFixture.deleteByEmail(userAdmin.email); + await userRepositoryFixture.deleteByEmail(teammate1.email); + await userRepositoryFixture.deleteByEmail(teammate2.email); + await teamsRepositoryFixture.delete(team.id); + await organizationsRepositoryFixture.delete(org.id); + await app.close(); + }); + }); +}); diff --git a/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/create-team-event-type.output.ts b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/create-team-event-type.output.ts new file mode 100644 index 0000000000..960a7d8466 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/create-team-event-type.output.ts @@ -0,0 +1,21 @@ +import { ApiProperty, getSchemaPath } from "@nestjs/swagger"; +import { Type } from "class-transformer"; +import { IsNotEmptyObject, ValidateNested } from "class-validator"; + +import { ApiResponseWithoutData, TeamEventTypeOutput_2024_06_14 } from "@calcom/platform-types"; + +export class CreateTeamEventTypeOutput extends ApiResponseWithoutData { + @IsNotEmptyObject() + @ValidateNested() + @ApiProperty({ + oneOf: [ + { $ref: getSchemaPath(TeamEventTypeOutput_2024_06_14) }, + { + type: "array", + items: { $ref: getSchemaPath(TeamEventTypeOutput_2024_06_14) }, + }, + ], + }) + @Type(() => TeamEventTypeOutput_2024_06_14) + data!: TeamEventTypeOutput_2024_06_14 | TeamEventTypeOutput_2024_06_14[]; +} diff --git a/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/delete-team-event-type.output.ts b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/delete-team-event-type.output.ts new file mode 100644 index 0000000000..300728c55f --- /dev/null +++ b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/delete-team-event-type.output.ts @@ -0,0 +1,10 @@ +import { Type } from "class-transformer"; +import { ValidateNested } from "class-validator"; + +import { ApiResponseWithoutData, TeamEventTypeOutput_2024_06_14 } from "@calcom/platform-types"; + +export class DeleteTeamEventTypeOutput extends ApiResponseWithoutData { + @ValidateNested() + @Type(() => TeamEventTypeOutput_2024_06_14) + data!: Pick; +} diff --git a/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/get-team-event-type.output.ts b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/get-team-event-type.output.ts new file mode 100644 index 0000000000..3206c66a58 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/get-team-event-type.output.ts @@ -0,0 +1,10 @@ +import { Type } from "class-transformer"; +import { ValidateNested } from "class-validator"; + +import { ApiResponseWithoutData, TeamEventTypeOutput_2024_06_14 } from "@calcom/platform-types"; + +export class GetTeamEventTypeOutput extends ApiResponseWithoutData { + @ValidateNested() + @Type(() => TeamEventTypeOutput_2024_06_14) + data!: TeamEventTypeOutput_2024_06_14; +} diff --git a/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/get-team-event-types.output.ts b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/get-team-event-types.output.ts new file mode 100644 index 0000000000..939c74c369 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/get-team-event-types.output.ts @@ -0,0 +1,10 @@ +import { Type } from "class-transformer"; +import { ValidateNested } from "class-validator"; + +import { ApiResponseWithoutData, TeamEventTypeOutput_2024_06_14 } from "@calcom/platform-types"; + +export class GetTeamEventTypesOutput extends ApiResponseWithoutData { + @ValidateNested({ each: true }) + @Type(() => TeamEventTypeOutput_2024_06_14) + data!: TeamEventTypeOutput_2024_06_14[]; +} diff --git a/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/update-team-event-type.output.ts b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/update-team-event-type.output.ts new file mode 100644 index 0000000000..403280b7a5 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/controllers/event-types/outputs/teams/update-team-event-type.output.ts @@ -0,0 +1,21 @@ +import { ApiProperty, getSchemaPath } from "@nestjs/swagger"; +import { Type } from "class-transformer"; +import { IsNotEmptyObject, ValidateNested } from "class-validator"; + +import { ApiResponseWithoutData, TeamEventTypeOutput_2024_06_14 } from "@calcom/platform-types"; + +export class UpdateTeamEventTypeOutput extends ApiResponseWithoutData { + @IsNotEmptyObject() + @ValidateNested() + @ApiProperty({ + oneOf: [ + { $ref: getSchemaPath(TeamEventTypeOutput_2024_06_14) }, + { + type: "array", + items: { $ref: getSchemaPath(TeamEventTypeOutput_2024_06_14) }, + }, + ], + }) + @Type(() => TeamEventTypeOutput_2024_06_14) + data!: TeamEventTypeOutput_2024_06_14 | TeamEventTypeOutput_2024_06_14[]; +} diff --git a/apps/api/v2/src/modules/organizations/organizations.module.ts b/apps/api/v2/src/modules/organizations/organizations.module.ts index d842f174c2..a2eed9969a 100644 --- a/apps/api/v2/src/modules/organizations/organizations.module.ts +++ b/apps/api/v2/src/modules/organizations/organizations.module.ts @@ -1,18 +1,24 @@ +import { EventTypesModule_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.module"; import { SchedulesModule_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.module"; import { EmailModule } from "@/modules/email/email.module"; import { EmailService } from "@/modules/email/email.service"; import { MembershipsRepository } from "@/modules/memberships/memberships.repository"; +import { OrganizationsEventTypesController } from "@/modules/organizations/controllers/event-types/organizations-event-types.controller"; import { OrganizationsMembershipsController } from "@/modules/organizations/controllers/memberships/organizations-membership.controller"; import { OrganizationsSchedulesController } from "@/modules/organizations/controllers/schedules/organizations-schedules.controller"; import { OrganizationsTeamsMembershipsController } from "@/modules/organizations/controllers/teams/memberships/organizations-teams-memberships.controller"; import { OrganizationsTeamsController } from "@/modules/organizations/controllers/teams/organizations-teams.controller"; import { OrganizationsUsersController } from "@/modules/organizations/controllers/users/organizations-users.controller"; import { OrganizationsRepository } from "@/modules/organizations/organizations.repository"; +import { OrganizationsEventTypesRepository } from "@/modules/organizations/repositories/organizations-event-types.repository"; import { OrganizationsMembershipRepository } from "@/modules/organizations/repositories/organizations-membership.repository"; import { OrganizationSchedulesRepository } from "@/modules/organizations/repositories/organizations-schedules.repository"; import { OrganizationsTeamsMembershipsRepository } from "@/modules/organizations/repositories/organizations-teams-memberships.repository"; import { OrganizationsTeamsRepository } from "@/modules/organizations/repositories/organizations-teams.repository"; import { OrganizationsUsersRepository } from "@/modules/organizations/repositories/organizations-users.repository"; +import { InputOrganizationsEventTypesService } from "@/modules/organizations/services/event-types/input.service"; +import { OrganizationsEventTypesService } from "@/modules/organizations/services/event-types/organizations-event-types.service"; +import { OutputOrganizationsEventTypesService } from "@/modules/organizations/services/event-types/output.service"; import { OrganizationsMembershipService } from "@/modules/organizations/services/organizations-membership.service"; import { OrganizationsSchedulesService } from "@/modules/organizations/services/organizations-schedules.service"; import { OrganizationsTeamsMembershipsService } from "@/modules/organizations/services/organizations-teams-memberships.service"; @@ -26,7 +32,15 @@ import { UsersModule } from "@/modules/users/users.module"; import { Module } from "@nestjs/common"; @Module({ - imports: [PrismaModule, StripeModule, SchedulesModule_2024_06_11, UsersModule, RedisModule, EmailModule], + imports: [ + PrismaModule, + StripeModule, + SchedulesModule_2024_06_11, + UsersModule, + RedisModule, + EmailModule, + EventTypesModule_2024_06_14, + ], providers: [ OrganizationsRepository, OrganizationsTeamsRepository, @@ -40,6 +54,10 @@ import { Module } from "@nestjs/common"; EmailService, OrganizationsMembershipRepository, OrganizationsMembershipService, + OrganizationsEventTypesService, + InputOrganizationsEventTypesService, + OutputOrganizationsEventTypesService, + OrganizationsEventTypesRepository, OrganizationsTeamsMembershipsRepository, OrganizationsTeamsMembershipsService, ], @@ -59,6 +77,7 @@ import { Module } from "@nestjs/common"; OrganizationsSchedulesController, OrganizationsUsersController, OrganizationsMembershipsController, + OrganizationsEventTypesController, OrganizationsTeamsMembershipsController, ], }) diff --git a/apps/api/v2/src/modules/organizations/repositories/organizations-event-types.repository.ts b/apps/api/v2/src/modules/organizations/repositories/organizations-event-types.repository.ts new file mode 100644 index 0000000000..b71d77fa21 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/repositories/organizations-event-types.repository.ts @@ -0,0 +1,61 @@ +import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; +import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; +import { Injectable } from "@nestjs/common"; + +@Injectable() +export class OrganizationsEventTypesRepository { + constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {} + + async getTeamEventType(teamId: number, eventTypeId: number) { + return this.dbRead.prisma.eventType.findUnique({ + where: { + id: eventTypeId, + teamId, + }, + include: { users: true, schedule: true, hosts: true }, + }); + } + + async getTeamEventTypes(teamId: number) { + return this.dbRead.prisma.eventType.findMany({ + where: { + teamId, + }, + include: { users: true, schedule: true, hosts: true }, + }); + } + + async getEventTypeById(eventTypeId: number) { + return this.dbRead.prisma.eventType.findUnique({ + where: { id: eventTypeId }, + include: { users: true, schedule: true, hosts: true }, + }); + } + + async getEventTypeChildren(eventTypeId: number) { + return this.dbRead.prisma.eventType.findMany({ + where: { parentId: eventTypeId }, + include: { users: true, schedule: true, hosts: true }, + }); + } + + async getTeamsEventTypes(orgId: number, skip: number, take: number) { + return this.dbRead.prisma.eventType.findMany({ + where: { + team: { + parentId: orgId, + }, + }, + skip, + take, + include: { users: true, schedule: true, hosts: true }, + }); + } + + async getEventTypeByIdWithChildren(eventTypeId: number) { + return this.dbRead.prisma.eventType.findUnique({ + where: { id: eventTypeId }, + include: { children: true }, + }); + } +} diff --git a/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts b/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts index d51104ebfe..3b13012718 100644 --- a/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts +++ b/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts @@ -1,17 +1,10 @@ -import { PlatformPlan } from "@/modules/billing/types"; import { CreateOrgTeamDto } from "@/modules/organizations/inputs/create-organization-team.input"; import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; -import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; -import { StripeService } from "@/modules/stripe/stripe.service"; import { Injectable } from "@nestjs/common"; @Injectable() export class OrganizationsTeamsRepository { - constructor( - private readonly dbRead: PrismaReadService, - private readonly dbWrite: PrismaWriteService, - private readonly stripeService: StripeService - ) {} + constructor(private readonly dbRead: PrismaReadService) {} async findOrgTeam(organizationId: number, teamId: number) { return this.dbRead.prisma.team.findUnique({ @@ -55,4 +48,20 @@ export class OrganizationsTeamsRepository { take, }); } + + async getTeamMembersIds(teamId: number) { + const team = await this.dbRead.prisma.team.findUnique({ + where: { + id: teamId, + }, + include: { + members: true, + }, + }); + if (!team) { + return []; + } + + return team.members.map((member) => member.userId); + } } diff --git a/apps/api/v2/src/modules/organizations/services/event-types/input.service.ts b/apps/api/v2/src/modules/organizations/services/event-types/input.service.ts new file mode 100644 index 0000000000..766cf64c42 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/services/event-types/input.service.ts @@ -0,0 +1,162 @@ +import { InputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/input-event-types.service"; +import { OrganizationsEventTypesRepository } from "@/modules/organizations/repositories/organizations-event-types.repository"; +import { OrganizationsTeamsRepository } from "@/modules/organizations/repositories/organizations-teams.repository"; +import { UsersRepository } from "@/modules/users/users.repository"; +import { Injectable } from "@nestjs/common"; + +import { + CreateTeamEventTypeInput_2024_06_14, + UpdateTeamEventTypeInput_2024_06_14, + HostPriority, +} from "@calcom/platform-types"; + +@Injectable() +export class InputOrganizationsEventTypesService { + constructor( + private readonly inputEventTypesService: InputEventTypesService_2024_06_14, + private readonly organizationsTeamsRepository: OrganizationsTeamsRepository, + private readonly usersRepository: UsersRepository, + private readonly orgEventTypesRepository: OrganizationsEventTypesRepository + ) {} + async transformInputCreateTeamEventType( + teamId: number, + inputEventType: CreateTeamEventTypeInput_2024_06_14 + ) { + const { hosts, assignAllTeamMembers, ...rest } = inputEventType; + + const eventType = this.inputEventTypesService.transformInputCreateEventType(rest); + + const metadata = rest.schedulingType === "MANAGED" ? { managedEventConfig: {} } : undefined; + + const teamEventType = { + ...eventType, + hosts: assignAllTeamMembers ? await this.getAllTeamMembers(teamId) : this.transformInputHosts(hosts), + assignAllTeamMembers, + metadata, + }; + + return teamEventType; + } + + async transformInputUpdateTeamEventType( + eventTypeId: number, + teamId: number, + inputEventType: UpdateTeamEventTypeInput_2024_06_14 + ) { + const { hosts, assignAllTeamMembers, ...rest } = inputEventType; + + const eventType = this.inputEventTypesService.transformInputUpdateEventType(rest); + + const children = await this.getChildEventTypesForManagedEventType(eventTypeId, inputEventType, teamId); + const teamEventType = { + ...eventType, + // note(Lauris): we don't populate hosts for managed event-types because they are handled by the children + hosts: !children + ? assignAllTeamMembers + ? await this.getAllTeamMembers(teamId) + : this.transformInputHosts(hosts) + : undefined, + assignAllTeamMembers, + children, + }; + + return teamEventType; + } + + async getChildEventTypesForManagedEventType( + eventTypeId: number, + inputEventType: UpdateTeamEventTypeInput_2024_06_14, + teamId: number + ) { + const eventType = await this.orgEventTypesRepository.getEventTypeByIdWithChildren(eventTypeId); + + if (!eventType || eventType.schedulingType !== "MANAGED") { + return undefined; + } + + const ownersIds = await this.getOwnersIdsForManagedEventType(teamId, inputEventType, eventType); + const owners = await this.getOwnersForManagedEventType(ownersIds); + + return owners.map((owner) => { + return { + hidden: false, + owner, + }; + }); + } + + async getOwnersIdsForManagedEventType( + teamId: number, + inputEventType: UpdateTeamEventTypeInput_2024_06_14, + eventType: { children: { userId: number | null }[] } + ) { + if (inputEventType.assignAllTeamMembers) { + return await this.organizationsTeamsRepository.getTeamMembersIds(teamId); + } + + // note(Lauris): when API user updates managed event type users + if (inputEventType.hosts) { + return inputEventType.hosts.map((host) => host.userId); + } + + // note(Lauris): when API user DOES NOT update managed event type users, but we still need existing managed event type users to know which event-types to update + return eventType.children.map((child) => child.userId).filter((id) => !!id) as number[]; + } + + async getOwnersForManagedEventType(userIds: number[]) { + const users = await this.usersRepository.findByIdsWithEventTypes(userIds); + + return users.map((user) => { + const nonManagedEventTypes = user.eventTypes.filter((eventType) => !eventType.parentId); + return { + id: user.id, + name: user.name || user.email, + email: user.email, + // note(Lauris): managed event types slugs have to be excluded otherwise checkExistentEventTypes within handleChildrenEventTypes.ts will incorrectly delete managed user event type. + eventTypeSlugs: nonManagedEventTypes.map((eventType) => eventType.slug), + }; + }); + } + + async getAllTeamMembers(teamId: number) { + const membersIds = await this.organizationsTeamsRepository.getTeamMembersIds(teamId); + + return membersIds.map((id) => ({ + userId: id, + isFixed: false, + priority: 2, + })); + } + + transformInputHosts(inputHosts: CreateTeamEventTypeInput_2024_06_14["hosts"] | undefined) { + if (!inputHosts) { + return undefined; + } + + const defaultMandatory = false; + const defaultPriority = "medium"; + + return inputHosts.map((host) => ({ + userId: host.userId, + isFixed: host.mandatory || defaultMandatory, + priority: getPriorityValue(host.priority || defaultPriority), + })); + } +} + +function getPriorityValue(priority: keyof typeof HostPriority): number { + switch (priority) { + case "lowest": + return 0; + case "low": + return 1; + case "medium": + return 2; + case "high": + return 3; + case "highest": + return 4; + default: + throw new Error("Invalid HostPriority label"); + } +} diff --git a/apps/api/v2/src/modules/organizations/services/event-types/organizations-event-types.service.ts b/apps/api/v2/src/modules/organizations/services/event-types/organizations-event-types.service.ts new file mode 100644 index 0000000000..5ddcafe750 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/services/event-types/organizations-event-types.service.ts @@ -0,0 +1,179 @@ +import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.repository"; +import { EventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/event-types.service"; +import { MembershipsRepository } from "@/modules/memberships/memberships.repository"; +import { OrganizationsEventTypesRepository } from "@/modules/organizations/repositories/organizations-event-types.repository"; +import { OrganizationsTeamsRepository } from "@/modules/organizations/repositories/organizations-teams.repository"; +import { InputOrganizationsEventTypesService } from "@/modules/organizations/services/event-types/input.service"; +import { OutputOrganizationsEventTypesService } from "@/modules/organizations/services/event-types/output.service"; +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 { + CreateTeamEventTypeInput_2024_06_14, + UpdateTeamEventTypeInput_2024_06_14, +} from "@calcom/platform-types"; + +@Injectable() +export class OrganizationsEventTypesService { + constructor( + private readonly inputService: InputOrganizationsEventTypesService, + private readonly eventTypesService: EventTypesService_2024_06_14, + private readonly dbWrite: PrismaWriteService, + private readonly organizationEventTypesRepository: OrganizationsEventTypesRepository, + private readonly eventTypesRepository: EventTypesRepository_2024_06_14, + private readonly outputService: OutputOrganizationsEventTypesService, + private readonly membershipsRepository: MembershipsRepository, + private readonly organizationsTeamsRepository: OrganizationsTeamsRepository + ) {} + + async createTeamEventType( + user: UserWithProfile, + teamId: number, + orgId: number, + body: CreateTeamEventTypeInput_2024_06_14 + ) { + await this.validateHosts(teamId, body.hosts); + const eventTypeUser = await this.getUserToCreateTeamEvent(user, orgId); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { hosts, assignAllTeamMembers, ...rest } = + await this.inputService.transformInputCreateTeamEventType(teamId, body); + const { eventType: eventTypeCreated } = await createEventType({ + input: { teamId: teamId, ...rest }, + ctx: { + user: eventTypeUser, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + prisma: this.dbWrite.prisma, + }, + }); + + return await this.updateTeamEventType( + eventTypeCreated.id, + teamId, + { hosts: body.hosts, assignAllTeamMembers }, + user + ); + } + + async validateHosts(teamId: number, hosts: CreateTeamEventTypeInput_2024_06_14["hosts"] | undefined) { + if (hosts && hosts.length) { + const membersIds = await this.organizationsTeamsRepository.getTeamMembersIds(teamId); + const invalidHosts = hosts.filter((host) => !membersIds.includes(host.userId)); + if (invalidHosts.length) { + throw new NotFoundException(`Invalid hosts: ${invalidHosts.join(", ")}`); + } + } + } + + async validateEventTypeExists(teamId: number, eventTypeId: number) { + const eventType = await this.organizationEventTypesRepository.getTeamEventType(teamId, eventTypeId); + + if (!eventType) { + throw new NotFoundException(`Event type with id ${eventTypeId} not found`); + } + } + + async getUserToCreateTeamEvent(user: UserWithProfile, organizationId: number) { + const isOrgAdmin = await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId); + const profileId = user.movedToProfileId || null; + return { + id: user.id, + role: user.role, + organizationId: user.organizationId, + organization: { isOrgAdmin }, + profile: { id: profileId }, + metadata: user.metadata, + }; + } + + async getTeamEventType(teamId: number, eventTypeId: number) { + const eventType = await this.organizationEventTypesRepository.getTeamEventType(teamId, eventTypeId); + + if (!eventType) { + return null; + } + + return this.outputService.getResponseTeamEventType(eventType); + } + + async getTeamEventTypes(teamId: number) { + const eventTypes = await this.organizationEventTypesRepository.getTeamEventTypes(teamId); + + const eventTypePromises = eventTypes.map(async (eventType) => { + return await this.outputService.getResponseTeamEventType(eventType); + }); + + return await Promise.all(eventTypePromises); + } + + async getTeamsEventTypes(orgId: number, skip = 0, take = 250) { + const eventTypes = await this.organizationEventTypesRepository.getTeamsEventTypes(orgId, skip, take); + + const eventTypePromises = eventTypes.map(async (eventType) => { + return await this.outputService.getResponseTeamEventType(eventType); + }); + + return await Promise.all(eventTypePromises); + } + + async updateTeamEventType( + eventTypeId: number, + teamId: number, + body: UpdateTeamEventTypeInput_2024_06_14, + user: UserWithProfile + ) { + await this.validateEventTypeExists(teamId, eventTypeId); + await this.validateHosts(teamId, body.hosts); + const eventTypeUser = await this.eventTypesService.getUserToUpdateEvent(user); + const bodyTransformed = await this.inputService.transformInputUpdateTeamEventType( + eventTypeId, + teamId, + body + ); + + await updateEventType({ + input: { id: eventTypeId, ...bodyTransformed }, + ctx: { + user: eventTypeUser, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + prisma: this.dbWrite.prisma, + }, + }); + + const eventType = await this.organizationEventTypesRepository.getEventTypeById(eventTypeId); + + if (!eventType) { + throw new NotFoundException(`Event type with id ${eventTypeId} not found`); + } + + if (eventType.schedulingType !== "MANAGED") { + return this.outputService.getResponseTeamEventType(eventType); + } + + const children = await this.organizationEventTypesRepository.getEventTypeChildren(eventType.id); + + const eventTypes = [eventType, ...children]; + + const eventTypePromises = eventTypes.map(async (e) => { + return await this.outputService.getResponseTeamEventType(e); + }); + + return await Promise.all(eventTypePromises); + } + + async deleteTeamEventType(teamId: number, eventTypeId: number) { + const existingEventType = await this.organizationEventTypesRepository.getTeamEventType( + teamId, + eventTypeId + ); + + if (!existingEventType) { + throw new NotFoundException(`Event type with ID=${eventTypeId} does not exist.`); + } + + return this.eventTypesRepository.deleteEventType(eventTypeId); + } +} diff --git a/apps/api/v2/src/modules/organizations/services/event-types/output.service.ts b/apps/api/v2/src/modules/organizations/services/event-types/output.service.ts new file mode 100644 index 0000000000..3eaf5eb009 --- /dev/null +++ b/apps/api/v2/src/modules/organizations/services/event-types/output.service.ts @@ -0,0 +1,114 @@ +import { OutputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/output-event-types.service"; +import { OrganizationsEventTypesRepository } from "@/modules/organizations/repositories/organizations-event-types.repository"; +import { Injectable } from "@nestjs/common"; +import type { EventType, User, Schedule, Host } from "@prisma/client"; + +import { HostPriority } from "@calcom/platform-types"; + +type EventTypeRelations = { users: User[]; schedule: Schedule | null; hosts: Host[] }; +type DatabaseEventType = EventType & EventTypeRelations; + +type Input = Pick< + DatabaseEventType, + | "id" + | "length" + | "title" + | "description" + | "disableGuests" + | "slotInterval" + | "minimumBookingNotice" + | "beforeEventBuffer" + | "afterEventBuffer" + | "slug" + | "schedulingType" + | "requiresConfirmation" + | "price" + | "currency" + | "lockTimeZoneToggleOnBookingPage" + | "seatsPerTimeSlot" + | "forwardParamsSuccessRedirect" + | "successRedirectUrl" + | "seatsShowAvailabilityCount" + | "isInstantEvent" + | "locations" + | "bookingFields" + | "recurringEvent" + | "metadata" + | "users" + | "schedule" + | "hosts" + | "teamId" + | "userId" + | "parentId" + | "assignAllTeamMembers" +>; + +@Injectable() +export class OutputOrganizationsEventTypesService { + constructor( + private readonly outputEventTypesService: OutputEventTypesService_2024_06_14, + private readonly organizationEventTypesRepository: OrganizationsEventTypesRepository + ) {} + + async getResponseTeamEventType(databaseEventType: Input) { + const { teamId, userId, parentId, assignAllTeamMembers } = databaseEventType; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { ownerId, users, ...rest } = await this.outputEventTypesService.getResponseEventType( + 0, + databaseEventType + ); + const hosts = + databaseEventType.schedulingType === "MANAGED" + ? await this.getManagedEventTypeHosts(databaseEventType.id) + : this.transformHosts(databaseEventType.hosts); + + return { + ...rest, + hosts, + teamId, + ownerId: userId, + parentEventTypeId: parentId, + assignAllTeamMembers: teamId ? assignAllTeamMembers : undefined, + }; + } + + async getManagedEventTypeHosts(eventTypeId: number) { + const children = await this.organizationEventTypesRepository.getEventTypeChildren(eventTypeId); + const hostsIds: number[] = []; + for (const child of children) { + if (child.userId) { + hostsIds.push(child.userId); + } + } + return hostsIds.map((userId) => ({ userId })); + } + + transformHosts(hosts: Host[]) { + if (!hosts) return []; + + return hosts.map((host) => { + return { + userId: host.userId, + mandatory: host.isFixed, + priority: getPriorityLabel(host.priority || 2), + }; + }); + } +} + +function getPriorityLabel(priority: number): keyof typeof HostPriority { + switch (priority) { + case 0: + return "lowest"; + case 1: + return "low"; + case 2: + return "medium"; + case 3: + return "high"; + case 4: + return "highest"; + default: + throw new Error("Invalid HostPriority value"); + } +} diff --git a/apps/api/v2/src/modules/organizations/services/organizations-users-service.ts b/apps/api/v2/src/modules/organizations/services/organizations-users-service.ts index 83eaab5b73..4c6a964cc0 100644 --- a/apps/api/v2/src/modules/organizations/services/organizations-users-service.ts +++ b/apps/api/v2/src/modules/organizations/services/organizations-users-service.ts @@ -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.18"; +import { createNewUsersConnectToOrgIfExists } from "@calcom/platform-libraries-0.0.19"; import { Team } from "@calcom/prisma/client"; @Injectable() diff --git a/apps/api/v2/src/modules/slots/controllers/slots.controller.ts b/apps/api/v2/src/modules/slots/controllers/slots.controller.ts index a3a0c2c3df..f661ef6f8b 100644 --- a/apps/api/v2/src/modules/slots/controllers/slots.controller.ts +++ b/apps/api/v2/src/modules/slots/controllers/slots.controller.ts @@ -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.18"; -import type { AvailableSlotsType } from "@calcom/platform-libraries-0.0.18"; +import { getAvailableSlots } from "@calcom/platform-libraries-0.0.19"; +import type { AvailableSlotsType } from "@calcom/platform-libraries-0.0.19"; import { RemoveSelectedSlotInput, ReserveSlotInput } from "@calcom/platform-types"; import { ApiResponse, GetAvailableSlotsInput } from "@calcom/platform-types"; diff --git a/apps/api/v2/src/modules/slots/slots.repository.ts b/apps/api/v2/src/modules/slots/slots.repository.ts index 6f38214714..9b96fb303f 100644 --- a/apps/api/v2/src/modules/slots/slots.repository.ts +++ b/apps/api/v2/src/modules/slots/slots.repository.ts @@ -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.18"; +import { MINUTES_TO_BOOK } from "@calcom/platform-libraries-0.0.19"; import { ReserveSlotInput } from "@calcom/platform-types"; @Injectable() diff --git a/apps/api/v2/src/modules/timezones/controllers/timezones.controller.ts b/apps/api/v2/src/modules/timezones/controllers/timezones.controller.ts index 61dae93479..e3661f7605 100644 --- a/apps/api/v2/src/modules/timezones/controllers/timezones.controller.ts +++ b/apps/api/v2/src/modules/timezones/controllers/timezones.controller.ts @@ -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.18"; +import type { CityTimezones } from "@calcom/platform-libraries-0.0.19"; import { ApiResponse } from "@calcom/platform-types"; @Controller({ diff --git a/apps/api/v2/src/modules/timezones/services/timezones.service.ts b/apps/api/v2/src/modules/timezones/services/timezones.service.ts index 207b572ae7..9abd98c8a6 100644 --- a/apps/api/v2/src/modules/timezones/services/timezones.service.ts +++ b/apps/api/v2/src/modules/timezones/services/timezones.service.ts @@ -1,8 +1,8 @@ import { RedisService } from "@/modules/redis/redis.service"; import { Injectable } from "@nestjs/common"; -import { cityTimezonesHandler } from "@calcom/platform-libraries-0.0.18"; -import type { CityTimezones } from "@calcom/platform-libraries-0.0.18"; +import { cityTimezonesHandler } from "@calcom/platform-libraries-0.0.19"; +import type { CityTimezones } from "@calcom/platform-libraries-0.0.19"; @Injectable() export class TimezonesService { diff --git a/apps/api/v2/src/modules/users/users.repository.ts b/apps/api/v2/src/modules/users/users.repository.ts index 6983f064f1..a60c648de4 100644 --- a/apps/api/v2/src/modules/users/users.repository.ts +++ b/apps/api/v2/src/modules/users/users.repository.ts @@ -77,6 +77,19 @@ export class UsersRepository { }); } + async findByIdsWithEventTypes(userIds: number[]) { + return this.dbRead.prisma.user.findMany({ + where: { + id: { + in: userIds, + }, + }, + include: { + eventTypes: true, + }, + }); + } + async findByIdWithCalendars(userId: number) { return this.dbRead.prisma.user.findUnique({ where: { diff --git a/apps/api/v2/swagger/documentation.json b/apps/api/v2/swagger/documentation.json index 21810f9284..ad8e6453f6 100644 --- a/apps/api/v2/swagger/documentation.json +++ b/apps/api/v2/swagger/documentation.json @@ -1085,6 +1085,16 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateScheduleInput_2024_06_11" + } + } + } + }, "responses": { "201": { "description": "", @@ -1187,6 +1197,16 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateScheduleInput_2024_06_11" + } + } + } + }, "responses": { "200": { "description": "", @@ -1615,6 +1635,252 @@ ] } }, + "/v2/organizations/{orgId}/teams/{teamId}/event-types": { + "post": { + "operationId": "OrganizationsEventTypesController_createTeamEventType", + "parameters": [ + { + "name": "teamId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + }, + { + "name": "orgId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeamEventTypeInput_2024_06_14" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeamEventTypeOutput" + } + } + } + } + }, + "tags": [ + "Organizations Event Types" + ] + }, + "get": { + "operationId": "OrganizationsEventTypesController_getTeamEventTypes", + "parameters": [ + { + "name": "teamId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetTeamEventTypesOutput" + } + } + } + } + }, + "tags": [ + "Organizations Event Types" + ] + } + }, + "/v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}": { + "get": { + "operationId": "OrganizationsEventTypesController_getTeamEventType", + "parameters": [ + { + "name": "teamId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + }, + { + "name": "eventTypeId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetTeamEventTypeOutput" + } + } + } + } + }, + "tags": [ + "Organizations Event Types" + ] + }, + "patch": { + "operationId": "OrganizationsEventTypesController_updateTeamEventType", + "parameters": [ + { + "name": "teamId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + }, + { + "name": "eventTypeId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTeamEventTypeInput_2024_06_14" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTeamEventTypeOutput" + } + } + } + } + }, + "tags": [ + "Organizations Event Types" + ] + }, + "delete": { + "operationId": "OrganizationsEventTypesController_deleteTeamEventType", + "parameters": [ + { + "name": "teamId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + }, + { + "name": "eventTypeId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteTeamEventTypeOutput" + } + } + } + } + }, + "tags": [ + "Organizations Event Types" + ] + } + }, + "/v2/organizations/{orgId}/teams/event-types": { + "get": { + "operationId": "OrganizationsEventTypesController_getTeamsEventTypes", + "parameters": [ + { + "name": "orgId", + "required": true, + "in": "path", + "schema": { + "type": "number" + } + }, + { + "name": "take", + "required": false, + "in": "query", + "description": "The number of items to return", + "example": 10, + "schema": { + "type": "number" + } + }, + { + "name": "skip", + "required": false, + "in": "query", + "description": "The number of items to skip", + "example": 0, + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetTeamEventTypesOutput" + } + } + } + } + }, + "tags": [ + "Organizations Event Types" + ] + } + }, "/v2/organizations/{orgId}/teams/{teamId}/memberships": { "get": { "operationId": "OrganizationsTeamsMembershipsController_getAllOrgTeamMemberships", @@ -1980,6 +2246,16 @@ } } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateScheduleInput_2024_04_15" + } + } + } + }, "responses": { "200": { "description": "", @@ -4905,6 +5181,57 @@ "data" ] }, + "CreateScheduleInput_2024_06_11": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "One-on-one coaching" + }, + "timeZone": { + "type": "string", + "example": "Europe/Rome" + }, + "availability": { + "example": [ + { + "days": [ + "Monday", + "Tuesday" + ], + "startTime": "09:00", + "endTime": "10:00" + } + ], + "type": "array", + "items": { + "$ref": "#/components/schemas/ScheduleAvailabilityInput_2024_06_11" + } + }, + "isDefault": { + "type": "boolean", + "example": true + }, + "overrides": { + "example": [ + { + "date": "2024-05-20", + "startTime": "12:00", + "endTime": "14:00" + } + ], + "type": "array", + "items": { + "$ref": "#/components/schemas/ScheduleOverrideInput_2024_06_11" + } + } + }, + "required": [ + "name", + "timeZone", + "isDefault" + ] + }, "CreateScheduleOutput_2024_06_11": { "type": "object", "properties": { @@ -4953,6 +5280,52 @@ "data" ] }, + "UpdateScheduleInput_2024_06_11": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "One-on-one coaching" + }, + "timeZone": { + "type": "string", + "example": "Europe/Rome" + }, + "availability": { + "example": [ + { + "days": [ + "Monday", + "Tuesday" + ], + "startTime": "09:00", + "endTime": "10:00" + } + ], + "type": "array", + "items": { + "$ref": "#/components/schemas/ScheduleAvailabilityInput_2024_06_11" + } + }, + "isDefault": { + "type": "boolean", + "example": true + }, + "overrides": { + "example": [ + { + "date": "2024-05-20", + "startTime": "12:00", + "endTime": "14:00" + } + ], + "type": "array", + "items": { + "$ref": "#/components/schemas/ScheduleOverrideInput_2024_06_11" + } + } + } + }, "UpdateScheduleOutput_2024_06_11": { "type": "object", "properties": { @@ -5448,6 +5821,492 @@ "data" ] }, + "CreateTeamEventTypeInput_2024_06_14": { + "type": "object", + "properties": { + "lengthInMinutes": { + "type": "number", + "example": 60 + }, + "title": { + "type": "string", + "example": "Learn the secrets of masterchief!" + }, + "description": { + "type": "string", + "example": "Discover the culinary wonders of the Argentina by making the best flan ever!" + }, + "locations": { + "type": "array", + "items": { + "type": "string" + } + }, + "bookingFields": { + "type": "array", + "items": { + "type": "string" + } + }, + "disableGuests": { + "type": "boolean" + }, + "slotInterval": { + "type": "number" + }, + "minimumBookingNotice": { + "type": "number" + }, + "beforeEventBuffer": { + "type": "number" + }, + "afterEventBuffer": { + "type": "number" + }, + "schedulingType": { + "type": "object" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + }, + "assignAllTeamMembers": { + "type": "boolean" + } + }, + "required": [ + "lengthInMinutes", + "title", + "description", + "locations", + "bookingFields", + "disableGuests", + "slotInterval", + "minimumBookingNotice", + "beforeEventBuffer", + "afterEventBuffer", + "schedulingType", + "hosts", + "assignAllTeamMembers" + ] + }, + "CreateTeamEventTypeOutput": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "success", + "enum": [ + "success", + "error" + ] + }, + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/TeamEventTypeOutput_2024_06_14" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamEventTypeOutput_2024_06_14" + } + } + ] + } + }, + "required": [ + "status", + "data" + ] + }, + "RecurringEvent_2024_06_14": { + "type": "object", + "properties": { + "dtstart": { + "format": "date-time", + "type": "string" + }, + "interval": { + "type": "number" + }, + "count": { + "type": "number" + }, + "freq": { + "type": "number", + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ] + }, + "until": { + "format": "date-time", + "type": "string" + }, + "tzid": { + "type": "string" + } + }, + "required": [ + "interval", + "count", + "freq" + ] + }, + "Schedule_2024_06_14": { + "type": "object", + "properties": { + "id": { + "type": "number" + }, + "timeZone": { + "type": "string", + "nullable": true + } + }, + "required": [ + "id", + "timeZone" + ] + }, + "Host": { + "type": "object", + "properties": { + "userId": { + "type": "number" + }, + "mandatory": { + "type": "boolean", + "default": false + }, + "priority": { + "type": "object", + "default": "medium" + } + }, + "required": [ + "userId" + ] + }, + "TeamEventTypeOutput_2024_06_14": { + "type": "object", + "properties": { + "id": { + "type": "number", + "example": 1 + }, + "lengthInMinutes": { + "type": "number", + "minimum": 1 + }, + "title": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "description": { + "type": "string" + }, + "locations": { + "type": "array", + "items": { + "type": "object" + } + }, + "bookingFields": { + "type": "array", + "items": { + "type": "object" + } + }, + "disableGuests": { + "type": "boolean" + }, + "slotInterval": { + "type": "number", + "nullable": true + }, + "minimumBookingNotice": { + "type": "number", + "minimum": 0 + }, + "beforeEventBuffer": { + "type": "number" + }, + "afterEventBuffer": { + "type": "number" + }, + "schedulingType": { + "type": "object", + "nullable": true + }, + "recurringEvent": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/RecurringEvent_2024_06_14" + } + ] + }, + "metadata": { + "type": "object" + }, + "requiresConfirmation": { + "type": "boolean" + }, + "price": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "lockTimeZoneToggleOnBookingPage": { + "type": "boolean" + }, + "seatsPerTimeSlot": { + "type": "number", + "nullable": true + }, + "forwardParamsSuccessRedirect": { + "type": "boolean", + "nullable": true + }, + "successRedirectUrl": { + "type": "string", + "nullable": true + }, + "seatsShowAvailabilityCount": { + "type": "boolean", + "nullable": true + }, + "isInstantEvent": { + "type": "boolean" + }, + "schedule": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/Schedule_2024_06_14" + } + ] + }, + "teamId": { + "type": "number", + "nullable": true + }, + "ownerId": { + "type": "number", + "nullable": true + }, + "parentEventTypeId": { + "type": "number", + "nullable": true + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Host" + } + }, + "assignAllTeamMembers": { + "type": "boolean" + } + }, + "required": [ + "id", + "lengthInMinutes", + "title", + "slug", + "description", + "locations", + "bookingFields", + "disableGuests", + "schedulingType", + "recurringEvent", + "metadata", + "requiresConfirmation", + "price", + "currency", + "lockTimeZoneToggleOnBookingPage", + "seatsPerTimeSlot", + "forwardParamsSuccessRedirect", + "successRedirectUrl", + "seatsShowAvailabilityCount", + "isInstantEvent", + "schedule", + "hosts" + ] + }, + "GetTeamEventTypeOutput": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "success", + "enum": [ + "success", + "error" + ] + }, + "data": { + "$ref": "#/components/schemas/TeamEventTypeOutput_2024_06_14" + } + }, + "required": [ + "status", + "data" + ] + }, + "GetTeamEventTypesOutput": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "success", + "enum": [ + "success", + "error" + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamEventTypeOutput_2024_06_14" + } + } + }, + "required": [ + "status", + "data" + ] + }, + "UpdateTeamEventTypeInput_2024_06_14": { + "type": "object", + "properties": { + "lengthInMinutes": { + "type": "number" + }, + "title": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "description": { + "type": "string" + }, + "locations": { + "type": "array", + "items": { + "type": "string" + } + }, + "bookingFields": { + "type": "array", + "items": { + "type": "string" + } + }, + "disableGuests": { + "type": "boolean" + }, + "slotInterval": { + "type": "number" + }, + "minimumBookingNotice": { + "type": "number" + }, + "beforeEventBuffer": { + "type": "number" + }, + "afterEventBuffer": { + "type": "number" + }, + "hosts": { + "type": "array", + "items": { + "type": "string" + } + }, + "assignAllTeamMembers": { + "type": "boolean" + } + }, + "required": [ + "lengthInMinutes", + "title", + "slug", + "description", + "locations", + "bookingFields", + "disableGuests", + "slotInterval", + "minimumBookingNotice", + "beforeEventBuffer", + "afterEventBuffer", + "hosts", + "assignAllTeamMembers" + ] + }, + "UpdateTeamEventTypeOutput": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "success", + "enum": [ + "success", + "error" + ] + }, + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/TeamEventTypeOutput_2024_06_14" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamEventTypeOutput_2024_06_14" + } + } + ] + } + }, + "required": [ + "status", + "data" + ] + }, + "DeleteTeamEventTypeOutput": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "success", + "enum": [ + "success", + "error" + ] + }, + "data": { + "type": "object" + } + }, + "required": [ + "status", + "data" + ] + }, "OrgTeamMembershipOutputDto": { "type": "object", "properties": { @@ -5577,6 +6436,26 @@ "userId" ] }, + "GetDefaultScheduleOutput_2024_06_11": { + "type": "object", + "properties": { + "status": { + "type": "string", + "example": "success", + "enum": [ + "success", + "error" + ] + }, + "data": { + "$ref": "#/components/schemas/ScheduleOutput_2024_06_11" + } + }, + "required": [ + "status", + "data" + ] + }, "CreateAvailabilityInput_2024_04_15": { "type": "object", "properties": { @@ -5874,6 +6753,66 @@ "data" ] }, + "UpdateScheduleInput_2024_04_15": { + "type": "object", + "properties": { + "timeZone": { + "type": "string" + }, + "name": { + "type": "string" + }, + "isDefault": { + "type": "boolean" + }, + "schedule": { + "example": [ + [], + [ + { + "start": "2022-01-01T00:00:00.000Z", + "end": "2022-01-02T00:00:00.000Z" + } + ], + [], + [], + [], + [], + [] + ], + "items": { + "type": "array" + }, + "type": "array" + }, + "dateOverrides": { + "example": [ + [], + [ + { + "start": "2022-01-01T00:00:00.000Z", + "end": "2022-01-02T00:00:00.000Z" + } + ], + [], + [], + [], + [], + [] + ], + "items": { + "type": "array" + }, + "type": "array" + } + }, + "required": [ + "timeZone", + "name", + "isDefault", + "schedule" + ] + }, "EventTypeModel_2024_04_15": { "type": "object", "properties": { diff --git a/apps/api/v2/test/fixtures/repository/event-types.repository.fixture.ts b/apps/api/v2/test/fixtures/repository/event-types.repository.fixture.ts index 4d0d15fd18..d802800a64 100644 --- a/apps/api/v2/test/fixtures/repository/event-types.repository.fixture.ts +++ b/apps/api/v2/test/fixtures/repository/event-types.repository.fixture.ts @@ -21,6 +21,14 @@ export class EventTypesRepositoryFixture { }); } + async getAllTeamEventTypes(teamId: number) { + return this.prismaWriteClient.eventType.findMany({ + where: { + teamId, + }, + }); + } + async create( data: Pick, userId: number diff --git a/apps/api/v2/test/mocks/api-auth-mock.strategy.ts b/apps/api/v2/test/mocks/api-auth-mock.strategy.ts index 76bb3a0e62..9a7e760740 100644 --- a/apps/api/v2/test/mocks/api-auth-mock.strategy.ts +++ b/apps/api/v2/test/mocks/api-auth-mock.strategy.ts @@ -11,7 +11,7 @@ export class ApiAuthMockStrategy extends PassportStrategy(BaseStrategy, "api-aut async authenticate() { try { - const user = await this.usersRepository.findByEmail(this.email); + const user = await this.usersRepository.findByEmailWithProfile(this.email); if (!user) { throw new Error("User with the provided ID not found"); } diff --git a/packages/platform/types/api.ts b/packages/platform/types/api.ts index f18909605c..c870936b0b 100644 --- a/packages/platform/types/api.ts +++ b/packages/platform/types/api.ts @@ -1,14 +1,11 @@ import { ApiProperty } from "@nestjs/swagger"; import { Transform } from "class-transformer"; import { IsNumber, Min, Max, IsOptional } from "class-validator"; +import { IsEnum } from "class-validator"; import type { Response as BaseResponse } from "express"; -import type { - ERROR_STATUS, - SUCCESS_STATUS, - API_ERROR_CODES, - REDIRECT_STATUS, -} from "@calcom/platform-constants"; +import { ERROR_STATUS, SUCCESS_STATUS } from "@calcom/platform-constants"; +import type { API_ERROR_CODES, REDIRECT_STATUS } from "@calcom/platform-constants"; export type ApiSuccessResponse = { status: typeof SUCCESS_STATUS; data: T }; export type ApiSuccessResponseWithoutData = { status: typeof SUCCESS_STATUS }; @@ -75,3 +72,9 @@ export class SkipTakePagination { @IsOptional() skip?: number; } + +export class ApiResponseWithoutData { + @ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] }) + @IsEnum([SUCCESS_STATUS, ERROR_STATUS]) + status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS; +} diff --git a/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts b/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts index f456d9fb49..c7ff77802a 100644 --- a/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts +++ b/packages/platform/types/event-types/event-types_2024_06_14/inputs/create-event-type.input.ts @@ -1,8 +1,19 @@ import { ApiProperty as DocsProperty } from "@nestjs/swagger"; -import { IsString, IsInt, IsBoolean, IsOptional, Min } from "class-validator"; +import { Type } from "class-transformer"; +import { + IsString, + IsInt, + IsBoolean, + IsOptional, + Min, + IsEnum, + IsArray, + ValidateNested, +} from "class-validator"; import type { BookingField_2024_06_14 } from "./booking-fields.input"; import { ValidateBookingFields_2024_06_14 } from "./booking-fields.input"; +import { SchedulingType } from "./enums/scheduling-type"; import { ValidateLocations_2024_06_14 } from "./locations.input"; import type { Location_2024_06_14 } from "./locations.input"; @@ -10,6 +21,7 @@ export const CREATE_EVENT_LENGTH_EXAMPLE = 60; export const CREATE_EVENT_TITLE_EXAMPLE = "Learn the secrets of masterchief!"; export const CREATE_EVENT_DESCRIPTION_EXAMPLE = "Discover the culinary wonders of the Argentina by making the best flan ever!"; + export class CreateEventTypeInput_2024_06_14 { @IsInt() @Min(1) @@ -57,3 +69,93 @@ export class CreateEventTypeInput_2024_06_14 { @IsOptional() afterEventBuffer?: number; } + +export enum HostPriority { + lowest = "lowest", + low = "low", + medium = "medium", + high = "high", + highest = "highest", +} +export class Host { + @IsInt() + userId!: number; + + @IsOptional() + @IsBoolean() + mandatory?: boolean = false; + + @IsEnum(HostPriority) + @IsOptional() + priority?: keyof typeof HostPriority = "medium"; +} + +export class CreateTeamEventTypeInput_2024_06_14 { + @IsInt() + @Min(1) + @DocsProperty({ example: CREATE_EVENT_LENGTH_EXAMPLE }) + lengthInMinutes!: number; + + @IsString() + @DocsProperty({ example: CREATE_EVENT_TITLE_EXAMPLE }) + title!: string; + + @IsString() + slug!: string; + + @IsOptional() + @IsString() + @DocsProperty({ example: CREATE_EVENT_DESCRIPTION_EXAMPLE }) + description?: string; + + @IsOptional() + @ValidateLocations_2024_06_14() + @DocsProperty() + locations?: Location_2024_06_14[]; + + @IsOptional() + @ValidateBookingFields_2024_06_14() + @DocsProperty() + bookingFields?: BookingField_2024_06_14[]; + + @IsBoolean() + @IsOptional() + @DocsProperty() + disableGuests?: boolean; + + @IsInt() + @IsOptional() + @DocsProperty() + slotInterval?: number; + + @IsInt() + @Min(0) + @IsOptional() + @DocsProperty() + minimumBookingNotice?: number; + + @IsInt() + @IsOptional() + @DocsProperty() + beforeEventBuffer?: number; + + @IsInt() + @IsOptional() + @DocsProperty() + afterEventBuffer?: number; + + @IsEnum(SchedulingType) + @DocsProperty() + schedulingType!: keyof typeof SchedulingType; + + @ValidateNested({ each: true }) + @Type(() => Host) + @IsArray() + @DocsProperty() + hosts!: Host[]; + + @IsBoolean() + @IsOptional() + @DocsProperty() + assignAllTeamMembers?: boolean; +} diff --git a/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts b/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts index 2aeee77184..01aea1b9b6 100644 --- a/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts +++ b/packages/platform/types/event-types/event-types_2024_06_14/inputs/update-event-type.input.ts @@ -1,7 +1,10 @@ -import { IsString, IsInt, IsBoolean, IsOptional, Min } from "class-validator"; +import { ApiProperty as DocsProperty } from "@nestjs/swagger"; +import { Type } from "class-transformer"; +import { IsString, IsInt, IsBoolean, IsOptional, Min, ValidateNested, IsArray } from "class-validator"; import type { BookingField_2024_06_14 } from "./booking-fields.input"; import { ValidateBookingFields_2024_06_14 } from "./booking-fields.input"; +import { Host } from "./create-event-type.input"; import { ValidateLocations_2024_06_14 } from "./locations.input"; import type { Location_2024_06_14 } from "./locations.input"; @@ -15,6 +18,10 @@ export class UpdateEventTypeInput_2024_06_14 { @IsString() title?: string; + @IsString() + @IsOptional() + slug?: string; + @IsOptional() @IsString() description?: string; @@ -48,3 +55,73 @@ export class UpdateEventTypeInput_2024_06_14 { @IsOptional() afterEventBuffer?: number; } +export class UpdateTeamEventTypeInput_2024_06_14 { + @IsOptional() + @IsInt() + @Min(1) + @DocsProperty() + lengthInMinutes?: number; + + @IsOptional() + @IsString() + @DocsProperty() + title?: string; + + @IsString() + @IsOptional() + @DocsProperty() + slug?: string; + + @IsOptional() + @IsString() + @DocsProperty() + description?: string; + + @IsOptional() + @ValidateLocations_2024_06_14() + @DocsProperty() + locations?: Location_2024_06_14[]; + + @IsOptional() + @ValidateBookingFields_2024_06_14() + @DocsProperty() + bookingFields?: BookingField_2024_06_14[]; + + @IsBoolean() + @IsOptional() + @DocsProperty() + disableGuests?: boolean; + + @IsInt() + @IsOptional() + @DocsProperty() + slotInterval?: number; + + @IsInt() + @Min(0) + @IsOptional() + @DocsProperty() + minimumBookingNotice?: number; + + @IsInt() + @IsOptional() + @DocsProperty() + beforeEventBuffer?: number; + + @IsInt() + @IsOptional() + @DocsProperty() + afterEventBuffer?: number; + + @ValidateNested({ each: true }) + @Type(() => Host) + @IsArray() + @IsOptional() + @DocsProperty() + hosts?: Host[]; + + @IsBoolean() + @IsOptional() + @DocsProperty() + assignAllTeamMembers?: boolean; +} diff --git a/packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts b/packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts index abf460c388..ff1161c500 100644 --- a/packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts +++ b/packages/platform/types/event-types/event-types_2024_06_14/outputs/event-type.output.ts @@ -1,8 +1,18 @@ import { ApiProperty as DocsProperty } from "@nestjs/swagger"; import { Type } from "class-transformer"; -import { IsBoolean, IsEnum, IsInt, IsOptional, IsString, Min } from "class-validator"; +import { + IsArray, + IsBoolean, + IsEnum, + IsInt, + IsOptional, + IsString, + Min, + ValidateNested, +} from "class-validator"; import type { Location_2024_06_14, BookingField_2024_06_14 } from "../inputs"; +import { Host } from "../inputs"; import { RecurringEvent_2024_06_14 } from "../inputs"; import { ValidateBookingFields_2024_06_14 } from "../inputs/booking-fields.input"; import { ValidateLocations_2024_06_14 } from "../inputs/locations.input"; @@ -135,3 +145,107 @@ export class EventTypeOutput_2024_06_14 { schedule!: Schedule_2024_06_14 | null; } + +export class TeamEventTypeOutput_2024_06_14 { + @IsInt() + @DocsProperty({ example: 1 }) + id!: number; + + @IsInt() + @Min(1) + lengthInMinutes!: number; + + @IsString() + title!: string; + + @IsString() + slug!: string; + + @IsString() + description!: string; + + @ValidateLocations_2024_06_14() + locations!: Location_2024_06_14[]; + + @ValidateBookingFields_2024_06_14() + bookingFields!: BookingField_2024_06_14[]; + + @IsBoolean() + disableGuests!: boolean; + + @IsInt() + @IsOptional() + slotInterval?: number | null; + + @IsInt() + @Min(0) + @IsOptional() + minimumBookingNotice?: number; + + @IsInt() + @IsOptional() + beforeEventBuffer?: number; + + @IsInt() + @IsOptional() + afterEventBuffer?: number; + + @IsEnum(SchedulingTypeEnum) + schedulingType!: SchedulingType | null; + + @Type(() => RecurringEvent_2024_06_14) + recurringEvent!: RecurringEvent_2024_06_14 | null; + + @Type(() => Object) + metadata!: Record; + + @IsBoolean() + requiresConfirmation!: boolean; + + @IsInt() + price!: number; + + @IsString() + currency!: string; + + @IsBoolean() + lockTimeZoneToggleOnBookingPage!: boolean; + + @IsInt() + seatsPerTimeSlot!: number | null; + + @IsBoolean() + forwardParamsSuccessRedirect!: boolean | null; + + @IsString() + successRedirectUrl!: string | null; + + @IsBoolean() + seatsShowAvailabilityCount!: boolean | null; + + @IsBoolean() + isInstantEvent!: boolean; + + schedule!: Schedule_2024_06_14 | null; + + @IsInt() + @IsOptional() + teamId?: number | null; + + @IsInt() + @IsOptional() + ownerId?: number | null; + + @IsInt() + @IsOptional() + parentEventTypeId?: number | null; + + @ValidateNested({ each: true }) + @Type(() => Host) + @IsArray() + hosts!: Host[]; + + @IsBoolean() + @IsOptional() + assignAllTeamMembers?: boolean; +} diff --git a/yarn.lock b/yarn.lock index 7d6cb516e0..f56363874d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4065,9 +4065,8 @@ __metadata: resolution: "@calcom/api-v2@workspace:apps/api/v2" dependencies: "@calcom/platform-constants": "*" - "@calcom/platform-libraries-0.0.13": "npm:@calcom/platform-libraries@0.0.13" + "@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.4": "npm:@calcom/platform-libraries@0.0.4" "@calcom/platform-types": "*" "@calcom/platform-utils": "*" "@calcom/prisma": "*" @@ -4217,7 +4216,7 @@ __metadata: languageName: unknown linkType: soft -"@calcom/atoms@*, @calcom/atoms@workspace:^, @calcom/atoms@workspace:packages/platform/atoms": +"@calcom/atoms@*, @calcom/atoms@workspace:packages/platform/atoms": version: 0.0.0-use.local resolution: "@calcom/atoms@workspace:packages/platform/atoms" dependencies: @@ -4335,6 +4334,15 @@ __metadata: languageName: unknown linkType: soft +"@calcom/campsite@workspace:packages/app-store/campsite": + version: 0.0.0-use.local + resolution: "@calcom/campsite@workspace:packages/app-store/campsite" + dependencies: + "@calcom/lib": "*" + "@calcom/types": "*" + languageName: unknown + linkType: soft + "@calcom/clic@workspace:packages/app-store/clic": version: 0.0.0-use.local resolution: "@calcom/clic@workspace:packages/app-store/clic" @@ -4869,8 +4877,8 @@ __metadata: "@calcom/tsconfig": "*" "@calcom/types": "*" "@faker-js/faker": ^7.3.0 - "@formbricks/api": "^1.7.0" - "@formbricks/js": "^2.1.0" + "@formbricks/api": ^1.7.0 + "@formbricks/js": ^2.1.0 "@sendgrid/client": ^7.7.0 "@vercel/og": ^0.5.0 bcryptjs: ^2.4.3 @@ -5017,14 +5025,14 @@ __metadata: languageName: unknown linkType: soft -"@calcom/platform-libraries-0.0.13@npm:@calcom/platform-libraries@0.0.13": - version: 0.0.13 - resolution: "@calcom/platform-libraries@npm:0.0.13" +"@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" dependencies: "@calcom/core": "*" "@calcom/features": "*" "@calcom/lib": "*" - checksum: 53b92db84c669c2ff179acc4056ebc3c7426779aa0b9b7578f1bdd1abab5426bb45b9cb0b4858f0f8c8760c352e0a6f96e2062428a9e9cf0c695601d0f210349 + checksum: e5c4f2ca63c927e811232d3c83b5341e306d33f3fd0bfdeaf6dcdbca7f31ae02892bd4f8244273cd411fc0b725d2ff7690b58498ae29f6556c22d19159943b08 languageName: node linkType: hard @@ -5039,17 +5047,6 @@ __metadata: languageName: node linkType: hard -"@calcom/platform-libraries-0.0.4@npm:@calcom/platform-libraries@0.0.4": - version: 0.0.4 - resolution: "@calcom/platform-libraries@npm:0.0.4" - dependencies: - "@calcom/core": "*" - "@calcom/features": "*" - "@calcom/lib": "*" - checksum: 3e8cba76f767398f9ffb95575913514925b7a51a15791741a521284eabdaba5d52f85fbcd9f032b3f2f3a6130520e67049cd8ba6f96ae4f87597de5019710c7f - languageName: node - linkType: hard - "@calcom/platform-libraries@workspace:packages/platform/libraries": version: 0.0.0-use.local resolution: "@calcom/platform-libraries@workspace:packages/platform/libraries" @@ -5667,7 +5664,6 @@ __metadata: dependencies: "@algora/sdk": ^0.1.2 "@calcom/app-store": "*" - "@calcom/atoms": "workspace:^" "@calcom/config": "*" "@calcom/dayjs": "*" "@calcom/embed-react": "workspace:^" @@ -5713,7 +5709,6 @@ __metadata: "@vercel/og": ^0.5.0 autoprefixer: ^10.4.12 bcryptjs: ^2.4.3 - class-variance-authority: ^0.7.0 clsx: ^1.2.1 cobe: ^0.4.1 concurrently: ^7.6.0 @@ -5726,7 +5721,6 @@ __metadata: env-cmd: ^10.1.0 eslint: ^8.34.0 fathom-client: ^3.5.0 - framer-motion: ^11.0.25 globby: ^13.1.3 graphql: ^16.8.0 graphql-codegen: ^0.4.0 @@ -5736,7 +5730,7 @@ __metadata: i18n-unused: ^0.13.0 iframe-resizer-react: ^1.1.0 keen-slider: ^6.8.0 - lucide-react: ^0.364.0 + lucide-react: ^0.171.0 micro: ^10.0.1 next: ^14.1.3 next-auth: ^4.22.1 @@ -5748,7 +5742,7 @@ __metadata: prism-react-renderer: ^1.3.5 react: ^18.2.0 react-confetti: ^6.0.1 - react-datocms: ^5.0.3 + react-datocms: ^3.1.0 react-device-detect: ^2.2.2 react-dom: ^18.2.0 react-fast-marquee: ^1.6.4 @@ -5758,10 +5752,8 @@ __metadata: react-live-chat-loader: ^2.8.1 react-markdown: ^9.0.1 react-merge-refs: 1.1.0 - react-parallax-tilt: ^1.7.226 react-resize-detector: ^9.1.0 react-twemoji: ^0.3.0 - react-twitter-embed: ^4.0.4 react-use-measure: ^2.1.1 react-wrap-balancer: ^1.0.0 remark: ^14.0.2 @@ -8722,16 +8714,18 @@ __metadata: languageName: node linkType: hard -"@langchain/community@npm:~0.0.20": - version: 0.0.26 - resolution: "@langchain/community@npm:0.0.26" +"@langchain/community@npm:~0.0.47": + version: 0.0.57 + resolution: "@langchain/community@npm:0.0.57" dependencies: - "@langchain/core": ~0.1.16 - "@langchain/openai": ~0.0.10 + "@langchain/core": ~0.1.60 + "@langchain/openai": ~0.0.28 + expr-eval: ^2.0.2 flat: ^5.0.2 - langsmith: ~0.0.48 + langsmith: ~0.1.1 uuid: ^9.0.0 zod: ^3.22.3 + zod-to-json-schema: ^3.22.5 peerDependencies: "@aws-crypto/sha256-js": ^5.0.0 "@aws-sdk/client-bedrock-agent-runtime": ^3.485.0 @@ -8745,7 +8739,7 @@ __metadata: "@azure/search-documents": ^12.0.0 "@clickhouse/client": ^0.2.5 "@cloudflare/ai": "*" - "@datastax/astra-db-ts": ^0.1.4 + "@datastax/astra-db-ts": ^1.0.0 "@elastic/elasticsearch": ^8.4.0 "@getmetal/metal-sdk": "*" "@getzep/zep-js": ^0.9.0 @@ -8754,11 +8748,14 @@ __metadata: "@google-ai/generativelanguage": ^0.2.1 "@gradientai/nodejs-sdk": ^1.2.0 "@huggingface/inference": ^2.6.4 + "@mlc-ai/web-llm": ^0.2.35 "@mozilla/readability": "*" + "@neondatabase/serverless": "*" "@opensearch-project/opensearch": "*" "@pinecone-database/pinecone": "*" "@planetscale/database": ^1.8.0 - "@qdrant/js-client-rest": ^1.2.0 + "@premai/prem-sdk": ^0.3.25 + "@qdrant/js-client-rest": ^1.8.2 "@raycast/api": ^1.55.2 "@rockset/client": ^0.9.1 "@smithy/eventstream-codec": ^2.0.5 @@ -8771,32 +8768,41 @@ __metadata: "@tensorflow/tfjs-converter": "*" "@tensorflow/tfjs-core": "*" "@upstash/redis": ^1.20.6 + "@upstash/vector": ^1.0.7 "@vercel/kv": ^0.2.3 "@vercel/postgres": ^0.5.0 "@writerai/writer-sdk": ^0.40.2 "@xata.io/client": ^0.28.0 "@xenova/transformers": ^2.5.4 "@zilliz/milvus2-sdk-node": ">=2.2.7" + better-sqlite3: ^9.4.0 cassandra-driver: ^4.7.2 + cborg: ^4.1.1 chromadb: "*" - closevector-common: 0.1.0-alpha.1 - closevector-node: 0.1.0-alpha.10 - closevector-web: 0.1.0-alpha.16 + closevector-common: 0.1.3 + closevector-node: 0.1.6 + closevector-web: 0.1.6 cohere-ai: "*" convex: ^1.3.1 + couchbase: ^4.3.0 discord.js: ^14.14.1 + dria: ^0.0.3 + duck-duck-scrape: ^2.2.5 faiss-node: ^0.5.1 - firebase-admin: ^11.9.0 + firebase-admin: ^11.9.0 || ^12.0.0 google-auth-library: ^8.9.0 googleapis: ^126.0.1 - hnswlib-node: ^1.4.2 + hnswlib-node: ^3.0.0 html-to-text: ^9.0.5 + interface-datastore: ^8.2.11 ioredis: ^5.3.2 + it-all: ^3.0.4 jsdom: "*" + jsonwebtoken: ^9.0.2 llmonitor: ^0.5.9 lodash: ^4.17.21 lunary: ^0.6.11 - mongodb: ^5.2.0 + mongodb: ">=5.2.0" mysql2: ^3.3.3 neo4j-driver: "*" node-llama-cpp: "*" @@ -8804,14 +8810,14 @@ __metadata: pg-copy-streams: ^6.0.5 pickleparser: ^0.2.1 portkey-ai: ^0.1.11 - redis: ^4.6.4 + redis: "*" replicate: ^0.18.0 typeorm: ^0.3.12 typesense: ^1.5.3 usearch: ^1.1.1 vectordb: ^0.1.4 voy-search: 0.6.2 - weaviate-ts-client: ^1.4.0 + weaviate-ts-client: "*" web-auth-library: ^1.0.3 ws: ^8.14.2 peerDependenciesMeta: @@ -8857,14 +8863,20 @@ __metadata: optional: true "@huggingface/inference": optional: true + "@mlc-ai/web-llm": + optional: true "@mozilla/readability": optional: true + "@neondatabase/serverless": + optional: true "@opensearch-project/opensearch": optional: true "@pinecone-database/pinecone": optional: true "@planetscale/database": optional: true + "@premai/prem-sdk": + optional: true "@qdrant/js-client-rest": optional: true "@raycast/api": @@ -8891,6 +8903,8 @@ __metadata: optional: true "@upstash/redis": optional: true + "@upstash/vector": + optional: true "@vercel/kv": optional: true "@vercel/postgres": @@ -8903,8 +8917,12 @@ __metadata: optional: true "@zilliz/milvus2-sdk-node": optional: true + better-sqlite3: + optional: true cassandra-driver: optional: true + cborg: + optional: true chromadb: optional: true closevector-common: @@ -8917,8 +8935,14 @@ __metadata: optional: true convex: optional: true + couchbase: + optional: true discord.js: optional: true + dria: + optional: true + duck-duck-scrape: + optional: true faiss-node: optional: true firebase-admin: @@ -8931,10 +8955,16 @@ __metadata: optional: true html-to-text: optional: true + interface-datastore: + optional: true ioredis: optional: true + it-all: + optional: true jsdom: optional: true + jsonwebtoken: + optional: true llmonitor: optional: true lodash: @@ -8977,30 +9007,51 @@ __metadata: optional: true ws: optional: true - checksum: 6d45127dcab33813d8423447749a1067be47b23efab0c1e69bb3d9344ecdd51308dc81d5b02a22084b26b6c8840fa80929db192a2b348fee26e34101bb86440e + checksum: 9a9f8396af0571bad920c0871329953f74a2907c5cdbab544f94269db2eff3de475c07e25c69dcf1e3b014f21ab9fc9f3cf79717ed44a7878bf780e58f11da87 languageName: node linkType: hard -"@langchain/core@npm:^0.1.26, @langchain/core@npm:~0.1.13, @langchain/core@npm:~0.1.16, @langchain/core@npm:~0.1.25": - version: 0.1.26 - resolution: "@langchain/core@npm:0.1.26" +"@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" dependencies: ansi-styles: ^5.0.0 camelcase: 6 decamelize: 1.2.0 - js-tiktoken: ^1.0.8 - langsmith: ~0.0.48 + js-tiktoken: ^1.0.12 + langsmith: ~0.1.30 ml-distance: ^4.0.0 + mustache: ^4.2.0 + p-queue: ^6.6.2 + p-retry: 4 + uuid: ^10.0.0 + zod: ^3.22.4 + zod-to-json-schema: ^3.22.3 + checksum: 76d77a71b7f97ee5383a2d93b9b528349452105a35b0bec181bb5e318a27f95cc75a605975aa604ad176d490fb71d214d43f4ac9be69fbd8312fe6c8e417397a + languageName: node + linkType: hard + +"@langchain/core@npm:^0.1.26, @langchain/core@npm:~0.1.13, @langchain/core@npm:~0.1.60": + version: 0.1.63 + resolution: "@langchain/core@npm:0.1.63" + dependencies: + ansi-styles: ^5.0.0 + camelcase: 6 + decamelize: 1.2.0 + js-tiktoken: ^1.0.12 + langsmith: ~0.1.7 + ml-distance: ^4.0.0 + mustache: ^4.2.0 p-queue: ^6.6.2 p-retry: 4 uuid: ^9.0.0 zod: ^3.22.4 zod-to-json-schema: ^3.22.3 - checksum: 565c3d809fc857c277d5f87b500d618e5180322767b90eae130a15dbfdff6e65b5b2c1e6fce39248b8c2f90f29571953627531e6f93e6f6a85a4fcbe69a156ce + checksum: 0aa18f55e5e5cab2c609a6c0d37bcfe9a36b574658acaeb7857f6a0e23dd9ad5617d40988a48f6f00c461a33a5abee983d2ed8b311b92c60b641002b42f0ab26 languageName: node linkType: hard -"@langchain/openai@npm:^0.0.14, @langchain/openai@npm:~0.0.10, @langchain/openai@npm:~0.0.12": +"@langchain/openai@npm:^0.0.14": version: 0.0.14 resolution: "@langchain/openai@npm:0.0.14" dependencies: @@ -9013,6 +9064,29 @@ __metadata: languageName: node linkType: hard +"@langchain/openai@npm:~0.0.28": + version: 0.0.34 + resolution: "@langchain/openai@npm:0.0.34" + dependencies: + "@langchain/core": ">0.1.56 <0.3.0" + js-tiktoken: ^1.0.12 + openai: ^4.41.1 + zod: ^3.22.4 + zod-to-json-schema: ^3.22.3 + checksum: d2a5568b7fd0507af2510d68cf568945d5c7f6e45f57ac1178f65d0092e0437e7c908e2af3e20b829ce4507f63e71ddc38df7dc35b7e3d21394daa380243e297 + languageName: node + linkType: hard + +"@langchain/textsplitters@npm:~0.0.0": + version: 0.0.3 + resolution: "@langchain/textsplitters@npm:0.0.3" + dependencies: + "@langchain/core": ">0.2.0 <0.3.0" + js-tiktoken: ^1.0.12 + checksum: f0b32d65c863a280ce7104bff4d367734b8f76f2ec42b741fb690fbc20737bb4a3a412b82d8ba308a524441b6084ecd59cf61c3ce13cbb9639fbd02241c341d1 + languageName: node + linkType: hard + "@lexical/clipboard@npm:0.9.1": version: 0.9.1 resolution: "@lexical/clipboard@npm:0.9.1" @@ -9433,59 +9507,6 @@ __metadata: languageName: node linkType: hard -"@mux/mux-player-react@npm:*": - version: 2.7.0 - resolution: "@mux/mux-player-react@npm:2.7.0" - dependencies: - "@mux/mux-player": 2.7.0 - "@mux/playback-core": 0.24.0 - prop-types: ^15.7.2 - peerDependencies: - "@types/react": ^17.0.0 || ^18 - react: ^17.0.2 || ^18 - react-dom: ^17.0.2 || ^18 - peerDependenciesMeta: - "@types/react": - optional: true - "@types/react-dom": - optional: true - checksum: 15ea8a8b9b2c82252e0647c22f8a1fbe7a04efaf1eb7aa61d10e4665b3dad45057c97c47cd04b8da42d02aad8288555feb9de98a8b9059b730420a8d12cada73 - languageName: node - linkType: hard - -"@mux/mux-player@npm:2.7.0": - version: 2.7.0 - resolution: "@mux/mux-player@npm:2.7.0" - dependencies: - "@mux/mux-video": 0.19.0 - "@mux/playback-core": 0.24.0 - media-chrome: ~3.2.1 - checksum: d3254c5d82f42d26e4ec3c27e50b6438a7dc74863381ddd9003bdc92947f6db4fc45b8caee21de9125aa80e71536268426d7159617dbace739de99f8f0ed259f - languageName: node - linkType: hard - -"@mux/mux-video@npm:0.19.0": - version: 0.19.0 - resolution: "@mux/mux-video@npm:0.19.0" - dependencies: - "@mux/playback-core": 0.24.0 - castable-video: ~1.0.6 - custom-media-element: ~1.2.3 - media-tracks: ~0.3.0 - checksum: 342d6f29fc60a9ea9694a8d794f679306e194f5de5d5cf85ed67391dce8d70330c9d78ee2681aee0e332ab1d2583a8a0174addf1182d0cf1c08fb85a01da849d - languageName: node - linkType: hard - -"@mux/playback-core@npm:0.24.0": - version: 0.24.0 - resolution: "@mux/playback-core@npm:0.24.0" - dependencies: - hls.js: ~1.5.8 - mux-embed: ~5.2.0 - checksum: b9783c05b1c009fb296a84de61d7b693fd81996bd35ef26aca7342a09eee476e4d8840fde1ef89273b01db2d4f3b57692101ae7bcc4cb5b15d4d6786bd0ba961 - languageName: node - linkType: hard - "@ndelangen/get-tarball@npm:^3.0.7": version: 3.0.9 resolution: "@ndelangen/get-tarball@npm:3.0.9" @@ -17293,12 +17314,12 @@ __metadata: linkType: hard "@types/mailparser@npm:^3.4.0": - version: 3.4.0 - resolution: "@types/mailparser@npm:3.4.0" + version: 3.4.4 + resolution: "@types/mailparser@npm:3.4.4" dependencies: "@types/node": "*" iconv-lite: ^0.6.3 - checksum: 05232ba3579b09224e5335848da27817a4cac8cc0eb622202904b62851fd61bbab7b5ca90016531e40098641351d84c2355f10cd9c9fa718da4ea2cb0e637bd0 + checksum: c8bdb579d66756042b75c3763dd8b7b2fab6657d7e7d33504bb65bbbe6fa220b8da2ae67918dd821716c3229d8803bedffb00f2314a8946da1856396187c646a languageName: node linkType: hard @@ -20575,13 +20596,20 @@ __metadata: languageName: node linkType: hard -"binary-extensions@npm:^2.0.0, binary-extensions@npm:^2.2.0": +"binary-extensions@npm:^2.0.0": version: 2.2.0 resolution: "binary-extensions@npm:2.2.0" checksum: ccd267956c58d2315f5d3ea6757cf09863c5fc703e50fbeb13a7dc849b812ef76e3cf9ca8f35a0c48498776a7478d7b4a0418e1e2b8cb9cb9731f2922aaad7f8 languageName: node linkType: hard +"binary-extensions@npm:^2.2.0": + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: bcad01494e8a9283abf18c1b967af65ee79b0c6a9e6fcfafebfe91dbe6e0fc7272bafb73389e198b310516ae04f7ad17d79aacf6cb4c0d5d5202a7e2e52c7d98 + languageName: node + linkType: hard + "binary-search@npm:^1.3.5": version: 1.3.6 resolution: "binary-search@npm:1.3.6" @@ -21474,15 +21502,6 @@ __metadata: languageName: node linkType: hard -"castable-video@npm:~1.0.6": - version: 1.0.10 - resolution: "castable-video@npm:1.0.10" - dependencies: - custom-media-element: ~1.3.2 - checksum: 5b7a27aacf305f40c6867e96e773f4290260f6eb8b01fe1f209506f8f6dec4cd099f3e35ee57de098829e4bcc688ccdc2cbb2fc86c509712dd573eadf66d42cc - languageName: node - linkType: hard - "ccount@npm:^2.0.0": version: 2.0.1 resolution: "ccount@npm:2.0.1" @@ -21947,15 +21966,6 @@ __metadata: languageName: node linkType: hard -"class-variance-authority@npm:^0.7.0": - version: 0.7.0 - resolution: "class-variance-authority@npm:0.7.0" - dependencies: - clsx: 2.0.0 - checksum: e7fd1fab433ef06f52a1b7b241b70b4a185864deef199d3b0a2c3412f1cc179517288264c383f3b971a00d76811625fc8f7ffe709e6170219e88cd7368f08a20 - languageName: node - linkType: hard - "classnames@npm:^2.2.5, classnames@npm:^2.2.6": version: 2.3.2 resolution: "classnames@npm:2.3.2" @@ -22228,13 +22238,6 @@ __metadata: languageName: node linkType: hard -"clsx@npm:2.0.0": - version: 2.0.0 - resolution: "clsx@npm:2.0.0" - checksum: a2cfb2351b254611acf92faa0daf15220f4cd648bdf96ce369d729813b85336993871a4bf6978ddea2b81b5a130478339c20d9d0b5c6fc287e5147f0c059276e - languageName: node - linkType: hard - "clsx@npm:^1.1.1": version: 1.1.1 resolution: "clsx@npm:1.1.1" @@ -23540,20 +23543,6 @@ __metadata: languageName: node linkType: hard -"custom-media-element@npm:~1.2.3": - version: 1.2.3 - resolution: "custom-media-element@npm:1.2.3" - checksum: da43680c35c870cd80ea02b9fce3efe25e9502c7088de5ab0e47ef2734aa9ce7e147c95f78a10abd4c13c47a81eae4712a7651ad18f87e023bc371082ba09842 - languageName: node - linkType: hard - -"custom-media-element@npm:~1.3.2": - version: 1.3.2 - resolution: "custom-media-element@npm:1.3.2" - checksum: 9ec2ff88c3c5ba7d20b9484c0359b4cfe08ad6804f3116934ffbae2f2e0e04d2a832beb6f0bec56027a969ab366727d217406f750890613c988de6de5330cb4f - languageName: node - linkType: hard - "d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:^3.1.6": version: 3.2.3 resolution: "d3-array@npm:3.2.3" @@ -24886,6 +24875,13 @@ __metadata: languageName: node linkType: hard +"encoding-japanese@npm:2.1.0": + version: 2.1.0 + resolution: "encoding-japanese@npm:2.1.0" + checksum: ea1944539046fa9ae8ac38324e5349ebaecc1f972906ad855cc8400e6cac9d47eef16265440d2b8d72165123b94c953374549a85745863bd7d61fac84c2d258a + languageName: node + linkType: hard + "encoding@npm:0.1.12": version: 0.1.12 resolution: "encoding@npm:0.1.12" @@ -27594,26 +27590,6 @@ __metadata: languageName: node linkType: hard -"framer-motion@npm:^11.0.25": - version: 11.2.11 - resolution: "framer-motion@npm:11.2.11" - dependencies: - tslib: ^2.4.0 - peerDependencies: - "@emotion/is-prop-valid": "*" - react: ^18.0.0 - react-dom: ^18.0.0 - peerDependenciesMeta: - "@emotion/is-prop-valid": - optional: true - react: - optional: true - react-dom: - optional: true - checksum: a315e7f36eddf78d7a0a6edfb768e7de235bc34cffe4dabd294e7170646c1b4e2d8ff12797e6602ace8b232648196735d396b5e11d66b4b2ddb53b60d90132c0 - languageName: node - linkType: hard - "fresh@npm:0.5.2, fresh@npm:^0.5.2": version: 0.5.2 resolution: "fresh@npm:0.5.2" @@ -29286,13 +29262,6 @@ __metadata: languageName: node linkType: hard -"hls.js@npm:~1.5.8": - version: 1.5.11 - resolution: "hls.js@npm:1.5.11" - checksum: 04ce982633d33911005fe0d536ae11ffe966ee045fa29c3a06a700aa166d8743e9e500cfc768bf0562be6d124166ae1fb39d3acdae2bfbc69931d3c73ae85d2a - languageName: node - linkType: hard - "hmac-drbg@npm:^1.0.1": version: 1.0.1 resolution: "hmac-drbg@npm:1.0.1" @@ -32220,21 +32189,12 @@ __metadata: languageName: node linkType: hard -"js-tiktoken@npm:^1.0.7": - version: 1.0.7 - resolution: "js-tiktoken@npm:1.0.7" +"js-tiktoken@npm:^1.0.12, js-tiktoken@npm:^1.0.7": + version: 1.0.12 + resolution: "js-tiktoken@npm:1.0.12" dependencies: base64-js: ^1.5.1 - checksum: 4856641fed816e618c8a693db0a5478995c598914dec2ba9ccd69719a88a14756d5aec2eed0fba7a4999e603b277ba9a58fd7b2af98e8b638b39b436bbfb7060 - languageName: node - linkType: hard - -"js-tiktoken@npm:^1.0.8": - version: 1.0.10 - resolution: "js-tiktoken@npm:1.0.10" - dependencies: - base64-js: ^1.5.1 - checksum: 94810d3b903d4ec6b1fbaf91b98870ee2c9f0b38de1d7924a0dfa17baaa083af84f31c37c3b1914bf37e6a012b099e922f548072ddf0c06d95511f9b72c8296d + checksum: 07a0e9cd5cb05f304696ac74e76d48f960d62b0443b65f0d09adf79dc903d2fba82d2cff2907491259bbf8b59842c20f89fd1879d2c0249706e7c84507c687fd languageName: node linkType: hard @@ -32841,20 +32801,20 @@ __metadata: linkType: hard "langchain@npm:^0.1.17": - version: 0.1.17 - resolution: "langchain@npm:0.1.17" + version: 0.1.37 + resolution: "langchain@npm:0.1.37" dependencies: "@anthropic-ai/sdk": ^0.9.1 - "@langchain/community": ~0.0.20 - "@langchain/core": ~0.1.25 - "@langchain/openai": ~0.0.12 + "@langchain/community": ~0.0.47 + "@langchain/core": ~0.1.60 + "@langchain/openai": ~0.0.28 + "@langchain/textsplitters": ~0.0.0 binary-extensions: ^2.2.0 - expr-eval: ^2.0.2 js-tiktoken: ^1.0.7 js-yaml: ^4.1.0 jsonpointer: ^5.0.1 - langchainhub: ~0.0.6 - langsmith: ~0.0.59 + langchainhub: ~0.0.8 + langsmith: ~0.1.7 ml-distance: ^4.0.0 openapi-types: ^12.1.3 p-retry: 4 @@ -32868,11 +32828,13 @@ __metadata: "@aws-sdk/client-sfn": ^3.310.0 "@aws-sdk/credential-provider-node": ^3.388.0 "@azure/storage-blob": ^12.15.0 + "@browserbasehq/sdk": "*" "@gomomento/sdk": ^1.51.1 "@gomomento/sdk-core": ^1.51.1 "@gomomento/sdk-web": ^1.51.1 "@google-ai/generativelanguage": ^0.2.1 - "@google-cloud/storage": ^6.10.1 + "@google-cloud/storage": ^6.10.1 || ^7.7.0 + "@mendable/firecrawl-js": ^0.0.13 "@notionhq/client": ^2.2.10 "@pinecone-database/pinecone": "*" "@supabase/supabase-js": ^2.10.0 @@ -32884,9 +32846,10 @@ __metadata: cheerio: ^1.0.0-rc.12 chromadb: "*" convex: ^1.3.1 + couchbase: ^4.3.0 d3-dsv: ^2.0.0 epub2: ^3.0.1 - fast-xml-parser: ^4.2.7 + fast-xml-parser: "*" google-auth-library: ^8.9.0 handlebars: ^4.7.8 html-to-text: ^9.0.5 @@ -32894,7 +32857,7 @@ __metadata: ioredis: ^5.3.2 jsdom: "*" mammoth: ^1.6.0 - mongodb: ^5.2.0 + mongodb: ">=5.2.0" node-llama-cpp: "*" notion-to-md: ^3.1.0 officeparser: ^4.0.4 @@ -32907,12 +32870,11 @@ __metadata: sonix-speech-recognition: ^2.1.1 srt-parser-2: ^1.2.3 typeorm: ^0.3.12 - vectordb: ^0.1.4 - weaviate-ts-client: ^1.4.0 + weaviate-ts-client: "*" web-auth-library: ^1.0.3 ws: ^8.14.2 youtube-transcript: ^1.0.6 - youtubei.js: ^5.8.0 + youtubei.js: ^9.1.0 peerDependenciesMeta: "@aws-sdk/client-s3": optional: true @@ -32924,6 +32886,8 @@ __metadata: optional: true "@azure/storage-blob": optional: true + "@browserbasehq/sdk": + optional: true "@gomomento/sdk": optional: true "@gomomento/sdk-core": @@ -32934,6 +32898,8 @@ __metadata: optional: true "@google-cloud/storage": optional: true + "@mendable/firecrawl-js": + optional: true "@notionhq/client": optional: true "@pinecone-database/pinecone": @@ -32956,6 +32922,8 @@ __metadata: optional: true convex: optional: true + couchbase: + optional: true d3-dsv: optional: true epub2: @@ -33004,8 +32972,6 @@ __metadata: optional: true typeorm: optional: true - vectordb: - optional: true weaviate-ts-client: optional: true web-auth-library: @@ -33016,29 +32982,38 @@ __metadata: optional: true youtubei.js: optional: true - checksum: 712639657d4ea7ca153e6a092f02506c6878b2d9b2988a88715ee766a6513a488aa9d87a76bfd55d99516394a884383d0dbe4c4a0d02d6c608cd32ebdc4f0a82 + checksum: 6c1106d02c7198db973f0714cd71fb4c11a28a6630818f39ec07c2e0af573af64118bef49d7eb4cea3e2b2b701a2644fb95021377f75b8a9862e6faf9fa8a93a languageName: node linkType: hard -"langchainhub@npm:~0.0.6": - version: 0.0.6 - resolution: "langchainhub@npm:0.0.6" - checksum: f771e5375b7ae9cc6fc59d5e2b1fd35c29e5759f4595617e3a235142bc2ca12c4135aa1631d85ee4e25c89968696242dd6380f6b90e87ffbc9006efc3cdc53c4 +"langchainhub@npm:~0.0.8": + version: 0.0.11 + resolution: "langchainhub@npm:0.0.11" + checksum: 511371a6d9f277ddb0425b830afe41b029cf101becfa8ac55c3e7bf3dba2191d13772130b3c3d99f39d25f3bb22345808e0e8ce956296f49c728f8713072ce0b languageName: node linkType: hard -"langsmith@npm:~0.0.48, langsmith@npm:~0.0.59": - version: 0.0.68 - resolution: "langsmith@npm:0.0.68" +"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" dependencies: "@types/uuid": ^9.0.1 commander: ^10.0.1 p-queue: ^6.6.2 p-retry: 4 uuid: ^9.0.0 - bin: - langsmith: dist/cli/main.cjs - checksum: 63d5000dcbbe26b1bbfcf3f38011f294f6a8c69ac7aa64ee3ea60ef9b033d154641430dd11c0394e970fb5392c83f4c102f9fa3a7fdf2879c4ad85d1f13a4974 + peerDependencies: + "@langchain/core": "*" + langchain: "*" + openai: "*" + peerDependenciesMeta: + "@langchain/core": + optional: true + langchain: + optional: true + openai: + optional: true + checksum: 25e9f68589ef935791258c25c0ac0473f6d45cb6d50970266e3f9ed25eb84530dd5cb8c1a6c13d8ddadf81d2364a56081d5d3798dadb75e685d7c93afac9f903 languageName: node linkType: hard @@ -33260,6 +33235,13 @@ __metadata: languageName: node linkType: hard +"libbase64@npm:1.3.0": + version: 1.3.0 + resolution: "libbase64@npm:1.3.0" + checksum: 14adc74fab5635f7e57b4e49b3bfb13b1e3f3abc2615e56c9c96571b994125ceed12de2c36c0a1d7a3a4d5bb34b82d18cf7fe354382c946929dc42397baf4d1e + languageName: node + linkType: hard + "libmime@npm:5.2.0": version: 5.2.0 resolution: "libmime@npm:5.2.0" @@ -33272,15 +33254,15 @@ __metadata: languageName: node linkType: hard -"libmime@npm:5.2.1": - version: 5.2.1 - resolution: "libmime@npm:5.2.1" +"libmime@npm:5.3.5": + version: 5.3.5 + resolution: "libmime@npm:5.3.5" dependencies: - encoding-japanese: 2.0.0 + encoding-japanese: 2.1.0 iconv-lite: 0.6.3 - libbase64: 1.2.1 - libqp: 2.0.1 - checksum: 52ce39d0c5f6dd94c769191924ad3b8d2a400ea1dd63d8351c67b6bb64f23cdc129f495e9e28e264b41b1b51489c4a58fc5469b51be2db07fa59d8037e10a618 + libbase64: 1.3.0 + libqp: 2.1.0 + checksum: bf541c3968ddebf639be742745d8953f9a0d38f1341cb77c84dc87e537de46f41af7907f3bb32c5da62bb11c4e99579a7bc36211b3f24899e5c37643a4d912e7 languageName: node linkType: hard @@ -33312,6 +33294,13 @@ __metadata: languageName: node linkType: hard +"libqp@npm:2.1.0": + version: 2.1.0 + resolution: "libqp@npm:2.1.0" + checksum: 6fbc0e23cc84e1f9d5061db4fc0363a4fe42fdc008ece956bc525336efa75e297a45f23ed11df15e7fc07419ff11630ac9e310ad5f25347fc26cb673dd578b86 + languageName: node + linkType: hard + "light-bolt11-decoder@npm:^3.0.0": version: 3.0.0 resolution: "light-bolt11-decoder@npm:3.0.0" @@ -33359,7 +33348,16 @@ __metadata: languageName: node linkType: hard -"linkify-it@npm:4.0.1, linkify-it@npm:^4.0.1": +"linkify-it@npm:5.0.0": + version: 5.0.0 + resolution: "linkify-it@npm:5.0.0" + dependencies: + uc.micro: ^2.0.0 + checksum: b0b86cadaf816b64c947a83994ceaad1c15f9fe7e079776ab88699fb71afd7b8fc3fd3d0ae5ebec8c92c1d347be9ba257b8aef338c0ebf81b0d27dcf429a765a + languageName: node + linkType: hard + +"linkify-it@npm:^4.0.1": version: 4.0.1 resolution: "linkify-it@npm:4.0.1" dependencies: @@ -34084,6 +34082,15 @@ __metadata: languageName: node linkType: hard +"lucide-react@npm:^0.171.0": + version: 0.171.0 + resolution: "lucide-react@npm:0.171.0" + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + checksum: 768ffe368c52a518ee339203d86ff4479989ab4d79c0716f721900c4bb7392ef6ff7a14807f6a685abd74d27f4c1778170bff77a0ab4c3e06c17944b557d8300 + languageName: node + linkType: hard + "lucide-react@npm:^0.364.0": version: 0.364.0 resolution: "lucide-react@npm:0.364.0" @@ -34213,19 +34220,20 @@ __metadata: linkType: hard "mailparser@npm:^3.6.5": - version: 3.6.5 - resolution: "mailparser@npm:3.6.5" + version: 3.7.1 + resolution: "mailparser@npm:3.7.1" dependencies: - encoding-japanese: 2.0.0 + encoding-japanese: 2.1.0 he: 1.2.0 html-to-text: 9.0.5 iconv-lite: 0.6.3 - libmime: 5.2.1 - linkify-it: 4.0.1 + libmime: 5.3.5 + linkify-it: 5.0.0 mailsplit: 5.4.0 - nodemailer: 6.9.3 - tlds: 1.240.0 - checksum: 1f6e3a7a9f144e9ea7dc64256a310d3e5f182e32786cd0876e52fbeaf0abccecc11826b7e318a419b23dd1868bbaf893b0c0d3b4a36c66b8efa9ad0d57f9c7fa + nodemailer: 6.9.13 + punycode.js: 2.3.1 + tlds: 1.252.0 + checksum: 509c7177b0e1bae5f29eb2e10606562cae8a83785f09ed1e9adb62b317bbc99dfdb594dd08acb3dc6c81065a427da2f73d2db06e503c74f2b903e75dc2977321 languageName: node linkType: hard @@ -34652,20 +34660,6 @@ __metadata: languageName: node linkType: hard -"media-chrome@npm:~3.2.1": - version: 3.2.3 - resolution: "media-chrome@npm:3.2.3" - checksum: 073757ff6952045052f9c63fbb688ac8ff9f54787f5e26eaa52f47d72a8c53df65a1b62a30e2c7d90631c8c59a0ec2b960e746ab3e6dca389a3f936b42c858f2 - languageName: node - linkType: hard - -"media-tracks@npm:~0.3.0": - version: 0.3.3 - resolution: "media-tracks@npm:0.3.3" - checksum: 4795af3f171d7ad3a68d1ac1c1e8166a735244fe57d3fc0ec53b1c7410799e524756fc0bfb389632aebb148436b03baade36ca34a3f5377776c3968f6d2cc580 - languageName: node - linkType: hard - "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" @@ -36020,6 +36014,15 @@ __metadata: languageName: node linkType: hard +"mustache@npm:^4.2.0": + version: 4.2.0 + resolution: "mustache@npm:4.2.0" + bin: + mustache: bin/mustache + checksum: 928fcb63e3aa44a562bfe9b59ba202cccbe40a46da50be6f0dd831b495be1dd7e38ca4657f0ecab2c1a89dc7bccba0885eab7ee7c1b215830da765758c7e0506 + languageName: node + linkType: hard + "mute-stream@npm:0.0.8": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -36034,13 +36037,6 @@ __metadata: languageName: node linkType: hard -"mux-embed@npm:~5.2.0": - version: 5.2.1 - resolution: "mux-embed@npm:5.2.1" - checksum: ec34d3e003e2520be6d1386ca2383daa198a1fa3a469ca3f06c11a742d6ab136eef4944c37e8f2dcaa0585e1b0a6dfc119e3cf2302c7eb0e7f2ebc7c1fc95fbd - languageName: node - linkType: hard - "mysql2@npm:3.9.1": version: 3.9.1 resolution: "mysql2@npm:3.9.1" @@ -36867,10 +36863,10 @@ __metadata: languageName: node linkType: hard -"nodemailer@npm:6.9.3": - version: 6.9.3 - resolution: "nodemailer@npm:6.9.3" - checksum: 3bea8316652c0578515d9146d2f24660e4855807520153f061d39af76b440a4f61b4e70f10fed35f8f12f115f6aea1aeb483ea7ba0337c0e3e675f117c41c611 +"nodemailer@npm:6.9.13": + version: 6.9.13 + resolution: "nodemailer@npm:6.9.13" + checksum: 1b591ef480be2ff69480127cbff819e6593b1ef263b6f920e1a4e83e40280582daf7a14a809ef92f9828e2a70bdb3ce22b11924e209f2afe4975f9ff37e08e9d languageName: node linkType: hard @@ -37557,22 +37553,21 @@ __metadata: languageName: node linkType: hard -"openai@npm:^4.26.0": - version: 4.27.0 - resolution: "openai@npm:4.27.0" +"openai@npm:^4.26.0, openai@npm:^4.41.1": + version: 4.52.7 + resolution: "openai@npm:4.52.7" dependencies: "@types/node": ^18.11.18 "@types/node-fetch": ^2.6.4 abort-controller: ^3.0.0 agentkeepalive: ^4.2.1 - digest-fetch: ^1.3.0 form-data-encoder: 1.7.2 formdata-node: ^4.3.2 node-fetch: ^2.6.7 web-streams-polyfill: ^3.2.1 bin: openai: bin/cli - checksum: e7c1e20c05db8b9f713f74006c89efc6c94c97847b79a337b52b71a94ee373e6bf9effe2e92479aa98fda37af4920dacfb9aa21f4f737feb4ad338815065c0b5 + checksum: dcf5adc107366c91276a93ec338bb50e82f98048d18ac9bc330e05327fea854404f6ee40b1012c0f99e290afc174d9b886b8fe37f864c22ece30c53c666ed2e1 languageName: node linkType: hard @@ -39899,6 +39894,13 @@ __metadata: languageName: node linkType: hard +"punycode.js@npm:2.3.1": + version: 2.3.1 + resolution: "punycode.js@npm:2.3.1" + checksum: 13466d7ed5e8dacdab8c4cc03837e7dd14218a59a40eb14a837f1f53ca396e18ef2c4ee6d7766b8ed2fc391d6a3ac489eebf2de83b3596f5a54e86df4a251b72 + languageName: node + linkType: hard + "punycode@npm:1.3.2": version: 1.3.2 resolution: "punycode@npm:1.3.2" @@ -40343,21 +40345,20 @@ __metadata: languageName: node linkType: hard -"react-datocms@npm:^5.0.3": - version: 5.0.3 - resolution: "react-datocms@npm:5.0.3" +"react-datocms@npm:^3.1.0": + version: 3.1.4 + resolution: "react-datocms@npm:3.1.4" dependencies: - "@mux/mux-player-react": "*" datocms-listen: ^0.1.9 datocms-structured-text-generic-html-renderer: ^2.0.1 datocms-structured-text-utils: ^2.0.1 - react-intersection-observer: ^9.4.3 + react-intersection-observer: ^8.33.1 react-string-replace: ^1.1.0 universal-base64: ^2.1.0 use-deep-compare-effect: ^1.6.1 peerDependencies: react: ">= 16.12.0" - checksum: 22c20152afb54424acfe967a2c8c525cd9f132a33374f2aba0231f16ea64dade389b096e2dac8de9ffded612bc32e9891d725609ee947639fe1cef907cb143f5 + checksum: 54aba12aef4937175c2011548a8a576c96c8d8a596e84d191826910624c1d596e76a49782689dc236388a10803b02e700ac820cb7500cca7fd147a81f6c544c3 languageName: node linkType: hard @@ -40609,16 +40610,12 @@ __metadata: languageName: node linkType: hard -"react-intersection-observer@npm:^9.4.3": - version: 9.10.3 - resolution: "react-intersection-observer@npm:9.10.3" +"react-intersection-observer@npm:^8.33.1": + version: 8.34.0 + resolution: "react-intersection-observer@npm:8.34.0" peerDependencies: - react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - react-dom: - optional: true - checksum: 482c89a432e582749f3cb3dd696e08638a92e41fbcb81bcb3dc3cadebcf8b40bc47e7a52d2a7e8c4f9eb2a3c1c29b4cb0f21007c1540da05893b5abb11d7a761 + react: ^15.0.0 || ^16.0.0 || ^17.0.0|| ^18.0.0 + checksum: 7713fecfd1512c7f5a60f9f0bf15403b8f8bbd4110bcafaeaea6de36a0e0eb60368c3638f99e9c97b75ad8fc787ea48c241dcb5c694f821d7f2976f709082cc5 languageName: node linkType: hard @@ -40728,16 +40725,6 @@ __metadata: languageName: node linkType: hard -"react-parallax-tilt@npm:^1.7.226": - version: 1.7.229 - resolution: "react-parallax-tilt@npm:1.7.229" - peerDependencies: - react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: f0a034aaa02b2c025cae8e91f3f02650ea7bd279bd51439c41203cabfe59e1a1cf976497d0860f8fe52bde23b79a38a3818e4516b332b1e5e19a9a93029caef5 - languageName: node - linkType: hard - "react-phone-input-2@npm:^2.15.1": version: 2.15.1 resolution: "react-phone-input-2@npm:2.15.1" @@ -41152,18 +41139,6 @@ __metadata: languageName: node linkType: hard -"react-twitter-embed@npm:^4.0.4": - version: 4.0.4 - resolution: "react-twitter-embed@npm:4.0.4" - dependencies: - scriptjs: ^2.5.9 - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: cdb3c5bd04c4da0efa767476be47c0a3865fb6335f2a1b9e242170167b51615c38164223278cef60c77143c4bac27ba582cbea054d0af3f138104fa5ec537c4c - languageName: node - linkType: hard - "react-universal-interface@npm:^0.6.2": version: 0.6.2 resolution: "react-universal-interface@npm:0.6.2" @@ -42988,13 +42963,6 @@ __metadata: languageName: node linkType: hard -"scriptjs@npm:^2.5.9": - version: 2.5.9 - resolution: "scriptjs@npm:2.5.9" - checksum: fc84cb6b60b6fb9aa6f1b3bc59fc94b233bd5241ed3a04233579014382b5eb60640269c87d8657902acc09f9b785ee33230c218627cea00e653564bda8f5acb6 - languageName: node - linkType: hard - "scuid@npm:^1.1.0": version: 1.1.0 resolution: "scuid@npm:1.1.0" @@ -45653,12 +45621,12 @@ __metadata: languageName: node linkType: hard -"tlds@npm:1.240.0": - version: 1.240.0 - resolution: "tlds@npm:1.240.0" +"tlds@npm:1.252.0": + version: 1.252.0 + resolution: "tlds@npm:1.252.0" bin: tlds: bin.js - checksum: c4bfb0bbfde2f7533f79f7aa49d137e37e5c2f41680bb90a32f588386ac908e23132a61675e5e207e7cb06e7fcf77242b9f44040793de9dc4ca0193dcbcda923 + checksum: cc25439b380f879d8ebd23c294e4f9a14e81332ff134122e4dae136fed579b835e6272d39b3e52aeb084f2cb9748f7616dcebf83a0b3e5af312a8e54b712ecbe languageName: node linkType: hard @@ -46797,6 +46765,13 @@ __metadata: languageName: node linkType: hard +"uc.micro@npm:^2.0.0": + version: 2.1.0 + resolution: "uc.micro@npm:2.1.0" + checksum: 37197358242eb9afe367502d4638ac8c5838b78792ab218eafe48287b0ed28aaca268ec0392cc5729f6c90266744de32c06ae938549aee041fc93b0f9672d6b2 + languageName: node + linkType: hard + "ufo@npm:^1.1.2": version: 1.1.2 resolution: "ufo@npm:1.1.2" @@ -47566,6 +47541,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^10.0.0": + version: 10.0.0 + resolution: "uuid@npm:10.0.0" + bin: + uuid: dist/bin/uuid + checksum: 4b81611ade2885d2313ddd8dc865d93d8dccc13ddf901745edca8f86d99bc46d7a330d678e7532e7ebf93ce616679fb19b2e3568873ac0c14c999032acb25869 + languageName: node + linkType: hard + "uuid@npm:^3.3.2": version: 3.4.0 resolution: "uuid@npm:3.4.0" @@ -48997,7 +48981,16 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.2.1, yaml@npm:^2.3.1": +"yaml@npm:^2.2.1": + version: 2.4.5 + resolution: "yaml@npm:2.4.5" + bin: + yaml: bin.mjs + checksum: f8efd407c07e095f00f3031108c9960b2b12971d10162b1ec19007200f6c987d2e28f73283f4731119aa610f177a3ea03d4a8fcf640600a25de1b74d00c69b3d + languageName: node + linkType: hard + +"yaml@npm:^2.3.1": version: 2.4.1 resolution: "yaml@npm:2.4.1" bin: @@ -49264,22 +49257,29 @@ __metadata: languageName: node linkType: hard -"zod-to-json-schema@npm:^3.22.3": - version: 3.22.4 - resolution: "zod-to-json-schema@npm:3.22.4" +"zod-to-json-schema@npm:^3.22.3, zod-to-json-schema@npm:^3.22.5": + version: 3.23.1 + resolution: "zod-to-json-schema@npm:3.23.1" peerDependencies: - zod: ^3.22.4 - checksum: 22f89d505cc3d93020de38e4471362fbecd73a8df58017553ad57fb14e69b6f2f88bcdfe9f84b291442ed0654f97344d517af291d23848e43e6e208ee23dac2b + zod: ^3.23.3 + checksum: bbb0fdd8d28179c912d2d1c93051e418fc933288b8ac3704e7a514498fadf7781a8417aa9d52129a6a89ed5bc5a59793d3739c4869aa38600743cb009b52856d languageName: node linkType: hard -"zod@npm:^3.20.2, zod@npm:^3.22.2, zod@npm:^3.22.3, zod@npm:^3.22.4": +"zod@npm:^3.20.2, zod@npm:^3.22.2, zod@npm:^3.22.4": version: 3.22.4 resolution: "zod@npm:3.22.4" checksum: 80bfd7f8039b24fddeb0718a2ec7c02aa9856e4838d6aa4864335a047b6b37a3273b191ef335bf0b2002e5c514ef261ffcda5a589fb084a48c336ffc4cdbab7f languageName: node linkType: hard +"zod@npm:^3.22.3": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 15949ff82118f59c893dacd9d3c766d02b6fa2e71cf474d5aa888570c469dbf5446ac5ad562bb035bf7ac9650da94f290655c194f4a6de3e766f43febd432c5c + languageName: node + linkType: hard + "zustand@npm:^4.3.2": version: 4.5.2 resolution: "zustand@npm:4.5.2"