Skip to content

Commit

Permalink
🎁 Add admin dashboard data repair jobs menu
Browse files Browse the repository at this point in the history
Adds a new menu, `Data Repair` which contains buttons to submit
RolesService repair tasks as jobs.

Jobs included are:
* CreateCollectionAccessesJob,
* CreateAdminSetAccessesJob,
* CreateCollectionTypeParticipantsJob,
* GrantWorkflowRolesForAllAdminSetsJob

Refs: #844
  • Loading branch information
LaRita Robinson committed Dec 8, 2023
1 parent 4ce94a5 commit 5130c25
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 83 deletions.
27 changes: 27 additions & 0 deletions app/controllers/admin/roles_service_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Admin
class RolesServiceController < ApplicationController
layout 'hyrax/dashboard'

def index
authorize! :update, RolesService
add_breadcrumb t(:'hyrax.controls.home'), root_path
add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path
add_breadcrumb t(:'hyrax.admin.sidebar.roles_service_jobs'), main_app.admin_roles_service_jobs_path
end

# post "admin/roles_service/:job_name_key
def update_roles
authorize! :update, RolesService
job = RolesService.valid_jobs.fetch(params[:job_name_key])

job.perform_later

respond_to do |wants|
wants.html { redirect_to main_app.admin_roles_service_jobs_path, notice: "#{job} has been submitted." }
wants.json { render json: { notice: "#{job} has been submitted." }, status: :ok }
end
end
end
end
1 change: 1 addition & 0 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def admin_permissions

super
can [:manage], [Site, Role, User]
can [:update], RolesService

can [:read, :update], Account do |account|
account == Site.account
Expand Down
199 changes: 116 additions & 83 deletions app/services/roles_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,95 +101,19 @@ def create_default_hyrax_groups_with_roles!
# creating a Hyrax::PermissionTemplateAccess record (combined with Ability#user_groups)
# means all Collections will show up in Blacklight / Solr queries.
def create_collection_accesses!
Collection.find_each do |c|
pt = Hyrax::PermissionTemplate.find_or_create_by!(source_id: c.id)
original_access_grants_count = pt.access_grants.count

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::MANAGE,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: Ability.admin_group_name
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::MANAGE,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'collection_manager'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::VIEW,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'collection_editor'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::VIEW,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'collection_reader'
)

c.reset_access_controls! if pt.access_grants.count != original_access_grants_count
end
CreateCollectionAccessesJob.perform_now
end

# Creating a Hyrax::PermissionTemplateAccess record (combined with Ability#user_groups)
# will allow Works in all AdminSets to show up in Blacklight / Solr queries.
def create_admin_set_accesses!
AdminSet.find_each do |as|
pt = Hyrax::PermissionTemplate.find_or_create_by!(source_id: as.id)
original_access_grants_count = pt.access_grants.count

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::MANAGE,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: Ability.admin_group_name
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::DEPOSIT,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'work_depositor'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::DEPOSIT,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'work_editor'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::VIEW,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'work_editor'
)

as.reset_access_controls! if pt.access_grants.count != original_access_grants_count
end
CreateAdminSetAccessesJob.perform_now
end

# Because some of the collection roles have access to every Collection within a tenant, create a
# Hyrax::CollectionTypeParticipant record for them on every Hyrax::CollectionType (except the AdminSet)
def create_collection_type_participants!
Hyrax::CollectionType.find_each do |ct|
next if ct.admin_set?

# The :collection_manager role will automatically get a Hyrax::PermissionTemplateAccess
# record when a Collection is created, giving them manage access to that Collection.
ct.collection_type_participants.find_or_create_by!(
access: Hyrax::CollectionTypeParticipant::MANAGE_ACCESS,
agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE,
agent_id: 'collection_manager'
)

# The :collection_editor role will automatically get a Hyrax::PermissionTemplateAccess
# record when a Collection is created, giving them create access to that Collection.
ct.collection_type_participants.find_or_create_by!(
access: Hyrax::CollectionTypeParticipant::CREATE_ACCESS,
agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE,
agent_id: 'collection_editor'
)
end
CreateCollectionTypeParticipantsJob.perform_now
end

