refactor: platform org event types (#15961)
* chore: platform-libraries export updateNewTeamMemberEventTypes * chore: platform-libraries export updateNewTeamMemberEventTypes * chore: v2 api bump platform-libraries to 0.0.22 * fix: add created managed user to assignAllMembers: true team event-types * fix: add created organizations user to assignAllMembers: true team event-types * refactor: organization teams chose if team creator is auto-accepted * refactor: managed users have only 2 default event types with video * refactor: lowercase schedulingType for creating team event-types * refactor: lowercase schedulingType for creating team event-types * feat: separate platform teams by OAuth client * swagger regenerate * refactor: delete platform team when oauth client deleted * revert: keep 4 default event-types * fix: tests && merge of main into this branch * fix: typecheck --------- Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
This commit is contained in:
co-authored by
Morgan
parent
2f946fc5da
commit
41e565fcf8
@@ -26,7 +26,7 @@
|
||||
"dependencies": {
|
||||
"@calcom/platform-constants": "*",
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
|
||||
"@calcom/platform-libraries-0.0.21": "npm:@calcom/platform-libraries@0.0.21",
|
||||
"@calcom/platform-libraries-0.0.22": "npm:@calcom/platform-libraries@0.0.22",
|
||||
"@calcom/platform-types": "*",
|
||||
"@calcom/platform-utils": "*",
|
||||
"@calcom/prisma": "*",
|
||||
|
||||
@@ -19,7 +19,7 @@ import { UserRepositoryFixture } from "test/fixtures/repository/users.repository
|
||||
import { withApiAuth } from "test/utils/withApiAuth";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
import { handleNewBooking } from "@calcom/platform-libraries-0.0.21";
|
||||
import { handleNewBooking } from "@calcom/platform-libraries-0.0.22";
|
||||
import { ApiSuccessResponse, ApiResponse } from "@calcom/platform-types";
|
||||
|
||||
describe("Bookings Endpoints", () => {
|
||||
|
||||
@@ -46,7 +46,7 @@ import {
|
||||
getBookingInfo,
|
||||
handleCancelBooking,
|
||||
getBookingForReschedule,
|
||||
} from "@calcom/platform-libraries-0.0.21";
|
||||
} from "@calcom/platform-libraries-0.0.22";
|
||||
import { GetBookingsInput, CancelBookingInput, Status } from "@calcom/platform-types";
|
||||
import { ApiResponse } from "@calcom/platform-types";
|
||||
import { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CreateBookingInput } from "@/ee/bookings/inputs/create-booking.input";
|
||||
import { IsBoolean, IsNumber, IsOptional } from "class-validator";
|
||||
|
||||
import type { AppsStatus } from "@calcom/platform-libraries-0.0.21";
|
||||
import type { AppsStatus } from "@calcom/platform-libraries-0.0.22";
|
||||
|
||||
export class CreateRecurringBookingInput extends CreateBookingInput {
|
||||
@IsBoolean()
|
||||
|
||||
@@ -5,7 +5,7 @@ import { BadRequestException, UnauthorizedException } from "@nestjs/common";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { SUCCESS_STATUS, APPLE_CALENDAR_TYPE, APPLE_CALENDAR_ID } from "@calcom/platform-constants";
|
||||
import { symmetricEncrypt, CalendarService } from "@calcom/platform-libraries-0.0.21";
|
||||
import { symmetricEncrypt, CalendarService } from "@calcom/platform-libraries-0.0.22";
|
||||
|
||||
@Injectable()
|
||||
export class AppleCalendarService implements CredentialSyncCalendarApp {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { User } from "@prisma/client";
|
||||
import { DateTime } from "luxon";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getConnectedDestinationCalendars, getBusyCalendarTimes } from "@calcom/platform-libraries-0.0.21";
|
||||
import { getConnectedDestinationCalendars, getBusyCalendarTimes } from "@calcom/platform-libraries-0.0.22";
|
||||
import { Calendar } from "@calcom/platform-types";
|
||||
import { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ import {
|
||||
EventTypesPublic,
|
||||
eventTypeBookingFields,
|
||||
eventTypeLocations,
|
||||
} from "@calcom/platform-libraries-0.0.21";
|
||||
} from "@calcom/platform-libraries-0.0.22";
|
||||
import { ApiSuccessResponse } from "@calcom/platform-types";
|
||||
|
||||
describe("Event types Endpoints", () => {
|
||||
|
||||
@@ -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.21";
|
||||
import { getEventTypeById } from "@calcom/platform-libraries-0.0.22";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
@Injectable()
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import {
|
||||
updateEventType,
|
||||
EventTypesPublic,
|
||||
getEventTypesPublic,
|
||||
} from "@calcom/platform-libraries-0.0.21";
|
||||
} from "@calcom/platform-libraries-0.0.22";
|
||||
import { EventType } from "@calcom/prisma/client";
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
getEventTypeById,
|
||||
transformApiEventTypeBookingFields,
|
||||
transformApiEventTypeLocations,
|
||||
} from "@calcom/platform-libraries-0.0.21";
|
||||
} from "@calcom/platform-libraries-0.0.22";
|
||||
import { CreateEventTypeInput_2024_06_14 } from "@calcom/platform-types";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
|
||||
+3
-3
@@ -10,9 +10,9 @@ import { UsersService } from "@/modules/users/services/users.service";
|
||||
import { UserWithProfile, UsersRepository } from "@/modules/users/users.repository";
|
||||
import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
|
||||
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.21";
|
||||
import { getEventTypesPublic, EventTypesPublic } from "@calcom/platform-libraries-0.0.21";
|
||||
import { dynamicEvent } from "@calcom/platform-libraries-0.0.21";
|
||||
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.22";
|
||||
import { getEventTypesPublic, EventTypesPublic } from "@calcom/platform-libraries-0.0.22";
|
||||
import { dynamicEvent } from "@calcom/platform-libraries-0.0.22";
|
||||
import {
|
||||
CreateEventTypeInput_2024_06_14,
|
||||
UpdateEventTypeInput_2024_06_14,
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { Injectable } from "@nestjs/common";
|
||||
import {
|
||||
transformApiEventTypeBookingFields,
|
||||
transformApiEventTypeLocations,
|
||||
} from "@calcom/platform-libraries-0.0.21";
|
||||
} from "@calcom/platform-libraries-0.0.22";
|
||||
import { CreateEventTypeInput_2024_06_14, UpdateEventTypeInput_2024_06_14 } from "@calcom/platform-types";
|
||||
|
||||
@Injectable()
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import {
|
||||
parseRecurringEvent,
|
||||
TransformedLocationsSchema,
|
||||
BookingFieldsSchema,
|
||||
} from "@calcom/platform-libraries-0.0.21";
|
||||
} from "@calcom/platform-libraries-0.0.22";
|
||||
|
||||
type EventTypeRelations = { users: User[]; schedule: Schedule | null };
|
||||
type DatabaseEventType = EventType & EventTypeRelations;
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { Injectable } from "@nestjs/common";
|
||||
import {
|
||||
transformApiScheduleOverrides,
|
||||
transformApiScheduleAvailability,
|
||||
} from "@calcom/platform-libraries-0.0.21";
|
||||
} from "@calcom/platform-libraries-0.0.22";
|
||||
import { CreateScheduleInput_2024_06_11, ScheduleAvailabilityInput_2024_06_11 } from "@calcom/platform-types";
|
||||
import { ScheduleOverrideInput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ArgumentsHost, Catch, ExceptionFilter, Logger } from "@nestjs/common";
|
||||
import { Request } from "express";
|
||||
|
||||
import { ERROR_STATUS } from "@calcom/platform-constants";
|
||||
import { TRPCError } from "@calcom/platform-libraries-0.0.21";
|
||||
import { TRPCError } from "@calcom/platform-libraries-0.0.22";
|
||||
import { Response } from "@calcom/platform-types";
|
||||
|
||||
@Catch(TRPCError)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { sendSignupToOrganizationEmail, getTranslation } from "@calcom/platform-libraries-0.0.21";
|
||||
import { sendSignupToOrganizationEmail, getTranslation } from "@calcom/platform-libraries-0.0.22";
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
|
||||
+248
-3
@@ -14,7 +14,7 @@ import { UsersModule } from "@/modules/users/users.module";
|
||||
import { INestApplication } from "@nestjs/common";
|
||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { Test } from "@nestjs/testing";
|
||||
import { PlatformOAuthClient, Team, User } from "@prisma/client";
|
||||
import { PlatformOAuthClient, Team, User, EventType } from "@prisma/client";
|
||||
import * as request from "supertest";
|
||||
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
|
||||
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.repository.fixture";
|
||||
@@ -204,10 +204,16 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
// note(Lauris): to determine count see default event types created in EventTypesService.createUserDefaultEventTypes
|
||||
expect(defaultEventTypes?.length).toEqual(4);
|
||||
expect(
|
||||
defaultEventTypes?.find((eventType) => eventType.length === DEFAULT_EVENT_TYPES.thirtyMinutes.length)
|
||||
defaultEventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.thirtyMinutes.slug)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
defaultEventTypes?.find((eventType) => eventType.length === DEFAULT_EVENT_TYPES.sixtyMinutes.length)
|
||||
defaultEventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.sixtyMinutes.slug)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
defaultEventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.thirtyMinutesVideo.slug)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
defaultEventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.sixtyMinutesVideo.slug)
|
||||
).toBeTruthy();
|
||||
}
|
||||
|
||||
@@ -301,4 +307,243 @@ describe("OAuth Client Users Endpoints", () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe("User team even-types", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let oAuthClient1: PlatformOAuthClient;
|
||||
let oAuthClient2: PlatformOAuthClient;
|
||||
|
||||
let organization: Team;
|
||||
let team1: Team;
|
||||
let team2: Team;
|
||||
let owner: User;
|
||||
|
||||
let managedEventType1: EventType;
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
|
||||
let teamRepositoryFixture: TeamRepositoryFixture;
|
||||
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
|
||||
let profileRepositoryFixture: ProfileRepositoryFixture;
|
||||
|
||||
let postResponseData: CreateUserResponse;
|
||||
|
||||
const userEmail = "oauth-client-users-user@gmail.com";
|
||||
const userTimeZone = "Europe/Rome";
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
providers: [PrismaExceptionFilter, HttpExceptionFilter],
|
||||
imports: [AppModule, UsersModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleRef.createNestApplication();
|
||||
bootstrap(app as NestExpressApplication);
|
||||
|
||||
oauthClientRepositoryFixture = new OAuthClientRepositoryFixture(moduleRef);
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
teamRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
|
||||
profileRepositoryFixture = new ProfileRepositoryFixture(moduleRef);
|
||||
|
||||
organization = await teamRepositoryFixture.create({
|
||||
name: "Testy Organization",
|
||||
isOrganization: true,
|
||||
});
|
||||
|
||||
owner = await userRepositoryFixture.create({
|
||||
email: userEmail,
|
||||
username: userEmail,
|
||||
organization: { connect: { id: organization.id } },
|
||||
});
|
||||
|
||||
await profileRepositoryFixture.create({
|
||||
uid: `usr-${owner.id}`,
|
||||
username: userEmail,
|
||||
organization: {
|
||||
connect: {
|
||||
id: organization.id,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
connect: {
|
||||
id: owner.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
oAuthClient1 = await createOAuthClient(organization.id);
|
||||
oAuthClient2 = await createOAuthClient(organization.id);
|
||||
|
||||
team1 = await teamRepositoryFixture.create({
|
||||
name: "Testy org team",
|
||||
isOrganization: false,
|
||||
parent: { connect: { id: organization.id } },
|
||||
createdByOAuthClient: { connect: { id: oAuthClient1.id } },
|
||||
});
|
||||
|
||||
team2 = await teamRepositoryFixture.create({
|
||||
name: "Testy org team 2",
|
||||
isOrganization: false,
|
||||
parent: { connect: { id: organization.id } },
|
||||
createdByOAuthClient: { connect: { id: oAuthClient2.id } },
|
||||
});
|
||||
|
||||
// note(Lauris): team1 team event-types
|
||||
await eventTypesRepositoryFixture.createTeamEventType({
|
||||
schedulingType: "COLLECTIVE",
|
||||
team: {
|
||||
connect: { id: team1.id },
|
||||
},
|
||||
title: "Collective Event Type",
|
||||
slug: "collective-event-type",
|
||||
length: 30,
|
||||
assignAllTeamMembers: true,
|
||||
bookingFields: [],
|
||||
locations: [],
|
||||
});
|
||||
|
||||
managedEventType1 = await eventTypesRepositoryFixture.createTeamEventType({
|
||||
schedulingType: "MANAGED",
|
||||
team: {
|
||||
connect: { id: team1.id },
|
||||
},
|
||||
title: "Managed Event Type",
|
||||
slug: "managed-event-type",
|
||||
length: 60,
|
||||
assignAllTeamMembers: true,
|
||||
bookingFields: [],
|
||||
locations: [],
|
||||
});
|
||||
|
||||
// note(Lauris): team2 team event-types
|
||||
await eventTypesRepositoryFixture.createTeamEventType({
|
||||
schedulingType: "COLLECTIVE",
|
||||
team: {
|
||||
connect: { id: team2.id },
|
||||
},
|
||||
title: "Collective Event Type team 2",
|
||||
slug: "collective-event-type-team-2",
|
||||
length: 30,
|
||||
assignAllTeamMembers: true,
|
||||
bookingFields: [],
|
||||
locations: [],
|
||||
});
|
||||
|
||||
await eventTypesRepositoryFixture.createTeamEventType({
|
||||
schedulingType: "MANAGED",
|
||||
team: {
|
||||
connect: { id: team2.id },
|
||||
},
|
||||
title: "Managed Event Type team 2",
|
||||
slug: "managed-event-type-team-2",
|
||||
length: 60,
|
||||
assignAllTeamMembers: true,
|
||||
bookingFields: [],
|
||||
locations: [],
|
||||
});
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
async function createOAuthClient(organizationId: number) {
|
||||
const data = {
|
||||
logo: "logo-url",
|
||||
name: "name",
|
||||
redirectUris: [CLIENT_REDIRECT_URI],
|
||||
permissions: 32,
|
||||
};
|
||||
const secret = "secret";
|
||||
|
||||
const client = await oauthClientRepositoryFixture.create(organizationId, data, secret);
|
||||
return client;
|
||||
}
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(oauthClientRepositoryFixture).toBeDefined();
|
||||
expect(userRepositoryFixture).toBeDefined();
|
||||
expect(oAuthClient1).toBeDefined();
|
||||
});
|
||||
|
||||
it(`should create managed user and update team event-types of OAuthClient marked as assignAllTeamMembers: true`, async () => {
|
||||
const requestBody: CreateManagedUserInput = {
|
||||
email: userEmail,
|
||||
timeZone: userTimeZone,
|
||||
weekStart: "Monday",
|
||||
timeFormat: 24,
|
||||
locale: Locales.FR,
|
||||
};
|
||||
|
||||
const response = await request(app.getHttpServer())
|
||||
.post(`/api/v2/oauth-clients/${oAuthClient1.id}/users`)
|
||||
.set("x-cal-secret-key", oAuthClient1.secret)
|
||||
.send(requestBody)
|
||||
.expect(201);
|
||||
|
||||
const responseBody: ApiSuccessResponse<{
|
||||
user: Omit<User, "password">;
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
}> = response.body;
|
||||
|
||||
postResponseData = responseBody.data;
|
||||
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
|
||||
await userHasCorrectEventTypes(responseBody.data.user.id);
|
||||
await teamHasCorrectEventTypes(team1.id);
|
||||
});
|
||||
|
||||
async function userHasCorrectEventTypes(userId: number) {
|
||||
const eventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(userId);
|
||||
|
||||
expect(eventTypes?.length).toEqual(5);
|
||||
|
||||
// note(Lauris): managed event-types with assignAllTeamMembers: true
|
||||
expect(eventTypes?.find((eventType) => eventType.slug === managedEventType1.slug)).toBeTruthy();
|
||||
|
||||
// note(Lauris): default event types
|
||||
expect(
|
||||
eventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.thirtyMinutes.slug)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
eventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.sixtyMinutes.slug)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
eventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.thirtyMinutesVideo.slug)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
eventTypes?.find((eventType) => eventType.slug === DEFAULT_EVENT_TYPES.sixtyMinutesVideo.slug)
|
||||
).toBeTruthy();
|
||||
}
|
||||
|
||||
async function teamHasCorrectEventTypes(teamId: number) {
|
||||
const eventTypes = await eventTypesRepositoryFixture.getAllTeamEventTypes(teamId);
|
||||
|
||||
expect(eventTypes?.length).toEqual(2);
|
||||
|
||||
// note(Lauris): managed event-types with assignAllTeamMembers: true
|
||||
expect(eventTypes?.find((eventType) => eventType.slug === managedEventType1.slug)).toBeTruthy();
|
||||
|
||||
// note(Lauris): check if managed user added to collective event-type hosts given that it has assignAllTeamMembers: true
|
||||
const collective = eventTypes?.find((eventType) => eventType.schedulingType === "COLLECTIVE");
|
||||
expect(collective).toBeTruthy();
|
||||
expect(collective?.hosts).toBeDefined();
|
||||
expect(collective?.hosts?.length).toEqual(1);
|
||||
expect(collective?.hosts[0].userId).toEqual(postResponseData.user.id);
|
||||
}
|
||||
|
||||
afterAll(async () => {
|
||||
await oauthClientRepositoryFixture.delete(oAuthClient1.id);
|
||||
await teamRepositoryFixture.delete(organization.id);
|
||||
await userRepositoryFixture.delete(owner.id);
|
||||
try {
|
||||
await userRepositoryFixture.delete(postResponseData.user.id);
|
||||
} catch (e) {
|
||||
// User might have been deleted by the test
|
||||
}
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+1
@@ -78,6 +78,7 @@ export class OAuthClientUsersController {
|
||||
`Creating user with data: ${JSON.stringify(body, null, 2)} for OAuth Client with ID ${oAuthClientId}`
|
||||
);
|
||||
const client = await this.oauthRepository.getOAuthClient(oAuthClientId);
|
||||
console.log("asap createUser client", JSON.stringify(client, null, 2));
|
||||
|
||||
const isPlatformManaged = true;
|
||||
const { user, tokens } = await this.oAuthClientUsersService.createOauthClientUser(
|
||||
|
||||
@@ -10,6 +10,7 @@ import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repo
|
||||
import { OAuthClientUsersService } from "@/modules/oauth-clients/services/oauth-clients-users.service";
|
||||
import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.service";
|
||||
import { OrganizationsModule } from "@/modules/organizations/organizations.module";
|
||||
import { OrganizationsTeamsService } from "@/modules/organizations/services/organizations-teams.service";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RedisModule } from "@/modules/redis/redis.module";
|
||||
import { StripeModule } from "@/modules/stripe/stripe.module";
|
||||
@@ -33,7 +34,13 @@ import { Global, Module } from "@nestjs/common";
|
||||
BillingModule,
|
||||
SchedulesModule_2024_04_15,
|
||||
],
|
||||
providers: [OAuthClientRepository, TokensRepository, OAuthFlowService, OAuthClientUsersService],
|
||||
providers: [
|
||||
OAuthClientRepository,
|
||||
TokensRepository,
|
||||
OAuthFlowService,
|
||||
OAuthClientUsersService,
|
||||
OrganizationsTeamsService,
|
||||
],
|
||||
controllers: [OAuthClientUsersController, OAuthClientsController, OAuthFlowController],
|
||||
exports: [OAuthClientRepository],
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { EventTypesService_2024_04_15 } from "@/ee/event-types/event-types_2024_04_15/services/event-types.service";
|
||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||
import { OrganizationsTeamsService } from "@/modules/organizations/services/organizations-teams.service";
|
||||
import { TokensRepository } from "@/modules/tokens/tokens.repository";
|
||||
import { CreateManagedUserInput } from "@/modules/users/inputs/create-managed-user.input";
|
||||
import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input";
|
||||
@@ -7,7 +8,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.21";
|
||||
import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries-0.0.22";
|
||||
|
||||
@Injectable()
|
||||
export class OAuthClientUsersService {
|
||||
@@ -15,7 +16,8 @@ export class OAuthClientUsersService {
|
||||
private readonly userRepository: UsersRepository,
|
||||
private readonly tokensRepository: TokensRepository,
|
||||
private readonly eventTypesService: EventTypesService_2024_04_15,
|
||||
private readonly schedulesService: SchedulesService_2024_04_15
|
||||
private readonly schedulesService: SchedulesService_2024_04_15,
|
||||
private readonly organizationsTeamsService: OrganizationsTeamsService
|
||||
) {}
|
||||
|
||||
async createOauthClientUser(
|
||||
@@ -78,6 +80,8 @@ export class OAuthClientUsersService {
|
||||
user.defaultScheduleId = defaultSchedule.id;
|
||||
}
|
||||
|
||||
await this.organizationsTeamsService.addUserToPlatformTeamEvents(user.id, organizationId, oAuthClientId);
|
||||
|
||||
return {
|
||||
user,
|
||||
tokens: {
|
||||
|
||||
+4
-2
@@ -248,7 +248,9 @@ describe("Organizations Event Types Endpoints", () => {
|
||||
options: ["javascript", "python", "cobol"],
|
||||
},
|
||||
],
|
||||
schedulingType: "COLLECTIVE",
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
schedulingType: "collective",
|
||||
hosts: [
|
||||
{
|
||||
userId: teammate1.id,
|
||||
@@ -270,6 +272,7 @@ describe("Organizations Event Types Endpoints", () => {
|
||||
const data = responseBody.data;
|
||||
expect(data.title).toEqual(body.title);
|
||||
expect(data.hosts.length).toEqual(2);
|
||||
expect(data.schedulingType).toEqual("COLLECTIVE");
|
||||
evaluateHost(body.hosts[0], data.hosts[0]);
|
||||
evaluateHost(body.hosts[1], data.hosts[1]);
|
||||
|
||||
@@ -385,7 +388,6 @@ describe("Organizations Event Types Endpoints", () => {
|
||||
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");
|
||||
|
||||
+190
-12
@@ -11,20 +11,20 @@ import { Test } from "@nestjs/testing";
|
||||
import { User } from "@prisma/client";
|
||||
import * as request from "supertest";
|
||||
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
|
||||
import { OAuthClientRepositoryFixture } from "test/fixtures/repository/oauth-client.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 { SUCCESS_STATUS, X_CAL_CLIENT_ID, X_CAL_SECRET_KEY } from "@calcom/platform-constants";
|
||||
import { ApiSuccessResponse } from "@calcom/platform-types";
|
||||
import { Team } from "@calcom/prisma/client";
|
||||
import { PlatformOAuthClient, Team } from "@calcom/prisma/client";
|
||||
|
||||
describe("Organizations Team Endpoints", () => {
|
||||
describe("User Authentication - User is Org Admin", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let organizationsRepositoryFixture: TeamRepositoryFixture;
|
||||
let teamsRepositoryFixture: TeamRepositoryFixture;
|
||||
let membershipsRepositoryFixture: MembershipRepositoryFixture;
|
||||
|
||||
@@ -32,6 +32,7 @@ describe("Organizations Team Endpoints", () => {
|
||||
let team: Team;
|
||||
let team2: Team;
|
||||
let teamCreatedViaApi: Team;
|
||||
let teamCreatedViaApi2: Team;
|
||||
|
||||
const userEmail = "org-admin-teams-controller-e2e@api.com";
|
||||
let user: User;
|
||||
@@ -45,7 +46,6 @@ describe("Organizations Team Endpoints", () => {
|
||||
).compile();
|
||||
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
organizationsRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
teamsRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
membershipsRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
|
||||
|
||||
@@ -54,7 +54,7 @@ describe("Organizations Team Endpoints", () => {
|
||||
username: userEmail,
|
||||
});
|
||||
|
||||
org = await organizationsRepositoryFixture.create({
|
||||
org = await teamsRepositoryFixture.create({
|
||||
name: "Test Organization",
|
||||
isOrganization: true,
|
||||
});
|
||||
@@ -85,7 +85,7 @@ describe("Organizations Team Endpoints", () => {
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(userRepositoryFixture).toBeDefined();
|
||||
expect(organizationsRepositoryFixture).toBeDefined();
|
||||
expect(teamsRepositoryFixture).toBeDefined();
|
||||
expect(user).toBeDefined();
|
||||
expect(org).toBeDefined();
|
||||
});
|
||||
@@ -147,6 +147,7 @@ describe("Organizations Team Endpoints", () => {
|
||||
teamCreatedViaApi.id
|
||||
);
|
||||
expect(membership?.role ?? "").toEqual("OWNER");
|
||||
expect(membership?.accepted).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -199,11 +200,35 @@ describe("Organizations Team Endpoints", () => {
|
||||
return request(app.getHttpServer()).get(`/v2/organizations/${org.id}/teams/123132145`).expect(404);
|
||||
});
|
||||
|
||||
it("should create the team of the org without auto-accepting creator", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.post(`/v2/organizations/${org.id}/teams`)
|
||||
.send({
|
||||
name: "Team II created via API",
|
||||
autoAcceptCreator: false,
|
||||
} satisfies CreateOrgTeamDto)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
const responseBody: ApiSuccessResponse<Team> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
teamCreatedViaApi2 = responseBody.data;
|
||||
expect(teamCreatedViaApi2.name).toEqual("Team II created via API");
|
||||
expect(teamCreatedViaApi2.parentId).toEqual(org.id);
|
||||
const membership = await membershipsRepositoryFixture.getUserMembershipByTeamId(
|
||||
user.id,
|
||||
teamCreatedViaApi2.id
|
||||
);
|
||||
expect(membership?.role ?? "").toEqual("OWNER");
|
||||
expect(membership?.accepted).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await userRepositoryFixture.deleteByEmail(user.email);
|
||||
await teamsRepositoryFixture.delete(team.id);
|
||||
await teamsRepositoryFixture.delete(team2.id);
|
||||
await organizationsRepositoryFixture.delete(org.id);
|
||||
await teamsRepositoryFixture.delete(teamCreatedViaApi2.id);
|
||||
await teamsRepositoryFixture.delete(org.id);
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
@@ -214,7 +239,6 @@ describe("Organizations Team Endpoints", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let organizationsRepositoryFixture: TeamRepositoryFixture;
|
||||
let teamsRepositoryFixture: TeamRepositoryFixture;
|
||||
let membershipsRepositoryFixture: MembershipRepositoryFixture;
|
||||
|
||||
@@ -234,7 +258,6 @@ describe("Organizations Team Endpoints", () => {
|
||||
).compile();
|
||||
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
organizationsRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
teamsRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
membershipsRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
|
||||
|
||||
@@ -243,7 +266,7 @@ describe("Organizations Team Endpoints", () => {
|
||||
username: userEmail,
|
||||
});
|
||||
|
||||
org = await organizationsRepositoryFixture.create({
|
||||
org = await teamsRepositoryFixture.create({
|
||||
name: "Test Organization",
|
||||
isOrganization: true,
|
||||
});
|
||||
@@ -274,7 +297,7 @@ describe("Organizations Team Endpoints", () => {
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(userRepositoryFixture).toBeDefined();
|
||||
expect(organizationsRepositoryFixture).toBeDefined();
|
||||
expect(teamsRepositoryFixture).toBeDefined();
|
||||
expect(user).toBeDefined();
|
||||
expect(org).toBeDefined();
|
||||
});
|
||||
@@ -317,7 +340,7 @@ describe("Organizations Team Endpoints", () => {
|
||||
await userRepositoryFixture.deleteByEmail(user.email);
|
||||
await teamsRepositoryFixture.delete(team.id);
|
||||
await teamsRepositoryFixture.delete(team2.id);
|
||||
await organizationsRepositoryFixture.delete(org.id);
|
||||
await teamsRepositoryFixture.delete(org.id);
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
@@ -448,3 +471,158 @@ describe("Organizations Team Endpoints", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Organizations Team Endpoints", () => {
|
||||
describe("Platform teams", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let teamsRepositoryFixture: TeamRepositoryFixture;
|
||||
let membershipsRepositoryFixture: MembershipRepositoryFixture;
|
||||
let oauthClientRepositoryFixture: OAuthClientRepositoryFixture;
|
||||
|
||||
let oAuthClient1: PlatformOAuthClient;
|
||||
let oAuthClient2: PlatformOAuthClient;
|
||||
let org: Team;
|
||||
let team1: Team;
|
||||
let team2: Team;
|
||||
|
||||
const userEmail = "platform-org-member-teams-owner-controller-e2e@api.com";
|
||||
let user: User;
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await withApiAuth(
|
||||
userEmail,
|
||||
Test.createTestingModule({
|
||||
imports: [AppModule, PrismaModule, UsersModule, TokensModule],
|
||||
})
|
||||
).compile();
|
||||
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
teamsRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
membershipsRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
|
||||
oauthClientRepositoryFixture = new OAuthClientRepositoryFixture(moduleRef);
|
||||
|
||||
user = await userRepositoryFixture.create({
|
||||
email: userEmail,
|
||||
username: userEmail,
|
||||
});
|
||||
|
||||
org = await teamsRepositoryFixture.create({
|
||||
name: "Platform Test Organization",
|
||||
isOrganization: true,
|
||||
});
|
||||
|
||||
await membershipsRepositoryFixture.create({
|
||||
role: "ADMIN",
|
||||
user: { connect: { id: user.id } },
|
||||
team: { connect: { id: org.id } },
|
||||
});
|
||||
|
||||
oAuthClient1 = await createOAuthClient(org.id);
|
||||
oAuthClient2 = await createOAuthClient(org.id);
|
||||
|
||||
app = moduleRef.createNestApplication();
|
||||
bootstrap(app as NestExpressApplication);
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
async function createOAuthClient(organizationId: number) {
|
||||
const data = {
|
||||
logo: "logo-url",
|
||||
name: "name",
|
||||
redirectUris: ["redirect-uri"],
|
||||
permissions: 32,
|
||||
};
|
||||
const secret = "secret";
|
||||
|
||||
return await oauthClientRepositoryFixture.create(organizationId, data, secret);
|
||||
}
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(userRepositoryFixture).toBeDefined();
|
||||
expect(teamsRepositoryFixture).toBeDefined();
|
||||
expect(user).toBeDefined();
|
||||
expect(org).toBeDefined();
|
||||
});
|
||||
|
||||
it("should create first oAuth client team", async () => {
|
||||
const teamName = "Platform team created via API";
|
||||
return request(app.getHttpServer())
|
||||
.post(`/v2/organizations/${org.id}/teams`)
|
||||
.set(X_CAL_CLIENT_ID, oAuthClient1.id)
|
||||
.send({
|
||||
name: teamName,
|
||||
} satisfies CreateOrgTeamDto)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
const responseBody: ApiSuccessResponse<Team> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
team1 = responseBody.data;
|
||||
expect(team1.name).toEqual(teamName);
|
||||
expect(team1.parentId).toEqual(org.id);
|
||||
|
||||
const membership = await membershipsRepositoryFixture.getUserMembershipByTeamId(user.id, team1.id);
|
||||
|
||||
expect(membership?.role ?? "").toEqual("OWNER");
|
||||
expect(membership?.accepted).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should create second oAuth client team", async () => {
|
||||
const teamName = "Platform team II created via API";
|
||||
return request(app.getHttpServer())
|
||||
.post(`/v2/organizations/${org.id}/teams`)
|
||||
.set(X_CAL_CLIENT_ID, oAuthClient2.id)
|
||||
.set(X_CAL_SECRET_KEY, oAuthClient2.secret)
|
||||
.send({
|
||||
name: teamName,
|
||||
} satisfies CreateOrgTeamDto)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
const responseBody: ApiSuccessResponse<Team> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
team2 = responseBody.data;
|
||||
expect(team2.name).toEqual(teamName);
|
||||
expect(team2.parentId).toEqual(org.id);
|
||||
|
||||
const membership = await membershipsRepositoryFixture.getUserMembershipByTeamId(user.id, team2.id);
|
||||
|
||||
expect(membership?.role ?? "").toEqual("OWNER");
|
||||
expect(membership?.accepted).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should get all the platform teams correctly tied to OAuth clients", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/organizations/${org.id}/teams`)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: ApiSuccessResponse<Team[]> = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data[0].id).toEqual(team1.id);
|
||||
expect(responseBody.data[1].id).toEqual(team2.id);
|
||||
|
||||
const oAuthClientTeams = await teamsRepositoryFixture.getPlatformOrgTeams(org.id, oAuthClient1.id);
|
||||
expect(oAuthClientTeams.length).toEqual(1);
|
||||
const oAuthClientTeam = oAuthClientTeams[0];
|
||||
expect(oAuthClientTeam.id).toEqual(team1.id);
|
||||
expect(oAuthClientTeam.name).toEqual(team1.name);
|
||||
|
||||
const oAuthClient2Teams = await teamsRepositoryFixture.getPlatformOrgTeams(org.id, oAuthClient2.id);
|
||||
expect(oAuthClient2Teams.length).toEqual(1);
|
||||
const oAuthClientTeam2 = oAuthClient2Teams[0];
|
||||
expect(oAuthClientTeam2.id).toEqual(team2.id);
|
||||
expect(oAuthClientTeam2.name).toEqual(team2.name);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await userRepositoryFixture.deleteByEmail(user.email);
|
||||
await teamsRepositoryFixture.delete(team1.id);
|
||||
await teamsRepositoryFixture.delete(org.id);
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+10
-4
@@ -9,6 +9,7 @@ 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 { CreateOrgTeamDto } from "@/modules/organizations/inputs/create-organization-team.input";
|
||||
import { UpdateOrgTeamDto } from "@/modules/organizations/inputs/update-organization-team.input";
|
||||
import {
|
||||
OrgMeTeamOutputDto,
|
||||
OrgMeTeamsOutputResponseDto,
|
||||
@@ -28,11 +29,12 @@ import {
|
||||
Patch,
|
||||
Post,
|
||||
Body,
|
||||
Headers,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { SUCCESS_STATUS, X_CAL_CLIENT_ID } from "@calcom/platform-constants";
|
||||
import { OrgTeamOutputDto } from "@calcom/platform-types";
|
||||
import { SkipTakePagination } from "@calcom/platform-types";
|
||||
import { Team } from "@calcom/prisma/client";
|
||||
@@ -126,7 +128,7 @@ export class OrganizationsTeamsController {
|
||||
async updateTeam(
|
||||
@Param("orgId", ParseIntPipe) orgId: number,
|
||||
@Param("teamId", ParseIntPipe) teamId: number,
|
||||
@Body() body: CreateOrgTeamDto
|
||||
@Body() body: UpdateOrgTeamDto
|
||||
): Promise<OrgTeamOutputResponseDto> {
|
||||
const team = await this.organizationsTeamsService.updateOrgTeam(orgId, teamId, body);
|
||||
return {
|
||||
@@ -142,9 +144,13 @@ export class OrganizationsTeamsController {
|
||||
async createTeam(
|
||||
@Param("orgId", ParseIntPipe) orgId: number,
|
||||
@Body() body: CreateOrgTeamDto,
|
||||
@GetUser() user: UserWithProfile
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Headers(X_CAL_CLIENT_ID) oAuthClientId?: string
|
||||
): Promise<OrgTeamOutputResponseDto> {
|
||||
const team = await this.organizationsTeamsService.createOrgTeam(orgId, body, user);
|
||||
const team = oAuthClientId
|
||||
? await this.organizationsTeamsService.createPlatformOrgTeam(orgId, oAuthClientId, body, user)
|
||||
: await this.organizationsTeamsService.createOrgTeam(orgId, body, user);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: plainToClass(OrgTeamOutputDto, team, { strategy: "excludeAll" }),
|
||||
|
||||
+164
-3
@@ -8,6 +8,7 @@ import { INestApplication } from "@nestjs/common";
|
||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { Test } from "@nestjs/testing";
|
||||
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";
|
||||
@@ -15,7 +16,7 @@ import { UserRepositoryFixture } from "test/fixtures/repository/users.repository
|
||||
import { withApiAuth } from "test/utils/withApiAuth";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { User, Team, Membership } from "@calcom/prisma/client";
|
||||
import { User, Team, EventType } from "@calcom/prisma/client";
|
||||
|
||||
describe("Organizations Users Endpoints", () => {
|
||||
describe("Member role", () => {
|
||||
@@ -29,7 +30,6 @@ describe("Organizations Users Endpoints", () => {
|
||||
const userEmail = "member1@org.com";
|
||||
let user: User;
|
||||
let org: Team;
|
||||
let membership: Membership;
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await withApiAuth(
|
||||
@@ -70,7 +70,7 @@ describe("Organizations Users Endpoints", () => {
|
||||
},
|
||||
});
|
||||
|
||||
membership = await membershipFixtures.addUserToOrg(user, org, "MEMBER", true);
|
||||
await membershipFixtures.addUserToOrg(user, org, "MEMBER", true);
|
||||
app = moduleRef.createNestApplication();
|
||||
bootstrap(app as NestExpressApplication);
|
||||
|
||||
@@ -344,4 +344,165 @@ describe("Organizations Users Endpoints", () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Member event-types", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let organizationsRepositoryFixture: TeamRepositoryFixture;
|
||||
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
|
||||
let membershipFixtures: MembershipRepositoryFixture;
|
||||
let profileRepositoryFixture: ProfileRepositoryFixture;
|
||||
|
||||
const authEmail = "auth@org.com";
|
||||
let user: User;
|
||||
let org: Team;
|
||||
let team: Team;
|
||||
let managedEventType: EventType;
|
||||
let createdUser: User;
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await withApiAuth(
|
||||
authEmail,
|
||||
Test.createTestingModule({
|
||||
imports: [AppModule, PrismaModule, UsersModule, TokensModule],
|
||||
})
|
||||
).compile();
|
||||
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
organizationsRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
|
||||
membershipFixtures = new MembershipRepositoryFixture(moduleRef);
|
||||
profileRepositoryFixture = new ProfileRepositoryFixture(moduleRef);
|
||||
|
||||
org = await organizationsRepositoryFixture.create({
|
||||
name: "Test org 4",
|
||||
isOrganization: true,
|
||||
});
|
||||
|
||||
team = await organizationsRepositoryFixture.create({
|
||||
name: "Test org 4 team",
|
||||
isOrganization: false,
|
||||
parent: { connect: { id: org.id } },
|
||||
});
|
||||
|
||||
user = await userRepositoryFixture.create({
|
||||
email: authEmail,
|
||||
username: authEmail,
|
||||
organization: { connect: { id: org.id } },
|
||||
});
|
||||
|
||||
await profileRepositoryFixture.create({
|
||||
uid: `usr-${user.id}`,
|
||||
username: authEmail,
|
||||
organization: {
|
||||
connect: {
|
||||
id: org.id,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
connect: {
|
||||
id: user.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await membershipFixtures.addUserToOrg(user, org, "ADMIN", true);
|
||||
|
||||
await eventTypesRepositoryFixture.createTeamEventType({
|
||||
schedulingType: "COLLECTIVE",
|
||||
team: {
|
||||
connect: { id: team.id },
|
||||
},
|
||||
title: "Collective Event Type",
|
||||
slug: "collective-event-type",
|
||||
length: 30,
|
||||
assignAllTeamMembers: true,
|
||||
bookingFields: [],
|
||||
locations: [],
|
||||
});
|
||||
|
||||
managedEventType = await eventTypesRepositoryFixture.createTeamEventType({
|
||||
schedulingType: "MANAGED",
|
||||
team: {
|
||||
connect: { id: team.id },
|
||||
},
|
||||
title: "Managed Event Type",
|
||||
slug: "managed-event-type",
|
||||
length: 60,
|
||||
assignAllTeamMembers: true,
|
||||
bookingFields: [],
|
||||
locations: [],
|
||||
});
|
||||
|
||||
app = moduleRef.createNestApplication();
|
||||
bootstrap(app as NestExpressApplication);
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(userRepositoryFixture).toBeDefined();
|
||||
expect(organizationsRepositoryFixture).toBeDefined();
|
||||
expect(user).toBeDefined();
|
||||
expect(org).toBeDefined();
|
||||
});
|
||||
|
||||
it("should create a new org user with team event-types", async () => {
|
||||
const newOrgUser = {
|
||||
email: "new-org-member-d@org.com",
|
||||
organizationRole: "MEMBER",
|
||||
autoAccept: true,
|
||||
};
|
||||
|
||||
const { body } = await request(app.getHttpServer())
|
||||
.post(`/v2/organizations/${org.id}/users`)
|
||||
.send({
|
||||
email: newOrgUser.email,
|
||||
})
|
||||
.set("Content-Type", "application/json")
|
||||
.set("Accept", "application/json");
|
||||
|
||||
const userData = body.data;
|
||||
expect(body.status).toBe(SUCCESS_STATUS);
|
||||
userHasCorrectEventTypes(userData.id);
|
||||
createdUser = userData;
|
||||
teamHasCorrectEventTypes(team.id);
|
||||
});
|
||||
|
||||
async function userHasCorrectEventTypes(userId: number) {
|
||||
const eventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(userId);
|
||||
|
||||
expect(eventTypes?.length).toEqual(1);
|
||||
|
||||
// note(Lauris): managed event-types with assignAllTeamMembers: true
|
||||
expect(eventTypes?.find((eventType) => eventType.slug === managedEventType.slug)).toBeTruthy();
|
||||
}
|
||||
|
||||
async function teamHasCorrectEventTypes(teamId: number) {
|
||||
const eventTypes = await eventTypesRepositoryFixture.getAllTeamEventTypes(teamId);
|
||||
|
||||
expect(eventTypes?.length).toEqual(2);
|
||||
|
||||
// note(Lauris): managed event-types with assignAllTeamMembers: true
|
||||
expect(eventTypes?.find((eventType) => eventType.slug === managedEventType.slug)).toBeTruthy();
|
||||
|
||||
// note(Lauris): check if managed user added to collective event-type hosts given that it has assignAllTeamMembers: true
|
||||
const collective = eventTypes?.find((eventType) => eventType.schedulingType === "COLLECTIVE");
|
||||
expect(collective).toBeTruthy();
|
||||
expect(collective?.hosts).toBeDefined();
|
||||
expect(collective?.hosts?.length).toEqual(1);
|
||||
expect(collective?.hosts[0].userId).toEqual(createdUser.id);
|
||||
}
|
||||
|
||||
afterAll(async () => {
|
||||
// await membershipFixtures.delete(membership.id);
|
||||
await userRepositoryFixture.deleteByEmail(user.email);
|
||||
await userRepositoryFixture.deleteByEmail(createdUser.email);
|
||||
await organizationsRepositoryFixture.delete(org.id);
|
||||
await app.close();
|
||||
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,4 +72,8 @@ export class CreateOrgTeamDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly weekStart?: string = "Sunday";
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
readonly autoAcceptCreator?: boolean = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { IsBoolean, IsOptional, IsString, IsUrl, Length } from "class-validator";
|
||||
|
||||
export class UpdateOrgTeamDto {
|
||||
@IsString()
|
||||
@Length(1)
|
||||
readonly name?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly slug?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUrl()
|
||||
readonly logoUrl?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUrl()
|
||||
readonly calVideoLogo?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUrl()
|
||||
readonly appLogo?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUrl()
|
||||
readonly appIconLogo?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly bio?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
readonly hideBranding?: boolean = false;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
readonly isPrivate?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
readonly hideBookATeamMember?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly metadata?: string; // Assuming metadata is a JSON string. Adjust accordingly if it's a nested object.
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly theme?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly brandColor?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly darkBrandColor?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUrl()
|
||||
readonly bannerUrl?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly timeFormat?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly timeZone?: string = "Europe/London";
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
readonly weekStart?: string = "Sunday";
|
||||
}
|
||||
+29
-1
@@ -1,4 +1,5 @@
|
||||
import { CreateOrgTeamDto } from "@/modules/organizations/inputs/create-organization-team.input";
|
||||
import { UpdateOrgTeamDto } from "@/modules/organizations/inputs/update-organization-team.input";
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@@ -16,6 +17,14 @@ export class OrganizationsTeamsRepository {
|
||||
});
|
||||
}
|
||||
|
||||
async findOrgTeams(organizationId: number) {
|
||||
return this.dbRead.prisma.team.findMany({
|
||||
where: {
|
||||
parentId: organizationId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async deleteOrgTeam(organizationId: number, teamId: number) {
|
||||
return this.dbRead.prisma.team.delete({
|
||||
where: {
|
||||
@@ -32,7 +41,26 @@ export class OrganizationsTeamsRepository {
|
||||
});
|
||||
}
|
||||
|
||||
async updateOrgTeam(organizationId: number, teamId: number, data: CreateOrgTeamDto) {
|
||||
async createPlatformOrgTeam(organizationId: number, oAuthClientId: string, data: CreateOrgTeamDto) {
|
||||
return this.dbRead.prisma.team.create({
|
||||
data: {
|
||||
...data,
|
||||
parentId: organizationId,
|
||||
createdByOAuthClientId: oAuthClientId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getPlatformOrgTeams(organizationId: number, oAuthClientId: string) {
|
||||
return this.dbRead.prisma.team.findMany({
|
||||
where: {
|
||||
parentId: organizationId,
|
||||
createdByOAuthClientId: oAuthClientId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async updateOrgTeam(organizationId: number, teamId: number, data: UpdateOrgTeamDto) {
|
||||
return this.dbRead.prisma.team.update({
|
||||
data: { ...data },
|
||||
where: { id: teamId, parentId: organizationId, isOrganization: false },
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
|
||||
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.21";
|
||||
import { createEventType, updateEventType } from "@calcom/platform-libraries-0.0.22";
|
||||
import {
|
||||
CreateTeamEventTypeInput_2024_06_14,
|
||||
UpdateTeamEventTypeInput_2024_06_14,
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
|
||||
import { CreateOrgTeamDto } from "@/modules/organizations/inputs/create-organization-team.input";
|
||||
import { UpdateOrgTeamDto } from "@/modules/organizations/inputs/update-organization-team.input";
|
||||
import { OrganizationsTeamsRepository } from "@/modules/organizations/repositories/organizations-teams.repository";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { updateNewTeamMemberEventTypes } from "@calcom/platform-libraries-0.0.22";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsTeamsService {
|
||||
constructor(
|
||||
@@ -31,16 +34,58 @@ export class OrganizationsTeamsService {
|
||||
return team;
|
||||
}
|
||||
|
||||
async updateOrgTeam(organizationId: number, teamId: number, data: CreateOrgTeamDto) {
|
||||
async updateOrgTeam(organizationId: number, teamId: number, data: UpdateOrgTeamDto) {
|
||||
const team = await this.organizationsTeamRepository.updateOrgTeam(organizationId, teamId, data);
|
||||
return team;
|
||||
}
|
||||
|
||||
async createOrgTeam(organizationId: number, data: CreateOrgTeamDto, user: UserWithProfile) {
|
||||
const team = await this.organizationsTeamRepository.createOrgTeam(organizationId, data);
|
||||
const { autoAcceptCreator, ...rest } = data;
|
||||
|
||||
const team = await this.organizationsTeamRepository.createOrgTeam(organizationId, rest);
|
||||
|
||||
if (user.role !== "ADMIN") {
|
||||
await this.membershipsRepository.createMembership(team.id, user.id, "OWNER", true);
|
||||
await this.membershipsRepository.createMembership(team.id, user.id, "OWNER", !!autoAcceptCreator);
|
||||
}
|
||||
return team;
|
||||
}
|
||||
|
||||
async createPlatformOrgTeam(
|
||||
organizationId: number,
|
||||
oAuthClientId: string,
|
||||
data: CreateOrgTeamDto,
|
||||
user: UserWithProfile
|
||||
) {
|
||||
const { autoAcceptCreator, ...rest } = data;
|
||||
|
||||
const team = await this.organizationsTeamRepository.createPlatformOrgTeam(
|
||||
organizationId,
|
||||
oAuthClientId,
|
||||
rest
|
||||
);
|
||||
|
||||
if (user.role !== "ADMIN") {
|
||||
await this.membershipsRepository.createMembership(team.id, user.id, "OWNER", !!autoAcceptCreator);
|
||||
}
|
||||
return team;
|
||||
}
|
||||
|
||||
async addUserToTeamEvents(userId: number, organizationId: number) {
|
||||
const orgTeams = await this.organizationsTeamRepository.findOrgTeams(organizationId);
|
||||
|
||||
for (const team of orgTeams) {
|
||||
await updateNewTeamMemberEventTypes(userId, team.id);
|
||||
}
|
||||
}
|
||||
|
||||
async addUserToPlatformTeamEvents(userId: number, organizationId: number, oAuthClientId: string) {
|
||||
const oAuthClientTeams = await this.organizationsTeamRepository.getPlatformOrgTeams(
|
||||
organizationId,
|
||||
oAuthClientId
|
||||
);
|
||||
|
||||
for (const team of oAuthClientTeams) {
|
||||
await updateNewTeamMemberEventTypes(userId, team.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,19 @@ import { EmailService } from "@/modules/email/email.service";
|
||||
import { CreateOrganizationUserInput } from "@/modules/organizations/inputs/create-organization-user.input";
|
||||
import { UpdateOrganizationUserInput } from "@/modules/organizations/inputs/update-organization-user.input";
|
||||
import { OrganizationsUsersRepository } from "@/modules/organizations/repositories/organizations-users.repository";
|
||||
import { OrganizationsTeamsService } from "@/modules/organizations/services/organizations-teams.service";
|
||||
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.21";
|
||||
import { createNewUsersConnectToOrgIfExists } from "@calcom/platform-libraries-0.0.22";
|
||||
import { Team } from "@calcom/prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsUsersService {
|
||||
constructor(
|
||||
private readonly organizationsUsersRepository: OrganizationsUsersRepository,
|
||||
private readonly organizationsTeamsService: OrganizationsTeamsService,
|
||||
private readonly emailService: EmailService
|
||||
) {}
|
||||
|
||||
@@ -77,6 +79,8 @@ export class OrganizationsUsersService {
|
||||
updateUserBody
|
||||
);
|
||||
|
||||
await this.organizationsTeamsService.addUserToTeamEvents(user.id, org.id);
|
||||
|
||||
// Need to send email to new user to create password
|
||||
await this.emailService.sendSignupToOrganizationEmail({
|
||||
usernameOrEmail,
|
||||
|
||||
@@ -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.21";
|
||||
import type { AvailableSlotsType } from "@calcom/platform-libraries-0.0.21";
|
||||
import { getAvailableSlots } from "@calcom/platform-libraries-0.0.22";
|
||||
import type { AvailableSlotsType } from "@calcom/platform-libraries-0.0.22";
|
||||
import { RemoveSelectedSlotInput, ReserveSlotInput } from "@calcom/platform-types";
|
||||
import { ApiResponse, GetAvailableSlotsInput } from "@calcom/platform-types";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { DateTime } from "luxon";
|
||||
|
||||
import { MINUTES_TO_BOOK } from "@calcom/platform-libraries-0.0.21";
|
||||
import { MINUTES_TO_BOOK } from "@calcom/platform-libraries-0.0.22";
|
||||
import { ReserveSlotInput } from "@calcom/platform-types";
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Controller, Get } from "@nestjs/common";
|
||||
import { ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { CityTimezones } from "@calcom/platform-libraries-0.0.21";
|
||||
import type { CityTimezones } from "@calcom/platform-libraries-0.0.22";
|
||||
import { ApiResponse } from "@calcom/platform-types";
|
||||
|
||||
@Controller({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { RedisService } from "@/modules/redis/redis.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { cityTimezonesHandler } from "@calcom/platform-libraries-0.0.21";
|
||||
import type { CityTimezones } from "@calcom/platform-libraries-0.0.21";
|
||||
import { cityTimezonesHandler } from "@calcom/platform-libraries-0.0.22";
|
||||
import type { CityTimezones } from "@calcom/platform-libraries-0.0.22";
|
||||
|
||||
@Injectable()
|
||||
export class TimezonesService {
|
||||
|
||||
@@ -962,6 +962,14 @@
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x-cal-client-id",
|
||||
"required": true,
|
||||
"in": "header",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
@@ -1126,7 +1134,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateOrgTeamDto"
|
||||
"$ref": "#/components/schemas/UpdateOrgTeamDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5224,6 +5232,69 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"UpdateOrgTeamDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"slug": {
|
||||
"type": "string"
|
||||
},
|
||||
"logoUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"calVideoLogo": {
|
||||
"type": "string"
|
||||
},
|
||||
"appLogo": {
|
||||
"type": "string"
|
||||
},
|
||||
"appIconLogo": {
|
||||
"type": "string"
|
||||
},
|
||||
"bio": {
|
||||
"type": "string"
|
||||
},
|
||||
"hideBranding": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"isPrivate": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hideBookATeamMember": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metadata": {
|
||||
"type": "string"
|
||||
},
|
||||
"theme": {
|
||||
"type": "string"
|
||||
},
|
||||
"brandColor": {
|
||||
"type": "string"
|
||||
},
|
||||
"darkBrandColor": {
|
||||
"type": "string"
|
||||
},
|
||||
"bannerUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeFormat": {
|
||||
"type": "number"
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "string",
|
||||
"default": "Europe/London"
|
||||
},
|
||||
"weekStart": {
|
||||
"type": "string",
|
||||
"default": "Sunday"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateOrgTeamDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5284,6 +5355,10 @@
|
||||
"weekStart": {
|
||||
"type": "string",
|
||||
"default": "Sunday"
|
||||
},
|
||||
"autoAcceptCreator": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
@@ -4,6 +4,8 @@ import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { TestingModule } from "@nestjs/testing";
|
||||
import { EventType } from "@prisma/client";
|
||||
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
|
||||
export class EventTypesRepositoryFixture {
|
||||
private primaReadClient: PrismaReadService["prisma"];
|
||||
private prismaWriteClient: PrismaWriteService["prisma"];
|
||||
@@ -26,6 +28,9 @@ export class EventTypesRepositoryFixture {
|
||||
where: {
|
||||
teamId,
|
||||
},
|
||||
include: {
|
||||
hosts: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,6 +46,10 @@ export class EventTypesRepositoryFixture {
|
||||
});
|
||||
}
|
||||
|
||||
async createTeamEventType(data: Prisma.EventTypeCreateInput) {
|
||||
return this.prismaWriteClient.eventType.create({ data });
|
||||
}
|
||||
|
||||
async delete(eventTypeId: EventType["id"]) {
|
||||
return this.prismaWriteClient.eventType.delete({ where: { id: eventTypeId } });
|
||||
}
|
||||
|
||||
@@ -23,4 +23,13 @@ export class TeamRepositoryFixture {
|
||||
async delete(teamId: Team["id"]) {
|
||||
return this.prismaWriteClient.team.delete({ where: { id: teamId } });
|
||||
}
|
||||
|
||||
async getPlatformOrgTeams(organizationId: number, oAuthClientId: string) {
|
||||
return this.primaReadClient.team.findMany({
|
||||
where: {
|
||||
parentId: organizationId,
|
||||
createdByOAuthClientId: oAuthClientId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1574,6 +1574,7 @@ async function createOrg(
|
||||
metadata: {
|
||||
...(data.metadata || {}),
|
||||
},
|
||||
createdByOAuthClient: undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1591,6 +1592,7 @@ async function createTeamOutsideOrg(
|
||||
...(data.metadata || {}),
|
||||
isOrganization: false,
|
||||
},
|
||||
createdByOAuthClient: undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.0.22
|
||||
Export `updateNewTeamMemberEventTypes` from `"@calcom/lib/server/queries"` so that we can assign newly created organizations
|
||||
teams members to event-types that have been marked as "assign all team members"
|
||||
|
||||
## 0.0.20
|
||||
In event-types create handler (packages/trpc/server/routers/viewer/eventTypes/create.handler.ts) enable passing scheduleId so that when an event type is created it can be connected
|
||||
to a specific schedule.
|
||||
|
||||
@@ -109,3 +109,5 @@ export { CalendarService };
|
||||
export { getCalendar };
|
||||
|
||||
export { getTranslation };
|
||||
|
||||
export { updateNewTeamMemberEventTypes } from "@calcom/lib/server/queries";
|
||||
|
||||
+13
-1
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty as DocsProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { Type, Transform } from "class-transformer";
|
||||
import {
|
||||
IsString,
|
||||
IsInt,
|
||||
@@ -148,6 +148,18 @@ export class CreateTeamEventTypeInput_2024_06_14 {
|
||||
@DocsProperty()
|
||||
afterEventBuffer?: number;
|
||||
|
||||
@Transform(({ value }) => {
|
||||
if (value === "collective") {
|
||||
return SchedulingType.COLLECTIVE;
|
||||
}
|
||||
if (value === "roundRobin") {
|
||||
return SchedulingType.ROUND_ROBIN;
|
||||
}
|
||||
if (value === "managed") {
|
||||
return SchedulingType.MANAGED;
|
||||
}
|
||||
return value;
|
||||
})
|
||||
@IsEnum(SchedulingType)
|
||||
@DocsProperty()
|
||||
schedulingType!: keyof typeof SchedulingType;
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Team" ADD COLUMN "createdByOAuthClientId" TEXT;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Team" ADD CONSTRAINT "Team_createdByOAuthClientId_fkey" FOREIGN KEY ("createdByOAuthClientId") REFERENCES "PlatformOAuthClient"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Team" DROP CONSTRAINT "Team_createdByOAuthClientId_fkey";
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Team" ADD CONSTRAINT "Team_createdByOAuthClientId_fkey" FOREIGN KEY ("createdByOAuthClientId") REFERENCES "PlatformOAuthClient"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -359,55 +359,59 @@ model Profile {
|
||||
}
|
||||
|
||||
model Team {
|
||||
id Int @id @default(autoincrement())
|
||||
id Int @id @default(autoincrement())
|
||||
/// @zod.min(1)
|
||||
name String
|
||||
name String
|
||||
/// @zod.min(1)
|
||||
slug String?
|
||||
logoUrl String?
|
||||
calVideoLogo String?
|
||||
appLogo String?
|
||||
appIconLogo String?
|
||||
bio String?
|
||||
hideBranding Boolean @default(false)
|
||||
isPrivate Boolean @default(false)
|
||||
hideBookATeamMember Boolean @default(false)
|
||||
members Membership[]
|
||||
eventTypes EventType[]
|
||||
workflows Workflow[]
|
||||
createdAt DateTime @default(now())
|
||||
slug String?
|
||||
logoUrl String?
|
||||
calVideoLogo String?
|
||||
appLogo String?
|
||||
appIconLogo String?
|
||||
bio String?
|
||||
hideBranding Boolean @default(false)
|
||||
isPrivate Boolean @default(false)
|
||||
hideBookATeamMember Boolean @default(false)
|
||||
members Membership[]
|
||||
eventTypes EventType[]
|
||||
workflows Workflow[]
|
||||
createdAt DateTime @default(now())
|
||||
/// @zod.custom(imports.teamMetadataSchema)
|
||||
metadata Json?
|
||||
theme String?
|
||||
brandColor String?
|
||||
darkBrandColor String?
|
||||
verifiedNumbers VerifiedNumber[]
|
||||
verifiedEmails VerifiedEmail[]
|
||||
bannerUrl String?
|
||||
parentId Int?
|
||||
parent Team? @relation("organization", fields: [parentId], references: [id], onDelete: Cascade)
|
||||
children Team[] @relation("organization")
|
||||
orgUsers User[] @relation("scope")
|
||||
inviteTokens VerificationToken[]
|
||||
webhooks Webhook[]
|
||||
timeFormat Int?
|
||||
timeZone String @default("Europe/London")
|
||||
weekStart String @default("Sunday")
|
||||
routingForms App_RoutingForms_Form[]
|
||||
apiKeys ApiKey[]
|
||||
credentials Credential[]
|
||||
accessCodes AccessCode[]
|
||||
isOrganization Boolean @default(false)
|
||||
organizationSettings OrganizationSettings?
|
||||
instantMeetingTokens InstantMeetingToken[]
|
||||
orgProfiles Profile[]
|
||||
pendingPayment Boolean @default(false)
|
||||
dsyncTeamGroupMapping DSyncTeamGroupMapping[]
|
||||
isPlatform Boolean @default(false)
|
||||
platformOAuthClient PlatformOAuthClient[]
|
||||
smsLockState SMSLockState @default(UNLOCKED)
|
||||
platformBilling PlatformBilling?
|
||||
activeOrgWorkflows WorkflowsOnTeams[]
|
||||
metadata Json?
|
||||
theme String?
|
||||
brandColor String?
|
||||
darkBrandColor String?
|
||||
verifiedNumbers VerifiedNumber[]
|
||||
verifiedEmails VerifiedEmail[]
|
||||
bannerUrl String?
|
||||
parentId Int?
|
||||
parent Team? @relation("organization", fields: [parentId], references: [id], onDelete: Cascade)
|
||||
children Team[] @relation("organization")
|
||||
orgUsers User[] @relation("scope")
|
||||
inviteTokens VerificationToken[]
|
||||
webhooks Webhook[]
|
||||
timeFormat Int?
|
||||
timeZone String @default("Europe/London")
|
||||
weekStart String @default("Sunday")
|
||||
routingForms App_RoutingForms_Form[]
|
||||
apiKeys ApiKey[]
|
||||
credentials Credential[]
|
||||
accessCodes AccessCode[]
|
||||
isOrganization Boolean @default(false)
|
||||
organizationSettings OrganizationSettings?
|
||||
instantMeetingTokens InstantMeetingToken[]
|
||||
orgProfiles Profile[]
|
||||
pendingPayment Boolean @default(false)
|
||||
dsyncTeamGroupMapping DSyncTeamGroupMapping[]
|
||||
isPlatform Boolean @default(false)
|
||||
// Organization's OAuth clients. Organization has them but a team does not.
|
||||
platformOAuthClient PlatformOAuthClient[]
|
||||
// OAuth client used to create team of an organization. Team has it but organization does not.
|
||||
createdByOAuthClient PlatformOAuthClient? @relation("CreatedByOAuthClient", fields: [createdByOAuthClientId], references: [id], onDelete: Cascade)
|
||||
createdByOAuthClientId String?
|
||||
smsLockState SMSLockState @default(UNLOCKED)
|
||||
platformBilling PlatformBilling?
|
||||
activeOrgWorkflows WorkflowsOnTeams[]
|
||||
|
||||
@@unique([slug, parentId])
|
||||
@@index([parentId])
|
||||
@@ -1287,6 +1291,7 @@ model PlatformOAuthClient {
|
||||
redirectUris String[]
|
||||
organizationId Int
|
||||
organization Team @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
teams Team[] @relation("CreatedByOAuthClient")
|
||||
|
||||
accessTokens AccessToken[]
|
||||
refreshToken RefreshToken[]
|
||||
|
||||
@@ -4066,12 +4066,13 @@ __metadata:
|
||||
dependencies:
|
||||
"@calcom/platform-constants": "*"
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2"
|
||||
"@calcom/platform-libraries-0.0.20": "npm:@calcom/platform-libraries@0.0.20"
|
||||
"@calcom/platform-libraries-0.0.22": "npm:@calcom/platform-libraries@0.0.22"
|
||||
"@calcom/platform-types": "*"
|
||||
"@calcom/platform-utils": "*"
|
||||
"@calcom/prisma": "*"
|
||||
"@golevelup/ts-jest": ^0.4.0
|
||||
"@microsoft/microsoft-graph-types-beta": ^0.42.0-preview
|
||||
"@nestjs/bull": ^10.1.1
|
||||
"@nestjs/cli": ^10.0.0
|
||||
"@nestjs/common": ^10.0.0
|
||||
"@nestjs/config": ^3.1.1
|
||||
@@ -4093,6 +4094,7 @@ __metadata:
|
||||
"@types/passport-jwt": ^3.0.13
|
||||
"@types/supertest": ^2.0.12
|
||||
body-parser: ^1.20.2
|
||||
bull: ^4.12.4
|
||||
class-transformer: ^0.5.1
|
||||
class-validator: ^0.14.0
|
||||
cookie-parser: ^1.4.6
|
||||
@@ -4216,7 +4218,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:
|
||||
@@ -5025,14 +5027,14 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/platform-libraries-0.0.20@npm:@calcom/platform-libraries@0.0.20":
|
||||
version: 0.0.20
|
||||
resolution: "@calcom/platform-libraries@npm:0.0.20"
|
||||
"@calcom/platform-libraries-0.0.22@npm:@calcom/platform-libraries@0.0.22":
|
||||
version: 0.0.22
|
||||
resolution: "@calcom/platform-libraries@npm:0.0.22"
|
||||
dependencies:
|
||||
"@calcom/core": "*"
|
||||
"@calcom/features": "*"
|
||||
"@calcom/lib": "*"
|
||||
checksum: f17e9bd51429a1a70240944b8f3836be41790a8c0eba34ddeaa7336c4f98503c0ff8c70c4d79b15809895c3af8462cbf10cff14ca4ba0453cc751febf4dd86cb
|
||||
checksum: 137238600e8c19e5dcd77f340addb5e1284c5dee46b4dfb20c8fb37808251d1752a6c870120f394093c3d503987820c20a10b9a6f2bd4221fbf9109f71a08d87
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5673,7 +5675,6 @@ __metadata:
|
||||
dependencies:
|
||||
"@algora/sdk": ^0.1.2
|
||||
"@calcom/app-store": "*"
|
||||
"@calcom/atoms": "workspace:^"
|
||||
"@calcom/config": "*"
|
||||
"@calcom/dayjs": "*"
|
||||
"@calcom/embed-react": "workspace:^"
|
||||
@@ -5719,7 +5720,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
|
||||
@@ -5732,7 +5732,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
|
||||
@@ -5742,7 +5741,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
|
||||
@@ -5754,7 +5753,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
|
||||
@@ -5764,10 +5763,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
|
||||
@@ -9497,6 +9494,48 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:3.0.3"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-x64@npm:3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@msgpackr-extract/msgpackr-extract-darwin-x64@npm:3.0.3"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm64@npm:3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@msgpackr-extract/msgpackr-extract-linux-arm64@npm:3.0.3"
|
||||
conditions: os=linux & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm@npm:3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@msgpackr-extract/msgpackr-extract-linux-arm@npm:3.0.3"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-linux-x64@npm:3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@msgpackr-extract/msgpackr-extract-linux-x64@npm:3.0.3"
|
||||
conditions: os=linux & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-win32-x64@npm:3.0.3":
|
||||
version: 3.0.3
|
||||
resolution: "@msgpackr-extract/msgpackr-extract-win32-x64@npm:3.0.3"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mswjs/cookies@npm:^0.2.0":
|
||||
version: 0.2.1
|
||||
resolution: "@mswjs/cookies@npm:0.2.1"
|
||||
@@ -9521,59 +9560,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/mux-player-react@npm:*":
|
||||
version: 2.8.0
|
||||
resolution: "@mux/mux-player-react@npm:2.8.0"
|
||||
dependencies:
|
||||
"@mux/mux-player": 2.8.0
|
||||
"@mux/playback-core": 0.25.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: b4891a151ff92bbee3b9d2e0411c21be07b976c30f6e13c30b30cda97eeb5d4a88bb3d78fd58dac447b05bb12563234a9a5fbba3bdf79e0c274575cf9bb020cd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/mux-player@npm:2.8.0":
|
||||
version: 2.8.0
|
||||
resolution: "@mux/mux-player@npm:2.8.0"
|
||||
dependencies:
|
||||
"@mux/mux-video": 0.20.0
|
||||
"@mux/playback-core": 0.25.0
|
||||
media-chrome: ~3.2.3
|
||||
checksum: 6a8e410456a325c2e59ef3ebb4f3efba69596a4df3e38e9ccb332af23fe16c571a8271c51e97ea5f003352f09f63fdb311ff548c0b2f613b7ca4c47fa68fcade
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/mux-video@npm:0.20.0":
|
||||
version: 0.20.0
|
||||
resolution: "@mux/mux-video@npm:0.20.0"
|
||||
dependencies:
|
||||
"@mux/playback-core": 0.25.0
|
||||
castable-video: ~1.0.9
|
||||
custom-media-element: ~1.3.1
|
||||
media-tracks: ~0.3.2
|
||||
checksum: 2f316a6697ff63dbcc5428216600ced1db14e22c195567c69e826b29b2752b9aeee785f073bc2eef71d7422b696370608d9d081b8e24b5332dfeb57bf0839791
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/playback-core@npm:0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "@mux/playback-core@npm:0.25.0"
|
||||
dependencies:
|
||||
hls.js: ~1.5.11
|
||||
mux-embed: ~5.2.0
|
||||
checksum: 37175985f7ec7df0b2f24e9b6e3df9c39f94da81b0f1e59b989dd9d04d9451dae2ea6e06d4208a673e532ea2351c39c2d2ec0e149cde60a9a09b9dbd00ea2866
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ndelangen/get-tarball@npm:^3.0.7":
|
||||
version: 3.0.9
|
||||
resolution: "@ndelangen/get-tarball@npm:3.0.9"
|
||||
@@ -9585,6 +9571,32 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nestjs/bull-shared@npm:^10.1.1":
|
||||
version: 10.1.1
|
||||
resolution: "@nestjs/bull-shared@npm:10.1.1"
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
peerDependencies:
|
||||
"@nestjs/common": ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
"@nestjs/core": ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
checksum: 492c6bfd8d77ded163913aa8fced3c6a52f8b6b40ae2e35b722cde98d89d3a0136497233ea8d60436cc842107cb61fc1f2a5ddc3fa01dd85aa68f08a350f8c47
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nestjs/bull@npm:^10.1.1":
|
||||
version: 10.1.1
|
||||
resolution: "@nestjs/bull@npm:10.1.1"
|
||||
dependencies:
|
||||
"@nestjs/bull-shared": ^10.1.1
|
||||
tslib: 2.6.2
|
||||
peerDependencies:
|
||||
"@nestjs/common": ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
"@nestjs/core": ^8.0.0 || ^9.0.0 || ^10.0.0
|
||||
bull: ^3.3 || ^4.0.0
|
||||
checksum: 3f3cf1a119324f2e7721fedc3d1484a60ffb55381a2d291040953770e0aded825cd14ee2a2526e68929f79fee56053ae9ac0858f8a427cbb11dbffb73191be36
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nestjs/cli@npm:^10.0.0":
|
||||
version: 10.3.2
|
||||
resolution: "@nestjs/cli@npm:10.3.2"
|
||||
@@ -21178,6 +21190,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bull@npm:^4.12.4":
|
||||
version: 4.15.1
|
||||
resolution: "bull@npm:4.15.1"
|
||||
dependencies:
|
||||
cron-parser: ^4.2.1
|
||||
get-port: ^5.1.1
|
||||
ioredis: ^5.3.2
|
||||
lodash: ^4.17.21
|
||||
msgpackr: ^1.10.1
|
||||
semver: ^7.5.2
|
||||
uuid: ^8.3.0
|
||||
checksum: 9ac743e32bd68d6f52ec0dcb3696ad4d81ecd994faddc1b6fe48ceb5047ffaae4e45da1211b3b68f6c1dfd719c84405cc132c611fccd0a92ef8c44217b81a82f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bundle-name@npm:^4.1.0":
|
||||
version: 4.1.0
|
||||
resolution: "bundle-name@npm:4.1.0"
|
||||
@@ -21335,6 +21362,7 @@ __metadata:
|
||||
husky: ^8.0.0
|
||||
i18n-unused: ^0.13.0
|
||||
jest-diff: ^29.5.0
|
||||
jest-summarizing-reporter: ^1.1.4
|
||||
jsdom: ^22.0.0
|
||||
lint-staged: ^12.5.0
|
||||
mailhog: ^4.16.0
|
||||
@@ -21569,15 +21597,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"castable-video@npm:~1.0.9":
|
||||
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"
|
||||
@@ -22042,15 +22061,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"
|
||||
@@ -22323,13 +22333,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"
|
||||
@@ -23289,6 +23292,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cron-parser@npm:^4.2.1":
|
||||
version: 4.9.0
|
||||
resolution: "cron-parser@npm:4.9.0"
|
||||
dependencies:
|
||||
luxon: ^3.2.1
|
||||
checksum: 3cf248fc5cae6c19ec7124962b1cd84b76f02b9bc4f58976b3bd07624db3ef10aaf1548efcc2d2dcdab0dad4f12029d640a55ecce05ea5e1596af9db585502cf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-env@npm:^7.0.3":
|
||||
version: 7.0.3
|
||||
resolution: "cross-env@npm:7.0.3"
|
||||
@@ -23635,13 +23647,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"custom-media-element@npm:~1.3.1, 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"
|
||||
@@ -24334,6 +24339,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"detect-libc@npm:^2.0.1":
|
||||
version: 2.0.3
|
||||
resolution: "detect-libc@npm:2.0.3"
|
||||
checksum: 2ba6a939ae55f189aea996ac67afceb650413c7a34726ee92c40fb0deb2400d57ef94631a8a3f052055eea7efb0f99a9b5e6ce923415daa3e68221f963cfc27d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"detect-newline@npm:^3.0.0":
|
||||
version: 3.1.0
|
||||
resolution: "detect-newline@npm:3.1.0"
|
||||
@@ -27689,26 +27701,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"framer-motion@npm:^11.0.25":
|
||||
version: 11.3.12
|
||||
resolution: "framer-motion@npm:11.3.12"
|
||||
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: d13fa5fd2a21e73846a1171b8e6cad0be214b48f0c9b91070397975977758a98c66ea55d3e8dc027d959831027d76d0d8044cf41c49942cc3362a7b0cce7d4a0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fresh@npm:0.5.2, fresh@npm:^0.5.2":
|
||||
version: 0.5.2
|
||||
resolution: "fresh@npm:0.5.2"
|
||||
@@ -29381,13 +29373,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hls.js@npm:~1.5.11":
|
||||
version: 1.5.13
|
||||
resolution: "hls.js@npm:1.5.13"
|
||||
checksum: 534b48b18638fefe7788fd31d92b0b4e3820271b470fbd18c29cd46d51e6381b6f011d732f6196d4cda3148c81d8cb7740e1d1d0f2da0031e808b468198142f3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hmac-drbg@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "hmac-drbg@npm:1.0.1"
|
||||
@@ -32080,6 +32065,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jest-summarizing-reporter@npm:^1.1.4":
|
||||
version: 1.1.4
|
||||
resolution: "jest-summarizing-reporter@npm:1.1.4"
|
||||
checksum: 46be3e78146a86ba2b75b3e85f17b854f0da42587bf90e664b35d1b56cd51607c3a431da2c3b6a0a1fe5b3d3429ea493aedb51d2d7ce615919643e7e7dea3cbe
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0":
|
||||
version: 29.7.0
|
||||
resolution: "jest-util@npm:29.7.0"
|
||||
@@ -34208,6 +34200,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"
|
||||
@@ -34238,7 +34239,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"luxon@npm:^3.4.4":
|
||||
"luxon@npm:^3.2.1, luxon@npm:^3.4.4":
|
||||
version: 3.4.4
|
||||
resolution: "luxon@npm:3.4.4"
|
||||
checksum: 36c1f99c4796ee4bfddf7dc94fa87815add43ebc44c8934c924946260a58512f0fd2743a629302885df7f35ccbd2d13f178c15df046d0e3b6eb71db178f1c60c
|
||||
@@ -34777,20 +34778,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"media-chrome@npm:~3.2.3":
|
||||
version: 3.2.4
|
||||
resolution: "media-chrome@npm:3.2.4"
|
||||
checksum: 6401f509f4075cd7d02f8a479e81bcb084cd06104aa17fd7ebe6623bd171eaa52e1e1333c1895ad84c1f794ea3889cca13db52dd49b64129d67dd8be558d6eb2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"media-tracks@npm:~0.3.2":
|
||||
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"
|
||||
@@ -36062,6 +36049,49 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"msgpackr-extract@npm:^3.0.2":
|
||||
version: 3.0.3
|
||||
resolution: "msgpackr-extract@npm:3.0.3"
|
||||
dependencies:
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64": 3.0.3
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-x64": 3.0.3
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm": 3.0.3
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm64": 3.0.3
|
||||
"@msgpackr-extract/msgpackr-extract-linux-x64": 3.0.3
|
||||
"@msgpackr-extract/msgpackr-extract-win32-x64": 3.0.3
|
||||
node-gyp: latest
|
||||
node-gyp-build-optional-packages: 5.2.2
|
||||
dependenciesMeta:
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64":
|
||||
optional: true
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-x64":
|
||||
optional: true
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm":
|
||||
optional: true
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm64":
|
||||
optional: true
|
||||
"@msgpackr-extract/msgpackr-extract-linux-x64":
|
||||
optional: true
|
||||
"@msgpackr-extract/msgpackr-extract-win32-x64":
|
||||
optional: true
|
||||
bin:
|
||||
download-msgpackr-prebuilds: bin/download-prebuilds.js
|
||||
checksum: 3b5ae152821feff843380f0b091afbebd80bd224e644f4410abd33d05da3159eb8b0d45c7dcf7d5226ce1d5c71cd68052f066788f46ea7a3cd8791a1c740a079
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"msgpackr@npm:^1.10.1":
|
||||
version: 1.11.0
|
||||
resolution: "msgpackr@npm:1.11.0"
|
||||
dependencies:
|
||||
msgpackr-extract: ^3.0.2
|
||||
dependenciesMeta:
|
||||
msgpackr-extract:
|
||||
optional: true
|
||||
checksum: 20a1941e1a281c10a1d43d04349ae7a79bef1cbd0644f1e5acef7f98f6a6e6cd83388ee82689799f9e65623591b11f849ef2f86c8eac83492449bee5a2b055b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mssql@npm:10.0.2":
|
||||
version: 10.0.2
|
||||
resolution: "mssql@npm:10.0.2"
|
||||
@@ -36168,13 +36198,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,6 +36890,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp-build-optional-packages@npm:5.2.2":
|
||||
version: 5.2.2
|
||||
resolution: "node-gyp-build-optional-packages@npm:5.2.2"
|
||||
dependencies:
|
||||
detect-libc: ^2.0.1
|
||||
bin:
|
||||
node-gyp-build-optional-packages: bin.js
|
||||
node-gyp-build-optional-packages-optional: optional.js
|
||||
node-gyp-build-optional-packages-test: build-test.js
|
||||
checksum: 3c10d7380901ab5febcd153d2632917fe7507edb15a3405e9ef19801834a4c2162459a67b9944887f737f8718baeb4aaf0002c829a8214011930f2de80e4b42f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp@npm:latest":
|
||||
version: 9.3.1
|
||||
resolution: "node-gyp@npm:9.3.1"
|
||||
@@ -40483,21 +40519,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
|
||||
|
||||
@@ -40749,16 +40784,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-intersection-observer@npm:^9.4.3":
|
||||
version: 9.13.0
|
||||
resolution: "react-intersection-observer@npm:9.13.0"
|
||||
"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: ee2a163b078923c1556814834f83d7c3ea3e8a9d3ceef974351fd52afe12163518ec57cb2eb0f6544ac255ac4b64d2e7652bc5d60c255159c0f25bda57a565b6
|
||||
react: ^15.0.0 || ^16.0.0 || ^17.0.0|| ^18.0.0
|
||||
checksum: 7713fecfd1512c7f5a60f9f0bf15403b8f8bbd4110bcafaeaea6de36a0e0eb60368c3638f99e9c97b75ad8fc787ea48c241dcb5c694f821d7f2976f709082cc5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -40868,16 +40899,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-parallax-tilt@npm:^1.7.226":
|
||||
version: 1.7.232
|
||||
resolution: "react-parallax-tilt@npm:1.7.232"
|
||||
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: 8c866c9c06315aeaf1eddd4e5265db706e010d788667c337be552cbf8786e8b39f19cafc529be6c69d925e25b31705c52398e90bd89a805bf8914bbb46a8ebdb
|
||||
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"
|
||||
@@ -41292,18 +41313,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"
|
||||
@@ -43128,13 +43137,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"
|
||||
|
||||
Reference in New Issue
Block a user