From 5130c25ad46c9d480be12d6c72afc58c232222fc Mon Sep 17 00:00:00 2001 From: LaRita Robinson Date: Fri, 8 Dec 2023 11:27:29 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=81=20Add=20admin=20dashboard=20data?= =?UTF-8?q?=20repair=20jobs=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new menu, `Data Repair` which contains buttons to submit RolesService repair tasks as jobs. Jobs included are: * CreateCollectionAccessesJob, * CreateAdminSetAccessesJob, * CreateCollectionTypeParticipantsJob, * GrantWorkflowRolesForAllAdminSetsJob Refs: https://github.com/scientist-softserv/palni-palci/issues/844 --- .../admin/roles_service_controller.rb | 27 +++ app/models/ability.rb | 1 + app/services/roles_service.rb | 199 ++++++++++-------- app/views/admin/roles_service/index.html.erb | 21 ++ .../dashboard/sidebar/_configuration.html.erb | 5 + config/locales/en.yml | 23 ++ config/routes.rb | 2 + .../admin/roles_service_controller_spec.rb | 40 ++++ .../admin/roles_service_routing_spec.rb | 13 ++ 9 files changed, 248 insertions(+), 83 deletions(-) create mode 100644 app/controllers/admin/roles_service_controller.rb create mode 100644 app/views/admin/roles_service/index.html.erb create mode 100644 spec/controllers/admin/roles_service_controller_spec.rb create mode 100644 spec/routing/admin/roles_service_routing_spec.rb diff --git a/app/controllers/admin/roles_service_controller.rb b/app/controllers/admin/roles_service_controller.rb new file mode 100644 index 000000000..f7f91a28b --- /dev/null +++ b/app/controllers/admin/roles_service_controller.rb @@ -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 diff --git a/app/models/ability.rb b/app/models/ability.rb index c433ad198..e6a19f561 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -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 diff --git a/app/services/roles_service.rb b/app/services/roles_service.rb index c5c6a5de8..1acfe2cf9 100644 --- a/app/services/roles_service.rb +++ b/app/services/roles_service.rb @@ -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, @@ -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: @@ -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 diff --git a/app/views/admin/roles_service/index.html.erb b/app/views/admin/roles_service/index.html.erb new file mode 100644 index 000000000..93307704a --- /dev/null +++ b/app/views/admin/roles_service/index.html.erb @@ -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 %> +

+ <%= t('hyrax.admin.roles_service_jobs.header') %>

+<% end %> + +
+
+
+ + + <% RolesService.valid_jobs.each do |key, klass| %> + + + + + <% end %> + +
<%= 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' %><%= t("hyrax.admin.roles_service_jobs.jobs.#{key}.description") %>
+
+
\ No newline at end of file diff --git a/app/views/hyrax/dashboard/sidebar/_configuration.html.erb b/app/views/hyrax/dashboard/sidebar/_configuration.html.erb index d4859b344..7ea7aacba 100644 --- a/app/views/hyrax/dashboard/sidebar/_configuration.html.erb +++ b/app/views/hyrax/dashboard/sidebar/_configuration.html.erb @@ -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 %> + <%= t('hyrax.admin.sidebar.roles_service_jobs') %> + <% end %> + <% end %> <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 7962b44fa..6758d4405 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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}"? diff --git a/config/routes.rb b/config/routes.rb index 9132e685b..8483dcec9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/spec/controllers/admin/roles_service_controller_spec.rb b/spec/controllers/admin/roles_service_controller_spec.rb new file mode 100644 index 000000000..0cb2b98b8 --- /dev/null +++ b/spec/controllers/admin/roles_service_controller_spec.rb @@ -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 diff --git a/spec/routing/admin/roles_service_routing_spec.rb b/spec/routing/admin/roles_service_routing_spec.rb new file mode 100644 index 000000000..bd1d39756 --- /dev/null +++ b/spec/routing/admin/roles_service_routing_spec.rb @@ -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