# Because the collection roles are used to explicitly grant Collection creation permissions,
Expand Down Expand Up @@ -227,10 +151,7 @@ def create_admin_group_memberships!
#
# NOTE: All AdminSets must have a permission template or this will fail. Run #create_admin_set_accesses first.
def grant_workflow_roles_for_all_admin_sets!
AdminSet.find_each do |admin_set|
Hyrax::Workflow::PermissionGrantor
.grant_default_workflow_roles!(permission_template: admin_set.permission_template)
end
GrantWorkflowRolesForAllAdminSetsJob.perform_now
end

# This method is inspired by the devise_guests:delete_old_guest_users rake task in the devise-guests gem:
Expand Down Expand Up @@ -301,4 +222,116 @@ def seed_qa_users!
end
end
end

class GrantWorkflowRolesForAllAdminSetsJob < Hyrax::ApplicationJob
def perform
AdminSet.find_each do |admin_set|
Hyrax::Workflow::PermissionGrantor
.grant_default_workflow_roles!(permission_template: admin_set.permission_template)
end
end
end

class CreateCollectionAccessesJob < Hyrax::ApplicationJob
def perform
Collection.find_each do |c|
pt = Hyrax::PermissionTemplate.find_or_create_by!(source_id: c.id)
original_access_grants_count = pt.access_grants.count

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::MANAGE,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: Ability.admin_group_name
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::MANAGE,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'collection_manager'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::VIEW,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'collection_editor'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::VIEW,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'collection_reader'
)

c.reset_access_controls! if pt.access_grants.count != original_access_grants_count
end
end
end

class CreateAdminSetAccessesJob < Hyrax::ApplicationJob
def perform
AdminSet.find_each do |as|
pt = Hyrax::PermissionTemplate.find_or_create_by!(source_id: as.id)
original_access_grants_count = pt.access_grants.count

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::MANAGE,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: Ability.admin_group_name
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::DEPOSIT,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'work_depositor'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::DEPOSIT,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'work_editor'
)

pt.access_grants.find_or_create_by!(
access: Hyrax::PermissionTemplateAccess::VIEW,
agent_type: Hyrax::PermissionTemplateAccess::GROUP,
agent_id: 'work_editor'
)

as.reset_access_controls! if pt.access_grants.count != original_access_grants_count
end
end
end

class CreateCollectionTypeParticipantsJob < Hyrax::ApplicationJob
def perform
Hyrax::CollectionType.find_each do |ct|
next if ct.admin_set?

# The :collection_manager role will automatically get a Hyrax::PermissionTemplateAccess
# record when a Collection is created, giving them manage access to that Collection.
ct.collection_type_participants.find_or_create_by!(
access: Hyrax::CollectionTypeParticipant::MANAGE_ACCESS,
agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE,
agent_id: 'collection_manager'
)

# The :collection_editor role will automatically get a Hyrax::PermissionTemplateAccess
# record when a Collection is created, giving them create access to that Collection.
ct.collection_type_participants.find_or_create_by!(
access: Hyrax::CollectionTypeParticipant::CREATE_ACCESS,
agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE,
agent_id: 'collection_editor'
)
end
end
end

def self.valid_jobs
ActiveSupport::HashWithIndifferentAccess.new(
create_collection_accesses: CreateCollectionAccessesJob,
create_admin_set_accesses: CreateAdminSetAccessesJob,
create_collection_type_participants: CreateCollectionTypeParticipantsJob,
grant_workflow_roles_for_all_admin_sets: GrantWorkflowRolesForAllAdminSetsJob
)
end
end
21 changes: 21 additions & 0 deletions app/views/admin/roles_service/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<% content_for :page_title, construct_page_title(t('hyrax.admin.roles_service_jobs.header'), t('hyku.admin.title')) %>
<% provide :page_header do %>
<h1><span class="fa fa-wrench" aria-hidden="true"></span>
<%= t('hyrax.admin.roles_service_jobs.header') %></h1>
<% end %>

