Skip to content

Commit

Permalink
Merge pull request #1289 from sul-dlss/984-manage-catkey-bulk-action
Browse files Browse the repository at this point in the history
New manage catkey bulk action
  • Loading branch information
jcoyne authored Jan 23, 2019
2 parents 74ac6ca + cc61d6d commit 7f18e2a
Show file tree
Hide file tree
Showing 16 changed files with 285 additions and 148 deletions.
3 changes: 3 additions & 0 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ RSpec/AnyInstance:
- 'spec/features/set_governing_apo_spec.rb'
- 'spec/integration/apo_spec.rb'
- 'spec/jobs/modsulator_job_spec.rb'
- 'spec/jobs/generic_job_spec.rb'
- 'spec/jobs/release_object_job_spec.rb'
- 'spec/jobs/set_governing_apo_job_spec.rb'

Expand Down Expand Up @@ -197,6 +198,7 @@ RSpec/ExpectInHook:
- 'spec/controllers/items_controller_spec.rb'
- 'spec/forms/apo_form_spec.rb'
- 'spec/jobs/release_object_job_spec.rb'
- 'spec/jobs/generic_job_spec.rb'
- 'spec/models/dor_object_workflow_status_spec.rb'
- 'spec/search_builders/argo/access_controls_enforcement_spec.rb'
- 'spec/views/files/index.html.erb_spec.rb'
Expand Down Expand Up @@ -224,6 +226,7 @@ RSpec/InstanceVariable:
- 'spec/jobs/descmetadata_download_job_spec.rb'
- 'spec/jobs/modsulator_job_spec.rb'
- 'spec/jobs/set_governing_apo_job_spec.rb'
- 'spec/jobs/generic_job_spec.rb'
- 'spec/models/bulk_action_spec.rb'
- 'spec/models/report_spec.rb'
- 'spec/search_builders/argo/access_controls_enforcement_spec.rb'
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/bulk_actions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def bulk_action_params
:description,
:pids,
manage_release: [:tag, :what, :who, :to],
set_governing_apo: [:new_apo_id]
set_governing_apo: [:new_apo_id],
manage_catkeys: [:catkeys]
)
end

Expand Down
7 changes: 3 additions & 4 deletions app/jobs/descmetadata_download_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class DescmetadataDownloadJob < GenericJob
# @param [Hash] params Custom params for this job
# requires `:pids` (an Array of pids) and output_directory
def perform(bulk_action_id, params)
@pids = params[:pids]
zip_filename = generate_zip_filename(params[:output_directory])
with_bulk_action_log do |log|
# Fail with an error message if the calling BulkAction doesn't exist
Expand All @@ -20,11 +21,9 @@ def perform(bulk_action_id, params)
log.puts("argo.bulk_metadata.bulk_log_job_complete #{Time.now.strftime(TIME_FORMAT)}")
else
start_log(log, bulk_action.user_id, '', bulk_action.description)

bulk_action.update(druid_count_total: params[:pids].length)
bulk_action.save
update_druid_count
::Zip::File.open(zip_filename, Zip::File::CREATE) do |zip_file|
params[:pids].each { |current_druid| process_druid(current_druid, log, zip_file) }
pids.each { |current_druid| process_druid(current_druid, log, zip_file) }
zip_file.close
end
end
Expand Down
44 changes: 44 additions & 0 deletions app/jobs/generic_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class GenericJob < ActiveJob::Base
# A somewhat easy to understand and informative time stamp format
TIME_FORMAT = '%Y-%m-%d %H:%M%P'

attr_reader :pids

before_perform do |_job|
bulk_action.reset_druid_counts
end
Expand Down Expand Up @@ -46,4 +48,46 @@ def with_bulk_action_log
yield(log_buffer)
end
end

def ability
@ability ||= begin
user = bulk_action.user
# Since a user doesn't persist its groups, we need to pass the groups in here.
user.set_groups_to_impersonate(groups)
Ability.new(user)
end
end

def string_to_boolean(string)
case string
when 'true'
true
when 'false'
false
end
end

def update_druid_count
bulk_action.update(druid_count_total: pids.length)
bulk_action.save
end

def can_manage?(pid)
ability.can?(:manage_item, Dor.find(pid))
end

def open_new_version(object, description)
raise "#{Time.current} Unable to open new version for #{object.pid} (bulk_action.id=#{bulk_action.id})" unless DorObjectWorkflowStatus.new(object.pid).can_open_version?

vers_md_upd_info = {
significance: 'minor',
description: description,
opening_user_name: bulk_action.user.to_s
}
Dor::Services::Client.object(object.pid).open_new_version(vers_md_upd_info: vers_md_upd_info)
end

def close_version(object)
Dor::Services::Client.object(object.pid).close_version
end
end
53 changes: 53 additions & 0 deletions app/jobs/manage_catkey_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# frozen_string_literal: true

