From 132593c8547bce183c8d238578b50b92e11d18a6 Mon Sep 17 00:00:00 2001 From: Martin Artnik Date: Mon, 3 Apr 2023 11:46:32 +0200 Subject: [PATCH] Prevent removal of last manually assigned user manager [SCI-8131] --- .../access_permissions/projects_controller.rb | 10 ++++++---- .../access_permissions/protocols_controller.rb | 10 ++++++---- app/models/user_assignment.rb | 16 +++++++++++----- .../partials/_member_field.html.erb | 2 +- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/app/controllers/access_permissions/projects_controller.rb b/app/controllers/access_permissions/projects_controller.rb index bc2dfaf61..74fe04eb3 100644 --- a/app/controllers/access_permissions/projects_controller.rb +++ b/app/controllers/access_permissions/projects_controller.rb @@ -38,10 +38,10 @@ module AccessPermissions team: current_team ) - # prevent role change if it would result in no users having the user management permission + # prevent role change if it would result in no manually assigned users having the user management permission new_user_role = UserRole.find(permitted_update_params[:user_role_id]) if !new_user_role.has_permission?(ProjectPermissions::USERS_MANAGE) && - @user_assignment.last_with_permission?(ProjectPermissions::USERS_MANAGE) + @user_assignment.last_with_permission?(ProjectPermissions::USERS_MANAGE, assigned: :manually) raise ActiveRecord::RecordInvalid end @@ -106,8 +106,10 @@ module AccessPermissions user = @project.assigned_users.find(params[:user_id]) user_assignment = @project.user_assignments.find_by(user: user, team: current_team) - # prevent deletion of last user that can manage users - raise ActiveRecord::RecordInvalid if user_assignment.last_with_permission?(ProjectPermissions::USERS_MANAGE) + # prevent deletion of last manually assigned user that can manage users + if user_assignment.last_with_permission?(ProjectPermissions::USERS_MANAGE, assigned: :manually) + raise ActiveRecord::RecordInvalid + end if @project.visible? user_assignment.update!( diff --git a/app/controllers/access_permissions/protocols_controller.rb b/app/controllers/access_permissions/protocols_controller.rb index 6365f6c00..bfffb4405 100644 --- a/app/controllers/access_permissions/protocols_controller.rb +++ b/app/controllers/access_permissions/protocols_controller.rb @@ -36,10 +36,10 @@ module AccessPermissions team: current_team ) - # prevent role change if it would result in no users having the user management permission + # prevent role change if it would result in no manually assigned users having the user management permission new_user_role = UserRole.find(permitted_update_params[:user_role_id]) if !new_user_role.has_permission?(ProtocolPermissions::USERS_MANAGE) && - @user_assignment.last_with_permission?(ProtocolPermissions::USERS_MANAGE) + @user_assignment.last_with_permission?(ProtocolPermissions::USERS_MANAGE, assigned: :manually) raise ActiveRecord::RecordInvalid end @@ -102,8 +102,10 @@ module AccessPermissions user = @protocol.assigned_users.find(params[:user_id]) user_assignment = @protocol.user_assignments.find_by(user: user, team: current_team) - # prevent deletion of last user that can manage users - raise ActiveRecord::RecordInvalid if user_assignment.last_with_permission?(ProtocolPermissions::USERS_MANAGE) + # prevent deletion of last manually assigned user that can manage users + if user_assignment.last_with_permission?(ProtocolPermissions::USERS_MANAGE, assigned: :manually) + raise ActiveRecord::RecordInvalid + end Protocol.transaction do if @protocol.visible? diff --git a/app/models/user_assignment.rb b/app/models/user_assignment.rb index ccd6a35cf..a8c6f9f8b 100644 --- a/app/models/user_assignment.rb +++ b/app/models/user_assignment.rb @@ -20,17 +20,23 @@ class UserAssignment < ApplicationRecord validates :user, uniqueness: { scope: %i(assignable team_id) } + scope :with_permission, ->(permission) { joins(:user_role).where('? = ANY(user_roles.permissions)', permission) } + def last_assignable_owner? assignable_owners.count == 1 && user_role.owner? end - def last_with_permission?(permission) + def last_with_permission?(permission, assigned: nil) return false if user_role.permissions.exclude?(permission) - assignable.user_assignments.joins(:user_role) - .where.not(user: user) - .where('? = ANY(user_roles.permissions)', permission) - .none? + user_assignments = + assignable.user_assignments.joins(:user_role) + .where.not(user: user) + .with_permission(permission) + + user_assignments = user_assignments.where(assigned: assigned) if assigned + + user_assignments.none? end private diff --git a/app/views/access_permissions/partials/_member_field.html.erb b/app/views/access_permissions/partials/_member_field.html.erb index 6c7f261f8..ee75ea869 100644 --- a/app/views/access_permissions/partials/_member_field.html.erb +++ b/app/views/access_permissions/partials/_member_field.html.erb @@ -34,7 +34,7 @@ <% end %> - <% if defined?(delete_path) && !assignment.last_assignable_owner? %> + <% if defined?(delete_path) && !assignment.last_with_permission?(ProjectPermissions::USERS_MANAGE, assigned: :manually) %>
  • <%= link_to delete_path, remote: true, method: :delete, data: { action: 'remote-destroy', target: "##{item_id}" } do %>