<div class='panel panel-default'>
<div class='panel-body'>
<div class='table-responsive'>
<table class='table table-striped datatable'>
<tbody>
<% RolesService.valid_jobs.each do |key, klass| %>
<tr>
<td><%= button_to t("hyrax.admin.roles_service_jobs.jobs.#{key}.label"), main_app.admin_update_roles_path(job_name_key: key), method: :post, class: 'btn btn-danger' %></td>
<td><%= t("hyrax.admin.roles_service_jobs.jobs.#{key}.description") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
5 changes: 5 additions & 0 deletions app/views/hyrax/dashboard/sidebar/_configuration.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,9 @@
<% end # end of configuration block %>
<%= render 'hyrax/dashboard/sidebar/menu_partials', menu: menu, section: :configuration %>
<% end %>
<% if can?(:update, RolesService) %>
<%= menu.nav_link(main_app.admin_roles_service_jobs_path) do %>
<span class="fa fa-users" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.roles_service_jobs') %></span>
<% end %>
<% end %>
<% end %>
23 changes: 23 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,35 @@ en:
favicon: Favicon
fonts: "Fonts"
themes: "Themes"
roles_service_jobs:
header: Data Repair Jobs
jobs:
create_admin_set_accesses:
label: Create Admin Set Accesses
description: "Creating a Hyrax::PermissionTemplateAccess record (combined with Ability#user_groups)
will allow Works in all AdminSets to show up in Blacklight / Solr queries."
create_collection_accesses:
label: Create Collection Accesses
description: "Because each collection role has some level of access to every Collection within a tenant,
creating a Hyrax::PermissionTemplateAccess record (combined with Ability#user_groups)
means all Collections will show up in Blacklight / Solr queries."
create_collection_type_participants:
label: Create Collection Type Participants
description: "Because some of the collection roles have access to every Collection within a tenant, create a
Hyrax::CollectionTypeParticipant record for them on every Hyrax::CollectionType (except the AdminSet)"
grant_workflow_roles_for_all_admin_sets:
label: Admin Set Workflow Roles
description: "Permissions to deposit Works are controlled by Workflow Roles on individual AdminSets.
In order for Hyrax::Group and User records who have either the 'Work Editor' or 'Work Depositor' Role
to have the correct permissions for Works, we grant them Workflow Roles for all AdminSets.
NOTE: All AdminSets must have a permission template or this will fail. Run 'Create Admin Set Accesses' first."
sidebar:
accounts: Accounts
activity_summary: Activity Summary
labels: Labels
manage_groups: Manage Groups
system_status: System Status
roles_service_jobs: Data Repair
users:
activate:
confirmation: Are you sure you want to activate the user "%{user}"?
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@
resources :users, only: %i[index create destroy], param: :user_id, controller: 'group_users'
resources :roles, only: %i[index create destroy], param: :role_id, controller: 'group_roles'
end
post "roles_service/:job_name_key", to: "roles_service#update_roles", as: :update_roles
get "roles_service", to: "roles_service#index", as: :roles_service_jobs
end

# OVERRIDE here to add featured collection routes
Expand Down
40 changes: 40 additions & 0 deletions spec/controllers/admin/roles_service_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

RSpec.describe Admin::RolesServiceController, type: :controller do
context 'as an anonymous user' do
describe 'GET #index' do
subject { get :index }

it { is_expected.to redirect_to new_user_session_path }
end
end

context 'as an admin user' do
before { sign_in create(:admin) }

describe 'GET #index' do
subject { get :index }

it { is_expected.to render_template('layouts/hyrax/dashboard') }
it { is_expected.to render_template('admin/roles_service/index') }
end
end

context 'as an admin user' do
before { sign_in create(:admin) }

describe 'GET #index' do
subject { get :index }

it { is_expected.to render_template('layouts/hyrax/dashboard') }
it { is_expected.to render_template('admin/roles_service/index') }
end

describe 'POST #update_roles' do
it 'submits a job when it receives a valid job name' do
expect(RolesService::CreateCollectionAccessesJob).to receive(:perform_later)
post :update_roles, params: { job_name_key: :create_collection_accesses }
end
end
end
end
13 changes: 13 additions & 0 deletions spec/routing/admin/roles_service_routing_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

RSpec.describe Admin::RolesServiceController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(get: "/admin/roles_service").to route_to("admin/roles_service#index")
end

it "routes to #update_roles via POST" do
expect(post: "/admin/roles_service/create_collection_accesses").to route_to("admin/roles_service#update_roles", job_name_key: 'create_collection_accesses')
end
end
end

0 comments on commit 5130c25

Please sign in to comment.