From 269b3a67fbaeffa0dc87921af2e1611d864236e2 Mon Sep 17 00:00:00 2001 From: Florian M Date: Mon, 6 Feb 2023 10:24:04 +0100 Subject: [PATCH] Prevent Deactivaing Orga Owner --- app/controllers/UserController.scala | 13 ++++++++++--- app/models/user/User.scala | 24 +++++++++++++++++------- conf/messages | 5 +++-- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/app/controllers/UserController.scala b/app/controllers/UserController.scala index 040104514ac..76354ed1d3f 100755 --- a/app/controllers/UserController.scala +++ b/app/controllers/UserController.scala @@ -348,9 +348,15 @@ class UserController @Inject()(userService: UserService, adminCount <- userDAO.countAdminsForOrganization(user._organization) _ <- bool2Fox(adminCount > 1) ?~> "user.lastAdmin" } yield () - } else { - Fox.successful(()) - } + } else Fox.successful(()) + + private def preventZeroOwners(user: User, isActive: Boolean) = + if (user.isOrganizationOwner && !user.isDeactivated && !isActive) { + for { + ownerCount <- userDAO.countOwnersForOrganization(user._organization) + _ <- bool2Fox(ownerCount > 1) ?~> "user.lastOwner" + } yield () + } else Fox.successful(()) @ApiOperation(hidden = true, value = "") def update(userId: String): Action[JsValue] = sil.SecuredAction.async(parse.json) { implicit request => @@ -387,6 +393,7 @@ class UserController @Inject()(userService: UserService, _ <- checkNoActivateBeyondLimit(user, isActive) _ <- checkSuperUserOnlyUpdates(user, oldEmail, email)(issuingUser) _ <- preventZeroAdmins(user, isAdmin) + _ <- preventZeroOwners(user, isActive) teams <- Fox.combined(assignedMemberships.map(t => teamDAO.findOne(t.teamId)(GlobalAccessContext) ?~> "team.notFound" ~> NOT_FOUND)) oldTeamMemberships <- userService.teamMembershipsFor(user._id) diff --git a/app/models/user/User.scala b/app/models/user/User.scala index 57bb39a1b48..9644d244da6 100644 --- a/app/models/user/User.scala +++ b/app/models/user/User.scala @@ -184,17 +184,19 @@ class UserDAO @Inject()(sqlClient: SqlClient)(implicit ec: ExecutionContext) def findContributorsForAnnotation(annotationId: ObjectId)(implicit ctx: DBAccessContext): Fox[List[User]] = for { accessQuery <- accessQueryFromAccessQ(listAccessQ) - result <- run( - q"""select $columns from $existingCollectionName - where _id in (select _user from webknossos.annotation_contributors where _annotation = $annotationId) and $accessQuery""" - .as[UsersRow]) + result <- run(q"""SELECT $columns + FROM $existingCollectionName + WHERE _id in + (SELECT _user FROM webknossos.annotation_contributors WHERE _annotation = $annotationId) + AND NOT isUnlisted + AND $accessQuery""".as[UsersRow]) parsed <- parseAll(result) } yield parsed def countAllForOrganization(organizationId: ObjectId): Fox[Int] = for { resultList <- run( - q"select count(_id) from $existingCollectionName where _organization = $organizationId and not isDeactivated and not isUnlisted" + q"select count(*) from $existingCollectionName where _organization = $organizationId and not isDeactivated and not isUnlisted" .as[Int]) result <- resultList.headOption } yield result @@ -202,14 +204,22 @@ class UserDAO @Inject()(sqlClient: SqlClient)(implicit ec: ExecutionContext) def countAdminsForOrganization(organizationId: ObjectId): Fox[Int] = for { resultList <- run( - q"select count(_id) from $existingCollectionName where _organization = $organizationId and isAdmin and not isUnlisted" + q"select count(*) from $existingCollectionName where _organization = $organizationId and isAdmin and not isUnlisted" + .as[Int]) + result <- resultList.headOption + } yield result + + def countOwnersForOrganization(organizationId: ObjectId): Fox[Int] = + for { + resultList <- run( + q"select count(*) from $existingCollectionName where _organization = $organizationId and isOrganizationOwner and not isUnlisted" .as[Int]) result <- resultList.headOption } yield result def countIdentitiesForMultiUser(multiUserId: ObjectId): Fox[Int] = for { - resultList <- run(q"select count(_id) from $existingCollectionName where _multiUser = $multiUserId".as[Int]) + resultList <- run(q"select count(*) from $existingCollectionName where _multiUser = $multiUserId".as[Int]) result <- resultList.headOption } yield result diff --git a/conf/messages b/conf/messages index 5b59b009f73..a04496cffc8 100644 --- a/conf/messages +++ b/conf/messages @@ -37,7 +37,7 @@ organization.list.failed=Failed to retrieve list of organizations. organization.name.invalid=This organization name contains illegal characters. Please only use letters and numbers. organization.name.alreadyInUse=This name is already claimed by a different organization and not available anymore. Please choose a different name. organization.alreadyJoined=Your account is already associated with the selected organization. -organization.users.userLimitReached=Cannot add new user to this organization because it would exceed the organization’s user limit. Please ask the organization owner to upgrade. +organization.users.userLimitReached=Cannot add new user to this organization because it would exceed the organization’s user limit. Please ask the organization owner to upgrade. organization.pricingUpgrades.notAuthorized=You are not authorized to request any changes to your organization WEBKNOSSOS plan. Please ask the organization owner for permission. termsOfService.versionMismatch=Terms of service version mismatch. Current version is {0}, received acceptance for {1} @@ -46,7 +46,8 @@ user.notFound=User not found user.noAdmin=Access denied. Only admin users can execute this operation. user.deactivated=Your account has not been activated by an admin yet. Please contact your organization’s admin for help. user.noSelfDeactivate=You cannot deactivate yourself. Please contact an admin to do it for you. -user.lastAdmin=Your account is the last remaining admin in your organzation. You cannot remove admin privileges from your account. +user.lastAdmin=This user is the last remaining admin in your organzation. You cannot remove admin privileges from this account. +user.lastOwner=Cannot deactivate the organization owner. Please talk to the WEBKNOSSOS team to transfer organization ownership. user.email.alreadyInUse=This email address is already in use user.email.onlySuperUserCanChange=Only super users can change emails of users with multiple organization accounts