Skip to content

Commit 5aec1c7

Browse files
authored
Merge branch 'main' into dub-folders
2 parents bffe9e0 + 4012098 commit 5aec1c7

File tree

76 files changed

+7845
-1375
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+7845
-1375
lines changed

.yarn/versions/3c2036fd.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
undecided:
2+
- calcom-monorepo
3+
- "@calcom/prisma"

apps/api/v2/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"helmet": "^7.1.0",
6262
"ioredis": "^5.3.2",
6363
"jsforce": "^1.11.0",
64+
"lodash": "^4.17.21",
6465
"luxon": "^3.4.4",
6566
"nest-winston": "^1.9.4",
6667
"next-auth": "^4.22.1",

apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/booking-fields.e2e-spec.ts

-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,6 @@ describe("Bookings Endpoints 2024-08-13", () => {
455455
// eslint-disable-next-line
456456
// @ts-ignore
457457
const data: GetSeatedBookingOutput_2024_08_13 = responseBody.data;
458-
console.log("asap data", JSON.stringify(data, null, 2));
459458
expect(data.attendees[0].name).toEqual(`${splitName.firstName} ${splitName.lastName}`);
460459
expect(data.attendees[0].bookingFieldsResponses.name).toEqual(splitName);
461460
} else {

apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ import { InputEventTransformed_2024_06_14 } from "@calcom/platform-types";
77

88
@Injectable()
99
export class EventTypesRepository_2024_06_14 {
10-
constructor(
11-
private readonly dbRead: PrismaReadService,
12-
private readonly dbWrite: PrismaWriteService,
13-
private usersService: UsersService
14-
) {}
10+
constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {}
1511

1612
async createUserEventType(
1713
userId: number,
@@ -47,6 +43,13 @@ export class EventTypesRepository_2024_06_14 {
4743
});
4844
}
4945

46+
async getEventTypeWithHosts(eventTypeId: number) {
47+
return this.dbRead.prisma.eventType.findUnique({
48+
where: { id: eventTypeId },
49+
include: { hosts: true },
50+
});
51+
}
52+
5053
async getUserEventType(userId: number, eventTypeId: number) {
5154
return this.dbRead.prisma.eventType.findFirst({
5255
where: {

apps/api/v2/src/ee/event-types/event-types_2024_06_14/outputs/create-phone-call.output.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApiProperty } from "@nestjs/swagger";
22
import { Type } from "class-transformer";
3-
import { IsEnum, IsString, ValidateNested } from "class-validator";
3+
import { IsEnum, IsString, ValidateNested, IsOptional } from "class-validator";
44

55
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
66

@@ -10,8 +10,9 @@ class Data {
1010
callId!: string;
1111

1212
@IsString()
13+
@IsOptional()
1314
@ApiProperty()
14-
agentId!: string;
15+
agentId?: string;
1516
}
1617

1718
export class CreatePhoneCallOutput {

apps/api/v2/src/ee/platform-endpoints-module.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { MeModule } from "@/ee/me/me.module";
88
import { ProviderModule } from "@/ee/provider/provider.module";
99
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
1010
import { SchedulesModule_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.module";
11-
import { SlotsModule } from "@/modules/slots/slots.module";
11+
import { SlotsModule_2024_04_15 } from "@/modules/slots/slots-2024-04-15/slots.module";
12+
import { SlotsModule_2024_09_04 } from "@/modules/slots/slots-2024-09-04/slots.module";
1213
import { TeamsEventTypesModule } from "@/modules/teams/event-types/teams-event-types.module";
1314
import { TeamsMembershipsModule } from "@/modules/teams/memberships/teams-memberships.module";
1415
import { TeamsModule } from "@/modules/teams/teams/teams.module";
@@ -29,7 +30,8 @@ import { Module } from "@nestjs/common";
2930
BookingsModule_2024_04_15,
3031
BookingsModule_2024_08_13,
3132
TeamsMembershipsModule,
32-
SlotsModule,
33+
SlotsModule_2024_04_15,
34+
SlotsModule_2024_09_04,
3335
TeamsModule,
3436
],
3537
})

apps/api/v2/src/lib/api-versions.ts

+3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@ import {
66
VERSION_2024_06_11,
77
VERSION_2024_06_14,
88
VERSION_2024_08_13,
9+
VERSION_2024_09_04,
910
} from "@calcom/platform-constants";
1011

1112
export const API_VERSIONS_VALUES: VersionValue = API_VERSIONS as unknown as VersionValue;
1213
export const VERSION_2024_06_14_VALUE: VersionValue = VERSION_2024_06_14 as unknown as VersionValue;
1314
export const VERSION_2024_06_11_VALUE: VersionValue = VERSION_2024_06_11 as unknown as VersionValue;
1415
export const VERSION_2024_04_15_VALUE: VersionValue = VERSION_2024_04_15 as unknown as VersionValue;
1516
export const VERSION_2024_08_13_VALUE: VersionValue = VERSION_2024_08_13 as unknown as VersionValue;
17+
export const VERSION_2024_09_04_VALUE: VersionValue = VERSION_2024_09_04 as unknown as VersionValue;
1618

1719
export { VERSION_2024_04_15 };
1820
export { VERSION_2024_06_11 };
1921
export { VERSION_2024_06_14 };
2022
export { VERSION_2024_08_13 };
23+
export { VERSION_2024_09_04 };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { ApiAuthGuardUser } from "@/modules/auth/strategies/api-auth/api-auth.strategy";
2+
import { ExecutionContext } from "@nestjs/common";
3+
import { createParamDecorator } from "@nestjs/common";
4+
5+
export const GetOptionalUser = createParamDecorator<
6+
keyof ApiAuthGuardUser | (keyof ApiAuthGuardUser)[],
7+
ExecutionContext
8+
>((data, ctx) => {
9+
const request = ctx.switchToHttp().getRequest();
10+
const user = request.user as ApiAuthGuardUser;
11+
12+
if (!user) {
13+
return null;
14+
}
15+
16+
if (Array.isArray(data)) {
17+
return data.reduce((prev, curr) => {
18+
return {
19+
...prev,
20+
[curr]: user[curr],
21+
};
22+
}, {});
23+
}
24+
25+
if (data) {
26+
return user[data];
27+
}
28+
29+
return user;
30+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
2+
import { NO_AUTH_PROVIDED_MESSAGE } from "@/modules/auth/strategies/api-auth/api-auth.strategy";
3+
4+
export class OptionalApiAuthGuard extends ApiAuthGuard {
5+
handleRequest(error: Error, user: any) {
6+
// note(Lauris): optional means that auth is not required but if it is invalid then still throw error.
7+
const noAuthProvided = error && error.message === NO_AUTH_PROVIDED_MESSAGE;
8+
if (user || noAuthProvided || !error) {
9+
return user || null;
10+
} else {
11+
throw error;
12+
}
13+
}
14+
}

apps/api/v2/src/modules/auth/strategies/api-auth/api-auth.strategy.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { INVALID_ACCESS_TOKEN, X_CAL_CLIENT_ID, X_CAL_SECRET_KEY } from "@calcom
1919

2020
export type ApiAuthGuardUser = UserWithProfile & { isSystemAdmin: boolean };
2121

22+
export const NO_AUTH_PROVIDED_MESSAGE =
23+
"No authentication method provided. Either pass an API key as 'Bearer' header or OAuth client credentials as 'x-cal-secret-key' and 'x-cal-client-id' headers";
2224
@Injectable()
2325
export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth") {
2426
constructor(
@@ -62,9 +64,7 @@ export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth")
6264
return await this.authenticateNextAuth(nextAuthToken);
6365
}
6466

65-
throw new UnauthorizedException(
66-
"No authentication method provided. Either pass an API key as 'Bearer' header or OAuth client credentials as 'x-cal-secret-key' and 'x-cal-client-id' headers"
67-
);
67+
throw new UnauthorizedException(NO_AUTH_PROVIDED_MESSAGE);
6868
} catch (err) {
6969
if (err instanceof Error) {
7070
return this.error(err);
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
2+
import { MembershipsService } from "@/modules/memberships/services/memberships.service";
23
import { PrismaModule } from "@/modules/prisma/prisma.module";
34
import { Module } from "@nestjs/common";
45

56
@Module({
67
imports: [PrismaModule],
7-
providers: [MembershipsRepository],
8-
exports: [MembershipsRepository],
8+
providers: [MembershipsRepository, MembershipsService],
9+
exports: [MembershipsRepository, MembershipsService],
910
})
1011
export class MembershipsModule {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { MembershipsRepository } from "@/modules/memberships/memberships.repository";
2+
import { Injectable } from "@nestjs/common";
3+
import { intersectionBy } from "lodash";
4+
5+
@Injectable()
6+
export class MembershipsService {
7+
constructor(private readonly membershipsRepository: MembershipsRepository) {}
8+
9+
async haveMembershipsInCommon(firstUserId: number, secondUserId: number) {
10+
const memberships = await this.membershipsInCommon(firstUserId, secondUserId);
11+
return memberships.length > 0;
12+
}
13+
14+
async membershipsInCommon(firstUserId: number, secondUserId: number) {
15+
const firstUserMemberships = await this.membershipsRepository.findUserMemberships(firstUserId);
16+
const secondUserMemberships = await this.membershipsRepository.findUserMemberships(secondUserId);
17+
18+
return intersectionBy(
19+
firstUserMemberships.filter((m) => m.accepted),
20+
secondUserMemberships.filter((m) => m.accepted),
21+
"teamId"
22+
);
23+
}
24+
}

apps/api/v2/src/modules/organizations/organizations.repository.ts

+10
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,14 @@ export class OrganizationsRepository {
131131
},
132132
});
133133
}
134+
135+
async findOrgBySlug(slug: string) {
136+
return this.dbRead.prisma.team.findFirst({
137+
where: {
138+
slug,
139+
parentId: null,
140+
isOrganization: true,
141+
},
142+
});
143+
}
134144
}

apps/api/v2/src/modules/organizations/repositories/organizations-users.repository.ts

+15-16
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,6 @@ export class OrganizationsUsersRepository {
3737
});
3838
}
3939

40-
async getOrganizationUserByUsername(orgId: number, username: string) {
41-
return await this.dbRead.prisma.user.findFirst({
42-
where: {
43-
username,
44-
...this.filterOnOrgMembership(orgId),
45-
},
46-
include: {
47-
profiles: {
48-
where: {
49-
organizationId: orgId,
50-
},
51-
},
52-
},
53-
});
54-
}
55-
5640
async getOrganizationUserByEmail(orgId: number, email: string) {
5741
return await this.dbRead.prisma.user.findFirst({
5842
where: {
@@ -109,4 +93,19 @@ export class OrganizationsUsersRepository {
10993
},
11094
});
11195
}
96+
97+
async getOrganizationUserByUsername(orgId: number, username: string) {
98+
const profile = await this.dbRead.prisma.profile.findUnique({
99+
where: {
100+
username_organizationId: {
101+
organizationId: orgId,
102+
username,
103+
},
104+
},
105+
include: {
106+
user: true,
107+
},
108+
});
109+
return profile?.user;
110+
}
112111
}

apps/api/v2/src/modules/slots/controllers/slots.controller.e2e-spec.ts apps/api/v2/src/modules/slots/slots-2024-04-15/controllers/slots.controller.e2e-spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { SchedulesModule_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/
44
import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service";
55
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
66
import { PrismaModule } from "@/modules/prisma/prisma.module";
7-
import { SlotsModule } from "@/modules/slots/slots.module";
7+
import { SlotsModule_2024_04_15 } from "@/modules/slots/slots-2024-04-15/slots.module";
88
import { TokensModule } from "@/modules/tokens/tokens.module";
99
import { UsersModule } from "@/modules/users/users.module";
1010
import { INestApplication } from "@nestjs/common";
@@ -243,7 +243,7 @@ const expectedSlotsRomeRange = {
243243
},
244244
};
245245

246-
describe("Slots Endpoints", () => {
246+
describe("Slots 2024-04-15 Endpoints", () => {
247247
describe("Individual user slots", () => {
248248
let app: INestApplication;
249249

@@ -275,7 +275,7 @@ describe("Slots Endpoints", () => {
275275
UsersModule,
276276
TokensModule,
277277
SchedulesModule_2024_06_11,
278-
SlotsModule,
278+
SlotsModule_2024_04_15,
279279
],
280280
})
281281
)

apps/api/v2/src/modules/slots/controllers/slots.controller.ts apps/api/v2/src/modules/slots/slots-2024-04-15/controllers/slots.controller.ts

+20-14
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
1-
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
2-
import { SlotsOutputService } from "@/modules/slots/services/slots-output.service";
3-
import { SlotsService } from "@/modules/slots/services/slots.service";
1+
import { SlotsOutputService_2024_04_15 } from "@/modules/slots/slots-2024-04-15/services/slots-output.service";
2+
import { SlotsService_2024_04_15 } from "@/modules/slots/slots-2024-04-15/services/slots.service";
43
import { Query, Body, Controller, Get, Delete, Post, Req, Res } from "@nestjs/common";
4+
import { ApiExcludeController as DocsExcludeController } from "@nestjs/swagger";
55
import { ApiTags as DocsTags, ApiCreatedResponse, ApiOkResponse, ApiOperation } from "@nestjs/swagger";
66
import { Response as ExpressResponse, Request as ExpressRequest } from "express";
77

8-
import { SUCCESS_STATUS } from "@calcom/platform-constants";
8+
import {
9+
SUCCESS_STATUS,
10+
VERSION_2024_06_14,
11+
VERSION_2024_04_15,
12+
VERSION_2024_06_11,
13+
VERSION_2024_08_13,
14+
} from "@calcom/platform-constants";
915
import { getAvailableSlots } from "@calcom/platform-libraries";
1016
import type { AvailableSlotsType } from "@calcom/platform-libraries";
11-
import { RemoveSelectedSlotInput, ReserveSlotInput } from "@calcom/platform-types";
12-
import { ApiResponse, GetAvailableSlotsInput } from "@calcom/platform-types";
17+
import { RemoveSelectedSlotInput_2024_04_15, ReserveSlotInput_2024_04_15 } from "@calcom/platform-types";
18+
import { ApiResponse, GetAvailableSlotsInput_2024_04_15 } from "@calcom/platform-types";
1319

1420
@Controller({
1521
path: "/v2/slots",
16-
version: API_VERSIONS_VALUES,
22+
version: [VERSION_2024_04_15, VERSION_2024_06_11, VERSION_2024_06_14, VERSION_2024_08_13],
1723
})
18-
@DocsTags("Slots")
19-
export class SlotsController {
24+
@DocsExcludeController(true)
25+
export class SlotsController_2024_04_15 {
2026
constructor(
21-
private readonly slotsService: SlotsService,
22-
private readonly slotsOutputService: SlotsOutputService
27+
private readonly slotsService: SlotsService_2024_04_15,
28+
private readonly slotsOutputService: SlotsOutputService_2024_04_15
2329
) {}
2430

2531
@Post("/reserve")
@@ -40,7 +46,7 @@ export class SlotsController {
4046
})
4147
@ApiOperation({ summary: "Reserve a slot" })
4248
async reserveSlot(
43-
@Body() body: ReserveSlotInput,
49+
@Body() body: ReserveSlotInput_2024_04_15,
4450
@Res({ passthrough: true }) res: ExpressResponse,
4551
@Req() req: ExpressRequest
4652
): Promise<ApiResponse<string>> {
@@ -65,7 +71,7 @@ export class SlotsController {
6571
})
6672
@ApiOperation({ summary: "Delete a selected slot" })
6773
async deleteSelectedSlot(
68-
@Query() params: RemoveSelectedSlotInput,
74+
@Query() params: RemoveSelectedSlotInput_2024_04_15,
6975
@Req() req: ExpressRequest
7076
): Promise<ApiResponse> {
7177
const uid = req.cookies?.uid || params.uid;
@@ -148,7 +154,7 @@ export class SlotsController {
148154
})
149155
@ApiOperation({ summary: "Get available slots" })
150156
async getAvailableSlots(
151-
@Query() query: GetAvailableSlotsInput,
157+
@Query() query: GetAvailableSlotsInput_2024_04_15,
152158
@Req() req: ExpressRequest
153159
): Promise<ApiResponse<AvailableSlotsType>> {
154160
const isTeamEvent = await this.slotsService.checkIfIsTeamEvent(query.eventTypeId);

apps/api/v2/src/modules/slots/services/slots-output.service.ts apps/api/v2/src/modules/slots/slots-2024-04-15/services/slots-output.service.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import { DateTime } from "luxon";
44

55
import { SlotFormat } from "@calcom/platform-enums";
66

7-
type TimeSlots = { slots: Record<string, { time: string; attendees?: number; bookingUid?: string }[]> };
7+
export type TimeSlots = {
8+
slots: Record<string, { time: string; attendees?: number; bookingUid?: string }[]>;
9+
};
810
type RangeSlots = {
911
slots: Record<string, { startTime: string; endTime: string; attendees?: number; bookingUid?: string }[]>;
1012
};
1113

1214
@Injectable()
13-
export class SlotsOutputService {
15+
export class SlotsOutputService_2024_04_15 {
1416
constructor(private readonly eventTypesRepository: EventTypesRepository_2024_04_15) {}
1517

1618
async getOutputSlots(

0 commit comments

Comments
 (0)