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 6cc9713ab9..ce7677f1d8 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 @@ -1,6 +1,7 @@ import { bootstrap } from "@/app"; import { AppModule } from "@/app.module"; import { CreateOrgTeamDto } from "@/modules/organizations/inputs/create-organization-team.input"; +import { OrgMeTeamOutputDto } from "@/modules/organizations/outputs/organization-team.output"; import { PrismaModule } from "@/modules/prisma/prisma.module"; import { TokensModule } from "@/modules/tokens/tokens.module"; import { UsersModule } from "@/modules/users/users.module"; @@ -149,6 +150,17 @@ describe("Organizations Team Endpoints", () => { }); }); + it("should get all the teams of the authenticated org member", async () => { + return request(app.getHttpServer()) + .get(`/v2/organizations/${org.id}/teams/me`) + .expect(200) + .then((response) => { + const responseBody: ApiSuccessResponse = response.body; + expect(responseBody.data.find((t) => t.id === teamCreatedViaApi.id)).toBeDefined(); + expect(responseBody.data.some((t) => t.accepted)).toBeTruthy(); + }); + }); + it("should update the team of the org", async () => { return request(app.getHttpServer()) .patch(`/v2/organizations/${org.id}/teams/${teamCreatedViaApi.id}`) 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 8da15a4b4d..47d889edba 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 @@ -8,6 +8,8 @@ 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 { + OrgMeTeamOutputDto, + OrgMeTeamsOutputResponseDto, OrgTeamOutputDto, OrgTeamOutputResponseDto, OrgTeamsOutputResponseDto, @@ -44,7 +46,6 @@ export class OrganizationsTeamsController { @Get() @ApiOperation({ summary: "Get all the teams of an organization." }) - @UseGuards() @Roles("ORG_ADMIN") async getAllTeams( @Param("orgId", ParseIntPipe) orgId: number, @@ -58,6 +59,33 @@ export class OrganizationsTeamsController { }; } + @Get("/me") + @ApiOperation({ summary: "Get the organization's teams user is a member of" }) + @Roles("ORG_MEMBER") + async getMyTeams( + @Param("orgId", ParseIntPipe) orgId: number, + @Query() queryParams: SkipTakePagination, + @GetUser() user: UserWithProfile + ): Promise { + const { skip, take } = queryParams; + const teams = await this.organizationsTeamsService.getPaginatedOrgUserTeams( + orgId, + user.id, + skip ?? 0, + take ?? 250 + ); + return { + status: SUCCESS_STATUS, + data: teams.map((team) => + plainToClass( + OrgMeTeamOutputDto, + { ...team, accepted: team.members.find((member) => member.userId === user.id)?.accepted ?? false }, + { strategy: "excludeAll" } + ) + ), + }; + } + @UseGuards(IsTeamInOrg) @Roles("TEAM_ADMIN") @Get("/:teamId") diff --git a/apps/api/v2/src/modules/organizations/outputs/organization-team.output.ts b/apps/api/v2/src/modules/organizations/outputs/organization-team.output.ts index 32c2134ba5..e8cb14ac6d 100644 --- a/apps/api/v2/src/modules/organizations/outputs/organization-team.output.ts +++ b/apps/api/v2/src/modules/organizations/outputs/organization-team.output.ts @@ -118,6 +118,12 @@ export class OrgTeamOutputDto { readonly weekStart?: string = "Sunday"; } +export class OrgMeTeamOutputDto extends OrgTeamOutputDto { + @IsString() + @Expose() + readonly accepted!: boolean; +} + export class OrgTeamsOutputResponseDto { @ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] }) @IsEnum([SUCCESS_STATUS, ERROR_STATUS]) @@ -129,6 +135,17 @@ export class OrgTeamsOutputResponseDto { data!: OrgTeamOutputDto[]; } +export class OrgMeTeamsOutputResponseDto { + @ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] }) + @IsEnum([SUCCESS_STATUS, ERROR_STATUS]) + status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS; + + @Expose() + @ValidateNested() + @Type(() => OrgTeamOutputDto) + data!: OrgTeamOutputDto[]; +} + export class OrgTeamOutputResponseDto { @ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] }) @IsEnum([SUCCESS_STATUS, ERROR_STATUS]) diff --git a/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts b/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts index 3b13012718..d5cbb97e19 100644 --- a/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts +++ b/apps/api/v2/src/modules/organizations/repositories/organizations-teams.repository.ts @@ -49,6 +49,24 @@ export class OrganizationsTeamsRepository { }); } + async findOrgUserTeamsPaginated(organizationId: number, userId: number, skip: number, take: number) { + return this.dbRead.prisma.team.findMany({ + where: { + parentId: organizationId, + members: { + some: { + userId, + }, + }, + }, + include: { + members: { select: { accepted: true, userId: true } }, + }, + skip, + take, + }); + } + async getTeamMembersIds(teamId: number) { const team = await this.dbRead.prisma.team.findUnique({ where: { 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 4cba19f307..8e9b7fc895 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 @@ -11,6 +11,16 @@ export class OrganizationsTeamsService { private readonly membershipsRepository: MembershipsRepository ) {} + async getPaginatedOrgUserTeams(organizationId: number, userId: number, skip = 0, take = 250) { + const teams = await this.organizationsTeamRepository.findOrgUserTeamsPaginated( + organizationId, + userId, + skip, + take + ); + return teams; + } + async getPaginatedOrgTeams(organizationId: number, skip = 0, take = 250) { const teams = await this.organizationsTeamRepository.findOrgTeamsPaginated(organizationId, skip, take); return teams;