From 9fec77e34533c09b2a5e10f3e22c17b428f90352 Mon Sep 17 00:00:00 2001 From: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:31:29 +0300 Subject: [PATCH] fix: creating organization team should add owner (#15779) * chore: platform libraries versions cleanup api v2 * fix: create membership to created org team apiv2 * chore: add test check owner membership --------- Co-authored-by: Lauris Skraucis --- .../modules/memberships/memberships.repository.ts | 14 ++++++++++++++ .../organizations-teams.controller.e2e-spec.ts | 7 ++++++- .../teams/organizations-teams.controller.ts | 8 +++++--- .../services/organizations-teams.service.ts | 12 ++++++++++-- .../repository/membership.repository.fixture.ts | 4 ++++ 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/apps/api/v2/src/modules/memberships/memberships.repository.ts b/apps/api/v2/src/modules/memberships/memberships.repository.ts index 37e950b006..98d495f07c 100644 --- a/apps/api/v2/src/modules/memberships/memberships.repository.ts +++ b/apps/api/v2/src/modules/memberships/memberships.repository.ts @@ -1,6 +1,8 @@ import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; import { Injectable } from "@nestjs/common"; +import { MembershipRole } from "@calcom/prisma/client"; + @Injectable() export class MembershipsRepository { constructor(private readonly dbRead: PrismaReadService) {} @@ -47,4 +49,16 @@ export class MembershipsRepository { return !!adminMembership; } + + async createMembership(teamId: number, userId: number, role: MembershipRole) { + const membership = await this.dbRead.prisma.membership.create({ + data: { + role, + teamId, + userId, + }, + }); + + return membership; + } } diff --git a/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.e2e-spec.ts b/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.e2e-spec.ts index 164c398773..6cc9713ab9 100644 --- a/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.e2e-spec.ts +++ b/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.e2e-spec.ts @@ -135,12 +135,17 @@ describe("Organizations Team Endpoints", () => { name: "Team created via API", } satisfies CreateOrgTeamDto) .expect(201) - .then((response) => { + .then(async (response) => { const responseBody: ApiSuccessResponse = response.body; expect(responseBody.status).toEqual(SUCCESS_STATUS); teamCreatedViaApi = responseBody.data; expect(teamCreatedViaApi.name).toEqual("Team created via API"); expect(teamCreatedViaApi.parentId).toEqual(org.id); + const membership = await membershipsRepositoryFixture.getUserMembershipByTeamId( + user.id, + teamCreatedViaApi.id + ); + expect(membership?.role ?? "").toEqual("OWNER"); }); }); diff --git a/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.ts b/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.ts index 65a2e18aba..8da15a4b4d 100644 --- a/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.ts +++ b/apps/api/v2/src/modules/organizations/controllers/teams/organizations-teams.controller.ts @@ -1,5 +1,6 @@ import { API_VERSIONS_VALUES } from "@/lib/api-versions"; import { GetTeam } from "@/modules/auth/decorators/get-team/get-team.decorator"; +import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator"; import { Roles } from "@/modules/auth/decorators/roles/roles.decorator"; import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard"; import { IsOrgGuard } from "@/modules/auth/guards/organizations/is-org.guard"; @@ -12,6 +13,7 @@ import { OrgTeamsOutputResponseDto, } from "@/modules/organizations/outputs/organization-team.output"; import { OrganizationsTeamsService } from "@/modules/organizations/services/organizations-teams.service"; +import { UserWithProfile } from "@/modules/users/users.repository"; import { Controller, UseGuards, @@ -99,14 +101,14 @@ export class OrganizationsTeamsController { } @Post() - @UseGuards() @Roles("ORG_ADMIN") @ApiOperation({ summary: "Create a team for an organization." }) async createTeam( @Param("orgId", ParseIntPipe) orgId: number, - @Body() body: CreateOrgTeamDto + @Body() body: CreateOrgTeamDto, + @GetUser() user: UserWithProfile ): Promise { - const team = await this.organizationsTeamsService.createOrgTeam(orgId, body); + const team = await this.organizationsTeamsService.createOrgTeam(orgId, body, user); return { status: SUCCESS_STATUS, data: plainToClass(OrgTeamOutputDto, team, { strategy: "excludeAll" }), diff --git a/apps/api/v2/src/modules/organizations/services/organizations-teams.service.ts b/apps/api/v2/src/modules/organizations/services/organizations-teams.service.ts index 700c7be915..13975e7614 100644 --- a/apps/api/v2/src/modules/organizations/services/organizations-teams.service.ts +++ b/apps/api/v2/src/modules/organizations/services/organizations-teams.service.ts @@ -1,10 +1,15 @@ +import { MembershipsRepository } from "@/modules/memberships/memberships.repository"; import { CreateOrgTeamDto } from "@/modules/organizations/inputs/create-organization-team.input"; import { OrganizationsTeamsRepository } from "@/modules/organizations/repositories/organizations-teams.repository"; +import { UserWithProfile } from "@/modules/users/users.repository"; import { Injectable } from "@nestjs/common"; @Injectable() export class OrganizationsTeamsService { - constructor(private readonly organizationsTeamRepository: OrganizationsTeamsRepository) {} + constructor( + private readonly organizationsTeamRepository: OrganizationsTeamsRepository, + private readonly membershipsRepository: MembershipsRepository + ) {} async getPaginatedOrgTeams(organizationId: number, skip = 0, take = 250) { const teams = await this.organizationsTeamRepository.findOrgTeamsPaginated(organizationId, skip, take); @@ -21,8 +26,11 @@ export class OrganizationsTeamsService { return team; } - async createOrgTeam(organizationId: number, data: CreateOrgTeamDto) { + async createOrgTeam(organizationId: number, data: CreateOrgTeamDto, user: UserWithProfile) { const team = await this.organizationsTeamRepository.createOrgTeam(organizationId, data); + if (user.role !== "ADMIN") { + await this.membershipsRepository.createMembership(team.id, user.id, "OWNER"); + } return team; } } diff --git a/apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts b/apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts index 21ee461df0..5cf8fd41f8 100644 --- a/apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts +++ b/apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts @@ -24,6 +24,10 @@ export class MembershipRepositoryFixture { return this.primaReadClient.membership.findFirst({ where: { id: membershipId } }); } + async getUserMembershipByTeamId(userId: User["id"], teamId: Team["id"]) { + return this.primaReadClient.membership.findFirst({ where: { teamId, userId } }); + } + async addUserToOrg(user: User, org: Team, role: MembershipRole, accepted: boolean) { const membership = await this.prismaWriteClient.membership.create({ data: { teamId: org.id, userId: user.id, role, accepted },