From 1690770d6afca777741a4e2b85a0d42f54390d9f Mon Sep 17 00:00:00 2001 From: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:15:48 +0300 Subject: [PATCH] fix: check profiles and orgId from user.profiles apiv2 (#16249) * fix: check profiles and orgId from user.profiles apiv2 * fixup! fix: check profiles and orgId from user.profiles apiv2 --------- Co-authored-by: Lauris Skraucis --- .../event-types_2024_04_15/event-types.repository.ts | 9 +++++++-- .../services/event-types.service.ts | 12 +++++++----- .../event-types_2024_06_14/event-types.repository.ts | 9 +++++++-- .../services/event-types.service.ts | 8 ++++---- .../organization-roles/organization-roles.guard.ts | 6 ++++-- apps/api/v2/src/modules/billing/billing.module.ts | 2 ++ .../oauth-clients/oauth-clients.controller.ts | 8 +++++--- .../oauth-clients/guards/oauth-client-guard.ts | 5 +++-- .../event-types/organizations-event-types.service.ts | 3 ++- .../v2/src/modules/users/services/users.service.ts | 4 ++++ .../webhooks/guards/is-oauth-client-webhook-guard.ts | 6 ++++-- 11 files changed, 49 insertions(+), 23 deletions(-) diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts index b56bf84bed..799cdc5e50 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/event-types.repository.ts @@ -1,6 +1,7 @@ import { CreateEventTypeInput_2024_04_15 } from "@/ee/event-types/event-types_2024_04_15/inputs/create-event-type.input"; import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; +import { UsersService } from "@/modules/users/services/users.service"; import { UserWithProfile } from "@/modules/users/users.repository"; import { Injectable } from "@nestjs/common"; @@ -9,7 +10,11 @@ import type { PrismaClient } from "@calcom/prisma"; @Injectable() export class EventTypesRepository_2024_04_15 { - constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {} + constructor( + private readonly dbRead: PrismaReadService, + private readonly dbWrite: PrismaWriteService, + private usersService: UsersService + ) {} async createUserEventType( userId: number, @@ -46,7 +51,7 @@ export class EventTypesRepository_2024_04_15 { eventTypeId: number ) { return await getEventTypeById({ - currentOrganizationId: user.movedToProfile?.organizationId || user.organizationId, + currentOrganizationId: this.usersService.getUserMainOrgId(user), eventTypeId, userId: user.id, prisma: this.dbRead.prisma as unknown as PrismaClient, diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts index a5eeb38615..549851f699 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_04_15/services/event-types.service.ts @@ -6,6 +6,7 @@ import { EventTypeOutput } from "@/ee/event-types/event-types_2024_04_15/outputs import { MembershipsRepository } from "@/modules/memberships/memberships.repository"; import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; import { SelectedCalendarsRepository } from "@/modules/selected-calendars/selected-calendars.repository"; +import { UsersService } from "@/modules/users/services/users.service"; import { UserWithProfile, UsersRepository } from "@/modules/users/users.repository"; import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common"; @@ -24,7 +25,8 @@ export class EventTypesService_2024_04_15 { private readonly membershipsRepository: MembershipsRepository, private readonly usersRepository: UsersRepository, private readonly selectedCalendarsRepository: SelectedCalendarsRepository, - private readonly dbWrite: PrismaWriteService + private readonly dbWrite: PrismaWriteService, + private usersService: UsersService ) {} async createUserEventType( @@ -53,11 +55,11 @@ export class EventTypesService_2024_04_15 { } async getUserToCreateEvent(user: UserWithProfile) { - const organizationId = user.movedToProfile?.organizationId || user.organizationId; + const organizationId = this.usersService.getUserMainOrgId(user); const isOrgAdmin = organizationId ? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId) : false; - const profileId = user.movedToProfile?.id || null; + const profileId = this.usersService.getUserMainProfile(user)?.id || null; return { id: user.id, role: user.role, @@ -80,7 +82,7 @@ export class EventTypesService_2024_04_15 { } async getUserEventTypeForAtom(user: UserWithProfile, eventTypeId: number) { - const organizationId = user.movedToProfile?.organizationId || user.organizationId; + const organizationId = this.usersService.getUserMainOrgId(user); const isUserOrganizationAdmin = organizationId ? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId) @@ -153,7 +155,7 @@ export class EventTypesService_2024_04_15 { } async getUserToUpdateEvent(user: UserWithProfile) { - const profileId = user.movedToProfile?.id || null; + const profileId = this.usersService.getUserMainProfile(user)?.id || null; const selectedCalendars = await this.selectedCalendarsRepository.getUserSelectedCalendars(user.id); return { ...user, profile: { id: profileId }, selectedCalendars }; } diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts index 01a69cec33..af9d0175f8 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts @@ -1,5 +1,6 @@ import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; +import { UsersService } from "@/modules/users/services/users.service"; import { UserWithProfile } from "@/modules/users/users.repository"; import { Injectable } from "@nestjs/common"; @@ -34,7 +35,11 @@ type InputEventTransformed = Omit< @Injectable() export class EventTypesRepository_2024_06_14 { - constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {} + constructor( + private readonly dbRead: PrismaReadService, + private readonly dbWrite: PrismaWriteService, + private usersService: UsersService + ) {} async createUserEventType(userId: number, body: InputEventTransformed) { return this.dbWrite.prisma.eventType.create({ @@ -80,7 +85,7 @@ export class EventTypesRepository_2024_06_14 { eventTypeId: number ) { return await getEventTypeById({ - currentOrganizationId: user.movedToProfile?.organizationId || user.organizationId, + currentOrganizationId: this.usersService.getUserMainOrgId(user), eventTypeId, userId: user.id, prisma: this.dbRead.prisma as unknown as PrismaClient, diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts index 61dd430709..2f1f910fd5 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts @@ -119,11 +119,11 @@ export class EventTypesService_2024_06_14 { } async getUserToCreateEvent(user: UserWithProfile) { - const organizationId = user.movedToProfile?.organizationId || user.organizationId; + const organizationId = this.usersService.getUserMainOrgId(user); const isOrgAdmin = organizationId ? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId) : false; - const profileId = user.movedToProfile?.id || null; + const profileId = this.usersService.getUserMainProfile(user)?.id || null; const selectedCalendars = await this.selectedCalendarsRepository.getUserSelectedCalendars(user.id); return { id: user.id, @@ -159,7 +159,7 @@ export class EventTypesService_2024_06_14 { } async getUserEventTypeForAtom(user: UserWithProfile, eventTypeId: number) { - const organizationId = user.movedToProfile?.organizationId || user.organizationId; + const organizationId = this.usersService.getUserMainOrgId(user); const isUserOrganizationAdmin = organizationId ? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId) @@ -270,7 +270,7 @@ export class EventTypesService_2024_06_14 { } async getUserToUpdateEvent(user: UserWithProfile) { - const profileId = user.movedToProfile?.id || null; + const profileId = this.usersService.getUserMainProfile(user)?.id || null; const selectedCalendars = await this.selectedCalendarsRepository.getUserSelectedCalendars(user.id); return { ...user, profile: { id: profileId }, selectedCalendars }; } diff --git a/apps/api/v2/src/modules/auth/guards/organization-roles/organization-roles.guard.ts b/apps/api/v2/src/modules/auth/guards/organization-roles/organization-roles.guard.ts index bb6eeffe58..1105a9a3a1 100644 --- a/apps/api/v2/src/modules/auth/guards/organization-roles/organization-roles.guard.ts +++ b/apps/api/v2/src/modules/auth/guards/organization-roles/organization-roles.guard.ts @@ -1,6 +1,7 @@ import { MembershipRoles } from "@/modules/auth/decorators/roles/membership-roles.decorator"; import { MembershipsRepository } from "@/modules/memberships/memberships.repository"; import { OrganizationsService } from "@/modules/organizations/services/organizations.service"; +import { UsersService } from "@/modules/users/services/users.service"; import { UserWithProfile } from "@/modules/users/users.repository"; import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; @@ -12,13 +13,14 @@ export class OrganizationRolesGuard implements CanActivate { constructor( private reflector: Reflector, private organizationsService: OrganizationsService, - private membershipRepository: MembershipsRepository + private membershipRepository: MembershipsRepository, + private usersService: UsersService ) {} async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const user: UserWithProfile = request.user; - const organizationId = user?.movedToProfile?.organizationId || user?.organizationId; + const organizationId = user ? this.usersService.getUserMainOrgId(user) : null; if (!user || !organizationId) { throw new ForbiddenException("No organization associated with the user."); diff --git a/apps/api/v2/src/modules/billing/billing.module.ts b/apps/api/v2/src/modules/billing/billing.module.ts index 2bd209a9cf..b09f662fa0 100644 --- a/apps/api/v2/src/modules/billing/billing.module.ts +++ b/apps/api/v2/src/modules/billing/billing.module.ts @@ -7,6 +7,7 @@ import { MembershipsModule } from "@/modules/memberships/memberships.module"; import { OrganizationsModule } from "@/modules/organizations/organizations.module"; import { PrismaModule } from "@/modules/prisma/prisma.module"; import { StripeModule } from "@/modules/stripe/stripe.module"; +import { UsersModule } from "@/modules/users/users.module"; import { BullModule } from "@nestjs/bull"; import { Module } from "@nestjs/common"; @@ -23,6 +24,7 @@ import { Module } from "@nestjs/common"; duration: 1000, }, }), + UsersModule, ], providers: [BillingConfigService, BillingService, BillingRepository, BillingProcessor], exports: [BillingService, BillingRepository], diff --git a/apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts b/apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts index c64d310c5b..c3788b9a87 100644 --- a/apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts +++ b/apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts @@ -13,6 +13,7 @@ import { OAuthClientGuard } from "@/modules/oauth-clients/guards/oauth-client-gu import { UpdateOAuthClientInput } from "@/modules/oauth-clients/inputs/update-oauth-client.input"; import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository"; import { OrganizationsRepository } from "@/modules/organizations/organizations.repository"; +import { UsersService } from "@/modules/users/services/users.service"; import { UserWithProfile } from "@/modules/users/users.repository"; import { UsersRepository } from "@/modules/users/users.repository"; import { @@ -59,7 +60,8 @@ export class OAuthClientsController { constructor( private readonly oauthClientRepository: OAuthClientRepository, private readonly userRepository: UsersRepository, - private readonly teamsRepository: OrganizationsRepository + private readonly teamsRepository: OrganizationsRepository, + private usersService: UsersService ) {} @Post("/") @@ -74,7 +76,7 @@ export class OAuthClientsController { @GetUser() user: UserWithProfile, @Body() body: CreateOAuthClientInput ): Promise { - const organizationId = (user.movedToProfile?.organizationId ?? user.organizationId) as number; + const organizationId = this.usersService.getUserMainOrgId(user) as number; this.logger.log( `For organisation ${organizationId} creating OAuth Client with data: ${JSON.stringify(body)}` ); @@ -100,7 +102,7 @@ export class OAuthClientsController { @MembershipRoles([MembershipRole.ADMIN, MembershipRole.OWNER, MembershipRole.MEMBER]) @DocsOperation({ description: AUTH_DOCUMENTATION }) async getOAuthClients(@GetUser() user: UserWithProfile): Promise { - const organizationId = (user.movedToProfile?.organizationId ?? user.organizationId) as number; + const organizationId = this.usersService.getUserMainOrgId(user) as number; const clients = await this.oauthClientRepository.getOrganizationOAuthClients(organizationId); return { status: SUCCESS_STATUS, data: clients }; diff --git a/apps/api/v2/src/modules/oauth-clients/guards/oauth-client-guard.ts b/apps/api/v2/src/modules/oauth-clients/guards/oauth-client-guard.ts index 029af7f5d1..bcc94627c4 100644 --- a/apps/api/v2/src/modules/oauth-clients/guards/oauth-client-guard.ts +++ b/apps/api/v2/src/modules/oauth-clients/guards/oauth-client-guard.ts @@ -1,5 +1,6 @@ import { GetUserReturnType } from "@/modules/auth/decorators/get-user/get-user.decorator"; import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository"; +import { UsersService } from "@/modules/users/services/users.service"; import { Injectable, CanActivate, @@ -11,12 +12,12 @@ import { Request } from "express"; @Injectable() export class OAuthClientGuard implements CanActivate { - constructor(private oAuthClientRepository: OAuthClientRepository) {} + constructor(private oAuthClientRepository: OAuthClientRepository, private usersService: UsersService) {} async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const user: GetUserReturnType = request.user; - const organizationId = user?.movedToProfile?.organizationId || user?.organizationId; + const organizationId = user ? this.usersService.getUserMainOrgId(user) : null; const oAuthClientId = request.params.clientId; if (!oAuthClientId) { diff --git a/apps/api/v2/src/modules/organizations/services/event-types/organizations-event-types.service.ts b/apps/api/v2/src/modules/organizations/services/event-types/organizations-event-types.service.ts index 061ebed1de..253940b21d 100644 --- a/apps/api/v2/src/modules/organizations/services/event-types/organizations-event-types.service.ts +++ b/apps/api/v2/src/modules/organizations/services/event-types/organizations-event-types.service.ts @@ -96,7 +96,8 @@ export class OrganizationsEventTypesService { async getUserToCreateTeamEvent(user: UserWithProfile, organizationId: number) { const isOrgAdmin = await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId); const profileId = - this.usersService.getUserProfileByOrgId(user, organizationId)?.id || user.movedToProfileId; + this.usersService.getUserProfileByOrgId(user, organizationId)?.id || + this.usersService.getUserMainProfile(user)?.id; return { id: user.id, role: user.role, diff --git a/apps/api/v2/src/modules/users/services/users.service.ts b/apps/api/v2/src/modules/users/services/users.service.ts index 8118acb58e..ed541b9500 100644 --- a/apps/api/v2/src/modules/users/services/users.service.ts +++ b/apps/api/v2/src/modules/users/services/users.service.ts @@ -30,6 +30,10 @@ export class UsersService { ); } + getUserMainOrgId(user: UserWithProfile) { + return this.getUserMainProfile(user)?.organizationId ?? user.organizationId; + } + getUserProfileByOrgId(user: UserWithProfile, organizationId: number) { return user.profiles?.find((p) => p.organizationId === organizationId); } diff --git a/apps/api/v2/src/modules/webhooks/guards/is-oauth-client-webhook-guard.ts b/apps/api/v2/src/modules/webhooks/guards/is-oauth-client-webhook-guard.ts index 19fb842622..0bb2da1368 100644 --- a/apps/api/v2/src/modules/webhooks/guards/is-oauth-client-webhook-guard.ts +++ b/apps/api/v2/src/modules/webhooks/guards/is-oauth-client-webhook-guard.ts @@ -1,5 +1,6 @@ import { GetUserReturnType } from "@/modules/auth/decorators/get-user/get-user.decorator"; import { OAuthClientRepository } from "@/modules/oauth-clients/oauth-client.repository"; +import { UsersService } from "@/modules/users/services/users.service"; import { WebhooksService } from "@/modules/webhooks/services/webhooks.service"; import { CanActivate, @@ -17,7 +18,8 @@ import { PlatformOAuthClient, Webhook } from "@calcom/prisma/client"; export class IsOAuthClientWebhookGuard implements CanActivate { constructor( private readonly webhooksService: WebhooksService, - private readonly oAuthClientRepository: OAuthClientRepository + private readonly oAuthClientRepository: OAuthClientRepository, + private usersService: UsersService ) {} async canActivate(context: ExecutionContext): Promise { @@ -27,7 +29,7 @@ export class IsOAuthClientWebhookGuard implements CanActivate { const user = request.user as GetUserReturnType; const webhookId = request.params.webhookId; const oAuthClientId = request.params.clientId; - const organizationId = user.movedToProfile?.organizationId || user.organizationId; + const organizationId = this.usersService.getUserMainOrgId(user); if (!user) { throw new ForbiddenException("User not authenticated");