Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4819 manage super user roles #5047

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9e1376b
Updated organization user table to show edit options for super admins…
Benjamin-Couey Feb 18, 2025
d719cd4
Fixed error trying to access super admin role's resource
Benjamin-Couey Feb 18, 2025
7f51385
Updated organization user table to always show edit user button to su…
Benjamin-Couey Feb 18, 2025
156e02b
Added tests to specify org admins can promote and demote users
Benjamin-Couey Feb 18, 2025
a97ebc1
Updated tests to run on both normal and super admin users
Benjamin-Couey Feb 19, 2025
ccab0f0
Updated organisation request tests to run on both normal and super ad…
Benjamin-Couey Feb 20, 2025
ed54cba
Moved checks on request handled by admin controller to more appropria…
Benjamin-Couey Feb 24, 2025
a40b865
Added user factory to create super admin that is also an org admin
Benjamin-Couey Feb 24, 2025
151337f
Updated shared_examples to handle both normal users and super admins …
Benjamin-Couey Feb 24, 2025
4f87454
Forgot to have org system tests also test with a super admin logged in
Benjamin-Couey Feb 24, 2025
8841ea4
Fixed dropdown div always being there instead of only when the dropdo…
Benjamin-Couey Feb 25, 2025
ba34e7a
Updated admin user request tests to run on both normal and super admi…
Benjamin-Couey Feb 26, 2025
2043e09
Updated add role system test to run on both normal and super admin us…
Benjamin-Couey Feb 26, 2025
da53615
Changes made by linter
Benjamin-Couey Feb 26, 2025
4f1aaa9
Merge branch 'main' into 4819-manage-super-user-roles
Benjamin-Couey Feb 27, 2025
7ecca27
Changed kind to org_role as it was only used on org user list, made i…
Benjamin-Couey Mar 3, 2025
a1307e0
Merge branch 'main' into 4819-manage-super-user-roles
Benjamin-Couey Mar 3, 2025
0a34a21
Updated org user list to show promote/demote buttons to super admins,…
Benjamin-Couey Mar 6, 2025
d7d78b0
Fixed context not actually signing in as a super admin
Benjamin-Couey Mar 6, 2025
664fa63
Merge branch 'main' into 4819-manage-super-user-roles
Benjamin-Couey Mar 6, 2025
c0d9283
Removed tests for #show while logged in as super admin as, while the …
Benjamin-Couey Mar 7, 2025
2e59b55
Refactored promote, demote, remove user shared_examples to explicilty…
Benjamin-Couey Mar 7, 2025
a918ab3
Merge branch 'main' into 4819-manage-super-user-roles
Benjamin-Couey Mar 7, 2025
931a89b
Forgot to run linter
Benjamin-Couey Mar 7, 2025
32ca8e2
Undid changes that replaced has_role_cached? with has_role?
Benjamin-Couey Mar 10, 2025
9649829
Merge branch 'main' into 4819-manage-super-user-roles
Benjamin-Couey Mar 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,11 @@ def invitation_status
"invited" if invitation_sent_at.present?
end

def kind
return "super" if has_cached_role?(Role::SUPER_ADMIN)
def org_role
return "admin" if has_cached_role?(Role::ORG_ADMIN, organization)
return "normal" if has_cached_role?(Role::ORG_USER, organization)
return "partner" if has_cached_role?(Role::PARTNER, partner)

"normal"
"not a member"
end

def is_admin?(org)
Expand Down
4 changes: 3 additions & 1 deletion app/views/admin/users/_roles.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
<% user.roles.each do |role| %>
<tr>
<td><%= role.title %></td>
<td><%= role.resource.name %> (id: <%= role.resource.id %>)</td>
<td>
<%= role.resource&.name || "Super Admin" %> <%= role.resource&.id ? "(id: #{role.resource&.id})" : "" %>
</td>
<td class="text-right">
<%= delete_button_to admin_user_remove_role_path(user, role_id: role.id),
confirm: "Are you sure you want to remove this role?" %>
Expand Down
20 changes: 8 additions & 12 deletions app/views/users/_organization_user.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,37 @@
<%= user.display_name %>
</td>
<td><%= user.email %></td>
<td><%= user.kind %> </td>
<td><%= user.org_role %> </td>
<td><%= user.current_sign_in_at&.strftime('%Y/%m/%d') %></td>
<td><%= user.invitation_status %></td>
<td nowrap><%= reinvite_user_link(user) %></td>
<td>
<% unless user.has_cached_role?(Role::SUPER_ADMIN) || user.has_cached_role?(Role::ORG_ADMIN, current_organization) %>
<% unless user.has_cached_role?(Role::ORG_ADMIN, current_organization) %>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="<%= dom_id(user, "dropdownMenu") %>" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Actions
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>
<% if current_user.has_cached_role?(Role::SUPER_ADMIN) %>
<%= edit_button_to(edit_admin_user_path(user), { text: 'Edit User' }) %>
<% else %>
<%= edit_button_to(
promote_to_org_admin_organization_path(user_id: user.id),
{text: 'Promote to Admin'},
{method: :post, rel: "nofollow", data: {confirm: 'This will promote the user to admin status. Are you sure that you want to submit this?', size: 'xs'}}
) %>
<% end %>
<%= edit_button_to(
promote_to_org_admin_organization_path(user_id: user.id),
{text: 'Promote to Admin'},
{method: :post, rel: "nofollow", data: {confirm: 'This will promote the user to admin status. Are you sure that you want to submit this?', size: 'xs'}}
) %>
</li>
<li>
<%= delete_button_to remove_user_organization_path(user_id: user.id),
{id: dom_id(user), method: :post, class: 'deactivate', text: "Remove User", rel: "nofollow", data: {confirm: 'This will revoke the user\'s organization permissions. Are you sure that you want to submit this?', size: 'xs'}} %>
</li>
</ul>
</div>

