From d3999b9510ab9ec470c544f7e2cd8bfedc6b9fc7 Mon Sep 17 00:00:00 2001 From: Mir Arif Hasan Date: Tue, 5 Nov 2024 21:48:23 +0600 Subject: [PATCH] chore: user deletetion if not solo team owner (#4508) (HSB-497) --- .../src/admin/admin.service.ts | 15 ++++---- .../src/team/team.service.ts | 36 +++++++++++++------ 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/packages/hoppscotch-backend/src/admin/admin.service.ts b/packages/hoppscotch-backend/src/admin/admin.service.ts index db0fba1c1..33e7d8868 100644 --- a/packages/hoppscotch-backend/src/admin/admin.service.ts +++ b/packages/hoppscotch-backend/src/admin/admin.service.ts @@ -231,9 +231,8 @@ export class AdminService { * @returns a count of team members */ async membersCountInTeam(teamID: string) { - const teamMembersCount = await this.teamService.getCountOfMembersInTeam( - teamID, - ); + const teamMembersCount = + await this.teamService.getCountOfMembersInTeam(teamID); return teamMembersCount; } @@ -276,9 +275,8 @@ export class AdminService { * @returns an array team invitations */ async pendingInvitationCountInTeam(teamID: string) { - const invitations = await this.teamInvitationService.getTeamInvitations( - teamID, - ); + const invitations = + await this.teamInvitationService.getTeamInvitations(teamID); return invitations; } @@ -614,9 +612,8 @@ export class AdminService { * @returns an Either of boolean or error */ async revokeTeamInviteByID(inviteID: string) { - const teamInvite = await this.teamInvitationService.revokeInvitation( - inviteID, - ); + const teamInvite = + await this.teamInvitationService.revokeInvitation(inviteID); if (E.isLeft(teamInvite)) return E.left(teamInvite.left); diff --git a/packages/hoppscotch-backend/src/team/team.service.ts b/packages/hoppscotch-backend/src/team/team.service.ts index f1afcf908..80a2240b1 100644 --- a/packages/hoppscotch-backend/src/team/team.service.ts +++ b/packages/hoppscotch-backend/src/team/team.service.ts @@ -38,7 +38,7 @@ export class TeamService implements UserDataHandler, OnModuleInit { canAllowUserDeletion(user: AuthUser): TO.TaskOption { return pipe( - this.isUserOwnerRoleInTeams(user.uid), + this.isUserSoleOwnerInAnyTeam(user.uid), TO.fromTask, TO.chain((isOwner) => (isOwner ? TO.some(USER_IS_OWNER) : TO.none)), ); @@ -396,18 +396,34 @@ export class TeamService implements UserDataHandler, OnModuleInit { return teamMember ? teamMember.role : null; } - isUserOwnerRoleInTeams(uid: string): T.Task { - return pipe( - () => - this.prisma.teamMember.count({ + isUserSoleOwnerInAnyTeam(uid: string): T.Task { + return async () => { + // Find all teams where the user is an OWNER + const userOwnedTeams = await this.prisma.teamMember.findMany({ + where: { + userUid: uid, + role: TeamMemberRole.OWNER, + }, + select: { + teamID: true, + }, + }); + + for (const userOwnedTeam of userOwnedTeams) { + const ownerCount = await this.prisma.teamMember.count({ where: { - userUid: uid, + teamID: userOwnedTeam.teamID, role: TeamMemberRole.OWNER, }, - take: 1, - }), - T.map((count) => count > 0), - ); + }); + + // early return true if the user is the sole owner + if (ownerCount === 1) return true; + } + + // return false if the user is not the sole owner in any team + return false; + }; } deleteUserFromAllTeams(uid: string) {