diff --git a/src/lib/services/project-service.ts b/src/lib/services/project-service.ts index e8ccf71bfb..7be3ebfe7e 100644 --- a/src/lib/services/project-service.ts +++ b/src/lib/services/project-service.ts @@ -430,7 +430,9 @@ export default class ProjectService { return this.accessService.getProjectRoleAccess(projectId); } - // Deprecated: See addAccess instead. + /** + * @deprecated see addAccess instead. + */ async addUser( projectId: string, roleId: number, @@ -470,6 +472,9 @@ export default class ProjectService { ); } + /** + * @deprecated use removeUserAccess + */ async removeUser( projectId: string, roleId: number, @@ -511,7 +516,10 @@ export default class ProjectService { const ownerRole = await this.accessService.getRoleByName( RoleName.OWNER, ); - await this.validateAtLeastOneOwner(projectId, ownerRole); + + if (existingRoles.includes(ownerRole.id)) { + await this.validateAtLeastOneOwner(projectId, ownerRole); + } await this.accessService.removeUserAccess(projectId, userId); @@ -540,7 +548,10 @@ export default class ProjectService { const ownerRole = await this.accessService.getRoleByName( RoleName.OWNER, ); - await this.validateAtLeastOneOwner(projectId, ownerRole); + + if (existingRoles.includes(ownerRole.id)) { + await this.validateAtLeastOneOwner(projectId, ownerRole); + } await this.accessService.removeGroupAccess(projectId, groupId); @@ -592,6 +603,9 @@ export default class ProjectService { ); } + /** + * @deprecated use removeGroupAccess + */ async removeGroup( projectId: string, roleId: number, @@ -745,7 +759,6 @@ export default class ProjectService { if (hasOwnerRole && isRemovingOwnerRole) { await this.validateAtLeastOneOwner(projectId, ownerRole); } - await this.validateAtLeastOneOwner(projectId, ownerRole); await this.accessService.setProjectRolesForGroup( projectId, @@ -871,7 +884,6 @@ export default class ProjectService { // Nothing to do.... return; } - await this.validateAtLeastOneOwner(projectId, currentRole); await this.accessService.updateUserProjectRole( @@ -925,7 +937,6 @@ export default class ProjectService { // Nothing to do.... return; } - await this.validateAtLeastOneOwner(projectId, currentRole); await this.accessService.updateGroupProjectRole( diff --git a/src/test/e2e/services/project-service.e2e.test.ts b/src/test/e2e/services/project-service.e2e.test.ts index e077d1c18c..7dfc7d2cdf 100644 --- a/src/test/e2e/services/project-service.e2e.test.ts +++ b/src/test/e2e/services/project-service.e2e.test.ts @@ -1048,6 +1048,44 @@ describe('ensure project has at least one owner', () => { ); }); + test('should be able to remove member user from the project when another is owner', async () => { + const project = { + id: 'remove-users-members-allowed', + name: 'New project', + description: 'Blah', + mode: 'open' as const, + defaultStickiness: 'clientId', + }; + await projectService.createProject(project, user); + + const memberRole = await stores.roleStore.getRoleByName( + RoleName.MEMBER, + ); + + const memberUser = await stores.userStore.insert({ + name: 'Some Name', + email: 'member@getunleash.io', + }); + + await projectService.addAccess( + project.id, + [memberRole.id], + [], + [memberUser.id], + 'test', + ); + + const usersBefore = await projectService.getProjectUsers(project.id); + await projectService.removeUserAccess( + project.id, + memberUser.id, + 'test', + ); + const usersAfter = await projectService.getProjectUsers(project.id); + expect(usersBefore).toHaveLength(2); + expect(usersAfter).toHaveLength(1); + }); + test('should not update role for user on project when she is the owner', async () => { const project = { id: 'update-users-not-allowed',