<% end %>
<% if current_user.is_admin?(current_organization) && user.has_cached_role?(Role::ORG_ADMIN, current_organization) %>
<%= edit_button_to demote_to_user_organization_path(user_id: user.id, organization_name: current_organization.short_name),
{text: 'Demote to User'},
{method: :post, rel: "nofollow", data: {confirm: 'This will demote the admin to user status. Are you sure that you want to submit this?', size: 'xs'}} unless user.id == current_user.id %>
<% end %>
</td>
</td>
</tr>
7 changes: 7 additions & 0 deletions spec/factories/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@
resource_type: Role::ORG_ADMIN)
end
end

factory :super_admin_org_admin do
name { "Administrative User And Org Admin" }
after(:create) do |user|
user.add_role(Role::SUPER_ADMIN)
end
end
end

factory :super_admin do
Expand Down
10 changes: 6 additions & 4 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,12 @@
expect(build(:user, invitation_sent_at: Time.zone.parse("2018-10-10 00:00:00"), invitation_accepted_at: Time.zone.parse("2018-10-11 00:00:00"), current_sign_in_at: Time.zone.parse("2018-10-23 00:00:00")).invitation_status).to eq("joined")
end

it "#kind" do
expect(create(:super_admin).kind).to eq("super")
expect(create(:organization_admin).kind).to eq("admin")
expect(create(:user).kind).to eq("normal")
it "#org_role" do
expect(create(:super_admin).org_role).to eq("normal")
expect(create(:super_admin_org_admin).org_role).to eq("admin")
expect(create(:organization_admin).org_role).to eq("admin")
expect(create(:user).org_role).to eq("normal")
expect(create(:partner_user).org_role).to eq("not a member")
end

it "#reinvitable?" do
Expand Down
11 changes: 9 additions & 2 deletions spec/requests/admin/organizations_requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@
it "returns http success" do
get admin_organizations_path
expect(response).to be_successful
expect(response.body).to include(organization.name)
expect(response.body).to include(organization.email)
expect(response.body).to include(organization.created_at.strftime("%Y-%m-%d"))
expect(response.body).to include(organization.display_last_distribution_date)
end
end

Expand Down Expand Up @@ -184,8 +188,11 @@
it "provides links to edit the user" do
get admin_organization_path({ id: organization.id })

expect(response.body).to include("Edit User")
expect(response.body).to include(edit_admin_user_path(user.id))
expect(response.body).to include("Actions")
expect(response.body).to include('Promote to Admin')
expect(response.body).to include(promote_to_org_admin_organization_path(user_id: user.id))
expect(response.body).to include('Remove User')
expect(response.body).to include(remove_user_organization_path(user_id: user.id))
end
end
end
Expand Down
39 changes: 29 additions & 10 deletions spec/requests/admin/users_requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,30 @@
end

describe '#add_role' do
context 'with no errors' do
it 'should call the service and redirect back' do
shared_examples "add role check" do |user_factory|
let!(:user_to_modify) { create(user_factory, name: "User to modify", organization: organization) }

it "should call the service and redirect back", :aggregate_failures do
allow(AddRoleService).to receive(:call)
post admin_user_add_role_path(user_id: user.id,
post admin_user_add_role_path(user_id: user_to_modify.id,
resource_type: Role::ORG_ADMIN,
resource_id: organization.id),
headers: { 'HTTP_REFERER' => '/back/url'}
expect(AddRoleService).to have_received(:call).with(user_id: user.id.to_s,
expect(AddRoleService).to have_received(:call).with(user_id: user_to_modify.id.to_s,
resource_type: Role::ORG_ADMIN.to_s,
resource_id: organization.id.to_s)
expect(flash[:notice]).to eq('Role added!')
expect(response).to redirect_to('/back/url')
end
end

context 'with no errors' do
include_examples "add role check", :user
context "modifying another super admin" do
include_examples "add role check", :super_admin
end
end

context 'with errors' do
it 'should redirect back with error' do
allow(AddRoleService).to receive(:call).and_raise('OH NOES')
Expand All @@ -85,19 +94,29 @@
end

describe '#remove_role' do
context 'with no errors' do
it 'should call the service and redirect back' do
shared_examples "remove role check" do |user_factory|
let!(:user_to_modify) { create(user_factory, name: "User to modify", organization: organization) }

it "should call the service and redirect back", :aggregate_failures do
role_to_remove_id = user_to_modify.roles.find_by(name: Role::ORG_ADMIN, resource_id: organization.id).id
allow(RemoveRoleService).to receive(:call)
delete admin_user_remove_role_path(user_id: user.id,
role_id: 123),
delete admin_user_remove_role_path(user_id: user_to_modify.id,
role_id: role_to_remove_id),
headers: { 'HTTP_REFERER' => '/back/url'}
expect(RemoveRoleService).to have_received(:call).with(user_id: user.id.to_s,
role_id: '123')
expect(RemoveRoleService).to have_received(:call).with(user_id: user_to_modify.id.to_s,
role_id: role_to_remove_id.to_s)
expect(flash[:notice]).to eq('Role removed!')
expect(response).to redirect_to('/back/url')
end
end

context 'with no errors' do
include_examples "remove role check", :organization_admin
context 'modifying another super admin' do
include_examples "remove role check", :super_admin_org_admin
end
end

context 'with errors' do
it 'should redirect back with error' do
allow(RemoveRoleService).to receive(:call).and_raise('OH NOES')
Expand Down
Loading