##
# Job to update/add catkey to objects
class ManageCatkeyJob < GenericJob
queue_as :manage_catkey

attr_reader :catkeys, :groups
##
# A job that allows a user to specify a list of pids and a list of catkeys to be associated with these pids
# @param [Integer] bulk_action_id GlobalID for a BulkAction object
# @param [Hash] params additional parameters that an Argo job may need
# @option params [Array] :pids required list of pids
# @option params [Hash] :manage_catkeys (required) list of catkeys to be associated 1:1 with pids in order
# @option params [Array] :groups the groups the user belonged to when the started the job. Required for permissions check
def perform(bulk_action_id, params)
@catkeys = params[:manage_catkeys]['catkeys'].split.map(&:strip)
@groups = params[:groups]
@pids = params[:pids]
@current_user = params[:user]
with_bulk_action_log do |log|
log.puts("#{Time.current} Starting ManageCatkeyJob for BulkAction #{bulk_action_id}")
update_druid_count

pids.each_with_index { |current_druid, i| update_catkey(current_druid, @catkeys[i], log) }
log.puts("#{Time.current} Finished ManageCatkeyJob for BulkAction #{bulk_action_id}")
end
end

private

def update_catkey(current_druid, new_catkey, log)
log.puts("#{Time.current} Beginning ManageCatkeyJob for #{current_druid}")
current_obj = Dor.find(current_druid)
unless can_manage?(current_druid)
log.puts("#{Time.current} Not authorized for #{current_druid}")
return
end
log.puts("#{Time.current} Adding catkey of #{new_catkey}")
begin
open_new_version(current_obj, "Catkey updated to #{new_catkey}") unless current_obj.allows_modification?
current_obj.catkey = new_catkey
current_obj.save
close_version(current_obj) if current_obj.new_version_open?
bulk_action.increment(:druid_count_success).save
log.puts("#{Time.current} Catkey added/updated/removed successfully")
rescue StandardError => e
log.puts("#{Time.current} Catkey failed #{e.class} #{e.message}")
bulk_action.increment(:druid_count_fail).save
return
end
end
end
29 changes: 1 addition & 28 deletions app/jobs/release_object_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class ReleaseObjectJob < GenericJob
queue_as :release_object

attr_reader :manage_release, :pids, :groups
attr_reader :manage_release, :groups
##
# This is a shameless green approach to a job that calls release from dor
# services app and then kicks off release WF.
Expand All @@ -31,10 +31,6 @@ def perform(bulk_action_id, params)
end
end

def can_manage?(pid)
ability.can?(:manage_item, Dor.find(pid))
end

private

def release_object(current_druid, log)
Expand Down Expand Up @@ -67,27 +63,4 @@ def release_object(current_druid, log)
bulk_action.increment(:druid_count_fail).save
end
end

def ability
@ability ||= begin
user = bulk_action.user
# Since a user doesn't persist its groups, we need to pass the groups in here.
user.set_groups_to_impersonate(groups)
Ability.new(user)
end
end

def string_to_boolean(string)
case string
when 'true'
true
when 'false'
false
end
end

def update_druid_count
bulk_action.update(druid_count_total: pids.length)
bulk_action.save
end
end
7 changes: 0 additions & 7 deletions app/jobs/remote_indexing_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
class RemoteIndexingJob < GenericJob
queue_as :indexing_remote

attr_reader :pids

def perform(bulk_action_id, params)
@pids = params[:pids]

Expand All @@ -33,9 +31,4 @@ def reindex_druid_safely(current_druid, log_buffer)
log_buffer.puts("#{Time.current} RemoteIndexingJob: Unexpected error for #{current_druid} (bulk_action.id=#{bulk_action.id}): #{e}")
bulk_action.increment(:druid_count_fail).save
end

def update_druid_count
bulk_action.update(druid_count_total: pids.length)
bulk_action.save
end
end
29 changes: 2 additions & 27 deletions app/jobs/set_governing_apo_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class SetGoverningApoJob < GenericJob
queue_as :set_governing_apo

attr_reader :pids, :new_apo_id, :groups
attr_reader :new_apo_id, :groups

# @param [Integer] bulk_action_id GlobalID for a BulkAction object
# @param [Hash] params additional parameters that an Argo job may need
Expand Down Expand Up @@ -39,7 +39,7 @@ def set_governing_apo_and_index_safely(current_druid, log)

check_can_set_governing_apo!(current_obj)

open_new_version(current_obj) unless current_obj.allows_modification?
open_new_version(current_obj, 'Set new governing APO') unless current_obj.allows_modification?

current_obj.admin_policy_object = Dor.find(new_apo_id)
current_obj.identityMetadata.adminPolicy = nil if current_obj.identityMetadata.adminPolicy # no longer supported, erase if present as a bit of remediation
Expand All @@ -57,29 +57,4 @@ def check_can_set_governing_apo!(obj)
raise "#{obj.pid} is not open for modification" unless obj.allows_modification?
raise "user not authorized to move #{obj.pid} to #{new_apo_id}" unless ability.can?(:manage_governing_apo, obj, new_apo_id)
end

def ability
@ability ||= begin
user = bulk_action.user
# Since a user doesn't persist its groups, we need to pass the groups in here.
user.set_groups_to_impersonate(groups)
Ability.new(user)
end
end

def update_druid_count
bulk_action.update(druid_count_total: pids.length)
bulk_action.save
end

def open_new_version(object)
raise "#{Time.current} Unable to open new version for #{object.pid} (bulk_action.id=#{bulk_action.id})" unless DorObjectWorkflowStatus.new(object.pid).can_open_version?

vers_md_upd_info = {
significance: 'minor',
description: 'Set new governing APO',
opening_user_name: bulk_action.user.to_s
}
Dor::Services::Client.object(object.pid).open_new_version(vers_md_upd_info: vers_md_upd_info)
end
end
5 changes: 3 additions & 2 deletions app/models/bulk_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class BulkAction < ActiveRecord::Base
belongs_to :user
validates :action_type, inclusion: { in: %w(GenericJob DescmetadataDownloadJob ReleaseObjectJob RemoteIndexingJob SetGoverningApoJob) }
validates :action_type, inclusion: { in: %w(GenericJob DescmetadataDownloadJob ReleaseObjectJob RemoteIndexingJob SetGoverningApoJob ManageCatkeyJob) }
after_create do
create_output_directory
create_log_file
Expand All @@ -11,7 +11,7 @@ class BulkAction < ActiveRecord::Base
before_destroy :remove_output_directory

# A virtual attribute used for job creation but not persisted
attr_accessor :pids, :manage_release, :set_governing_apo
attr_accessor :pids, :manage_release, :set_governing_apo, :manage_catkeys
attr_accessor :groups # the groups the user was a member of when they launched the job

def file(filename)
Expand Down Expand Up @@ -58,6 +58,7 @@ def job_params
output_directory: output_directory,
manage_release: manage_release,
set_governing_apo: set_governing_apo,
manage_catkeys: manage_catkeys,
groups: groups
}
end
Expand Down
13 changes: 12 additions & 1 deletion app/views/bulk_actions/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
<% end %>

<% if false #multiline comment %>
This button/radio form element is used to define Bulk Action Job types that
This button/radio form element is used to define Bulk Action Job types that
a user can select from. The `.tab-content` area below it can define a
description and additional form input used for each type of custom job.
<% end %>
<!-- TODO: this should probably be a different UI element, like a drop down list, since its getting a bit long-->
<div class='form-group'>
<div class='btn-group' data-toggle='buttons'>
<label href='#desc_metadata_download_custom_options' class='btn btn-default active' data-toggle='tab'>
Expand All @@ -35,6 +36,10 @@
<%= f.radio_button(:action_type, 'RemoteIndexingJob', autocomplete: 'off') %>
Reindex
</label>
<label href='#manage_catkey_options' data-toggle='tab' class='btn btn-default'>
<%= f.radio_button(:action_type, 'ManageCatkeyJob', autocomplete: 'off') %>
Manage Catkeys
</label>
</div>
<div class='tab-content'>
Expand All @@ -60,6 +65,12 @@
Reindexes the DOR object to Solr
</span>
</div>
<div role='tabpanel' class= 'tab-pane' id='manage_catkey_options'>
<span class='help-block'>
Adds or updates catkeys associated with objects. You need two lists: druids and catkeys, and they need to correspond 1:1 in the correct order.
</span>
<%= render 'bulk_actions/forms/manage_catkey_form' %>
</div>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions app/views/bulk_actions/forms/_manage_catkey_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class='form-group'>
<label>List of catkeys*</label>
<textarea id='bulk_action_manage_catkeys_catkeys' name='bulk_action[manage_catkeys][catkeys]' class='form-control' rows='10'>
</textarea>
<span class='help-block'>* must be same length as list of druids and in same order to update ... add a blank line to delete existing catkey</span>
</div>
7 changes: 7 additions & 0 deletions spec/controllers/bulk_actions_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@
expect(assigns(:bulk_action).pids).to eq "druid:a\ndruid:b\ndruid:c"
end

it 'assigns @bulk_action with catkeys passed in from form' do
post :create, params: { bulk_action: { action_type: 'ManageCatkeyJob', pids: '', 'manage_catkeys[catkeys]' => "1234\n5678" } }
expect(assigns(:bulk_action)).to be_an BulkAction
expect(assigns(:bulk_action).send(:job_params)).to be_an Hash
expect(assigns(:bulk_action).send(:job_params)).to include(manage_catkeys: { 'catkeys' => "1234\n5678" })
end

it 'creates a new BulkAction' do
expect do
post :create, params: { bulk_action: { action_type: 'GenericJob', pids: '' } }
Expand Down
Loading

0 comments on commit 7f18e2a

Please sign in to comment.