bulk_ops 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/app/assets/images/bulk_ops/github_logo.png +0 -0
- data/app/assets/javascripts/bulk_ops.js +14 -0
- data/app/assets/javascripts/bulk_ops/selections.js +24 -0
- data/app/assets/javascripts/selections.js +38 -0
- data/app/assets/javascripts/work_search.js +64 -0
- data/app/assets/stylesheets/bulk_ops.scss +99 -0
- data/app/controllers/bulk_ops/application_controller.rb +13 -0
- data/app/controllers/bulk_ops/github_authorization_controller.rb +33 -0
- data/app/controllers/bulk_ops/operations_controller.rb +481 -0
- data/app/jobs/bulk_ops/application_job.rb +4 -0
- data/app/mailers/bulk_ops/application_mailer.rb +6 -0
- data/app/models/bulk_ops/application_record.rb +5 -0
- data/app/views/bulk_ops/_bulk_ops_sidebar_widget.html.erb +15 -0
- data/app/views/bulk_ops/_github_auth_widget.html.erb +13 -0
- data/app/views/bulk_ops/operations/_bulk_ops_header.html.erb +4 -0
- data/app/views/bulk_ops/operations/_choose_fields.html.erb +22 -0
- data/app/views/bulk_ops/operations/_choose_notifications.html.erb +22 -0
- data/app/views/bulk_ops/operations/_git_message.html.erb +7 -0
- data/app/views/bulk_ops/operations/_ingest_options.html.erb +42 -0
- data/app/views/bulk_ops/operations/_operation_options.html.erb +38 -0
- data/app/views/bulk_ops/operations/_show_authorize.html.erb +13 -0
- data/app/views/bulk_ops/operations/_show_complete.html.erb +31 -0
- data/app/views/bulk_ops/operations/_show_draft.html.erb +20 -0
- data/app/views/bulk_ops/operations/_show_new.html.erb +2 -0
- data/app/views/bulk_ops/operations/_show_pending.html.erb +58 -0
- data/app/views/bulk_ops/operations/_show_running.html.erb +56 -0
- data/app/views/bulk_ops/operations/_show_verifying.html.erb +8 -0
- data/app/views/bulk_ops/operations/_show_waiting.html.erb +9 -0
- data/app/views/bulk_ops/operations/_update_draft_work_list.html.erb +45 -0
- data/app/views/bulk_ops/operations/_update_draft_work_search.html.erb +59 -0
- data/app/views/bulk_ops/operations/_update_options.html.erb +9 -0
- data/app/views/bulk_ops/operations/index.html.erb +51 -0
- data/app/views/bulk_ops/operations/new.html.erb +36 -0
- data/app/views/bulk_ops/operations/show.html.erb +7 -0
- data/config/routes.rb +25 -0
- data/db/migrate/20180926190757_create_github_credentials.rb +13 -0
- data/db/migrate/20181017180436_create_bulk_ops_tables.rb +40 -0
- data/lib/bulk_ops.rb +15 -0
- data/lib/bulk_ops/create_spreadsheet_job.rb +43 -0
- data/lib/bulk_ops/create_work_job.rb +14 -0
- data/lib/bulk_ops/delete_file_set_job.rb +15 -0
- data/lib/bulk_ops/engine.rb +6 -0
- data/lib/bulk_ops/error.rb +141 -0
- data/lib/bulk_ops/github_access.rb +284 -0
- data/lib/bulk_ops/github_credential.rb +3 -0
- data/lib/bulk_ops/operation.rb +358 -0
- data/lib/bulk_ops/relationship.rb +79 -0
- data/lib/bulk_ops/search_builder_behavior.rb +80 -0
- data/lib/bulk_ops/templates/configuration.yml +5 -0
- data/lib/bulk_ops/templates/readme.md +1 -0
- data/lib/bulk_ops/update_work_job.rb +14 -0
- data/lib/bulk_ops/verification.rb +210 -0
- data/lib/bulk_ops/verification_job.rb +23 -0
- data/lib/bulk_ops/version.rb +3 -0
- data/lib/bulk_ops/work_job.rb +104 -0
- data/lib/bulk_ops/work_proxy.rb +466 -0
- data/lib/generators/bulk_ops/install/install_generator.rb +27 -0
- data/lib/generators/bulk_ops/install/templates/config/github.yml.example +28 -0
- metadata +145 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
class BulkOps::Relationship < ActiveRecord::Base
|
2
|
+
RELATIONSHIP_FIELDS = ['parent','child','order','next','collection']
|
3
|
+
|
4
|
+
self.table_name = "bulk_ops_relationships"
|
5
|
+
belongs_to :work_proxy, class_name: "BulkOps::WorkProxy", foreign_key: "work_proxy_id"
|
6
|
+
|
7
|
+
def initialize *args
|
8
|
+
super *args
|
9
|
+
|
10
|
+
# Attempt to resolve the relationship immediately
|
11
|
+
# which might work in the case of updates
|
12
|
+
resolve!
|
13
|
+
end
|
14
|
+
|
15
|
+
def findObject
|
16
|
+
work_type = (relationship_type.downcase == "collection") ? "Collection" : work_proxy.work_type
|
17
|
+
case identifier_type
|
18
|
+
when "id"
|
19
|
+
begin
|
20
|
+
object = ActiveFedora::Base.find(object_identifier)
|
21
|
+
rescue Ldp::Gone
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
return object || false
|
25
|
+
when "title"
|
26
|
+
# TODO clean up solr query and add work type to it
|
27
|
+
query = "{!field f=title_tesim}#{object_identifier}"
|
28
|
+
objects = ActiveFedora::SolrService.instance.conn.get(ActiveFedora::SolrService.select_path,params: { fq: query, rows: 100})["response"]["docs"].first
|
29
|
+
object = objects.first
|
30
|
+
object ||= Collection.create(title: [object_identifier]) if work_type == "Collection"
|
31
|
+
return object || false
|
32
|
+
when "identifier"
|
33
|
+
query = "{!field f=identifier_tesim}#{object_identifier}"
|
34
|
+
objects = ActiveFedora::SolrService.instance.conn.get(ActiveFedora::SolrService.select_path,params: { fq: query, rows: 100})["response"]["docs"]
|
35
|
+
return false if objects.blank?
|
36
|
+
return objects.first
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def resolve! ()
|
41
|
+
unless subject = work_proxy.work and object = self.findObject
|
42
|
+
wait!
|
43
|
+
return
|
44
|
+
end
|
45
|
+
implement_relationship! relationship_type, subject, object
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def implement_relationship!(type,subject,object)
|
50
|
+
case type
|
51
|
+
when "parent"
|
52
|
+
object.ordered_members << subject
|
53
|
+
object.save
|
54
|
+
when "child"
|
55
|
+
subject.ordered_members << object
|
56
|
+
subject.save
|
57
|
+
when "collection"
|
58
|
+
object.add_members([subject.id])
|
59
|
+
object.save
|
60
|
+
when "next"
|
61
|
+
#TODO - implement this - related to ordering of filesets
|
62
|
+
when "order"
|
63
|
+
#TODO - implement this - related to ordering of filesets
|
64
|
+
|
65
|
+
end
|
66
|
+
update(status: "complete")
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def fail!
|
72
|
+
update(status: "failed")
|
73
|
+
end
|
74
|
+
|
75
|
+
def wait!
|
76
|
+
update(status: "pending")
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module BulkOps::SearchBuilderBehavior
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
included do
|
4
|
+
attr_reader :collection,
|
5
|
+
:admin_set,
|
6
|
+
:workflow_state
|
7
|
+
class_attribute :collection_field,
|
8
|
+
:collection_id_field,
|
9
|
+
:admin_set_field,
|
10
|
+
:admin_set_id_field,
|
11
|
+
:workflow_state_field,
|
12
|
+
:workflow_state_id_field,
|
13
|
+
:keyword_field
|
14
|
+
self.collection_field = 'member_of_collections_ssim'
|
15
|
+
self.collection_id_field = 'member_of_collection_ids_ssim'
|
16
|
+
self.admin_set_field = 'admin_set_tesim'
|
17
|
+
self.admin_set_id_field = 'isPartOf_ssim'
|
18
|
+
self.workflow_state_field = 'workflow_state_name_ssim'
|
19
|
+
self.keyword_field = 'all_fields'
|
20
|
+
|
21
|
+
self.default_processor_chain += [:member_of_collection,
|
22
|
+
:member_of_admin_set,
|
23
|
+
:in_workflow_state,
|
24
|
+
:with_keyword_query]
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [scope] Typically the controller object
|
28
|
+
def initialize(scope: {},
|
29
|
+
collection: nil,
|
30
|
+
collection_id: nil,
|
31
|
+
admin_set: nil,
|
32
|
+
admin_set_id: nil,
|
33
|
+
workflow_state: nil,
|
34
|
+
keyword_query: nil)
|
35
|
+
|
36
|
+
@collection = collection unless collection.blank?
|
37
|
+
@admin_set = admin_set unless admin_set.blank?
|
38
|
+
@admin_set_id = admin_set_id unless admin_set_id.blank?
|
39
|
+
@workflow_state = workflow_state unless workflow_state.blank?
|
40
|
+
@collection_id = collection_id unless collection_id.blank?
|
41
|
+
@workflow_state = workflow_state unless workflow_state.blank?
|
42
|
+
@keyword_query = keyword_query unless keyword_query.blank?
|
43
|
+
super(scope)
|
44
|
+
end
|
45
|
+
|
46
|
+
def models
|
47
|
+
[Work,Course,Lecture]
|
48
|
+
end
|
49
|
+
|
50
|
+
# include filters into the query to only include the collection memebers
|
51
|
+
def member_of_collection(solr_parameters)
|
52
|
+
solr_parameters[:fq] ||= []
|
53
|
+
solr_parameters[:fq] << "#{collection_field}:#{@collection}" if @collection
|
54
|
+
solr_parameters[:fq] << "#{collection_id_field}:#{@collection_id}" if @collection_id
|
55
|
+
end
|
56
|
+
|
57
|
+
# include filters into the query to only include the collection memebers
|
58
|
+
def member_of_admin_set(solr_parameters)
|
59
|
+
solr_parameters[:fq] ||= []
|
60
|
+
solr_parameters[:fq] << "#{admin_set_field}:#{@admin_set}" if @admin_set
|
61
|
+
solr_parameters[:fq] << "#{admin_set_id_field}:#{@admin_set_id}" if @admin_set_id
|
62
|
+
end
|
63
|
+
|
64
|
+
# include filters into the query to only include the collection memebers
|
65
|
+
def in_workflow_state(solr_parameters)
|
66
|
+
solr_parameters[:fq] ||= []
|
67
|
+
solr_parameters[:fq] << "#{workflow_state_field}:#{@workflow_state}" if @workflow_state
|
68
|
+
end
|
69
|
+
|
70
|
+
def with_keyword_query(solr_parameters)
|
71
|
+
if @keyword_query
|
72
|
+
solr_parameters[:q] ||= []
|
73
|
+
# solr_parameters[:q] << "#{keyword_field}:#{@keyword_query}" if @keyword_query
|
74
|
+
solr_parameters[:q] << @keyword_query
|
75
|
+
solr_parameters[:qf] = "title_tesim titleAlternative_tesim subseries_tesim creator_label_tesim contributor_label_tesim originalPublisher_tesim publisher_tesim publisherHomepage_tesim resourceType_label_tesim rightsHolder_label_tesim scale_tesim series_tesim source_tesim staffNote_tesim coordinates_tesim subjectName_label_tesim subjectPlace_label_tesim subjectTemporal_label_tesim subjectTopic_label_tesim dateCreated_tesim dateCreatedDisplay_tesim dateDigitized_tesim datePublished_tesim description_tesim physicalFormat_label_tesim keyword_tesim language_label_tesim license_tesim masterFilename_tesim physicalDescription_tesim accessRights_tesim itemCallNumber_tesim collectionCallNumber_tesim donorProvenance_tesim genre_label_tesim boxFolder_tesim subject_label_tesim file_format_tesim all_text_timv"
|
76
|
+
end
|
77
|
+
solr_parameters
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a readme file for the specific branch. The whole repository's readme file has different information. I'm not sure if we need both, since i haven't written either yet.
|
@@ -0,0 +1,210 @@
|
|
1
|
+
module BulkOps
|
2
|
+
module Verification
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def verify
|
6
|
+
@verification_errors ||= []
|
7
|
+
verify_column_headers
|
8
|
+
verify_remote_urls
|
9
|
+
verify_internal_references
|
10
|
+
verify_files
|
11
|
+
verify_works_to_update if operation_type.to_s == "update"
|
12
|
+
unless @verification_errors.blank?
|
13
|
+
error_file_name = BulkOps::Error.write_errors!(@verification_errors, git)
|
14
|
+
#notify everybody
|
15
|
+
notify(subject: "Errors verifying bulk #{operation_type} in Hycruz", message: "Hyrax ran a verification step to make sure that the spreadsheet for this bulk #{operation_type} is formatted correctly and won't create any errors. We found some problems. You can see a summary of the issues at this url: https://github.com/#{git.repo}/blob/#{git.name}/#{git.name}/errors/#{error_file_name}. Please fix these problems and run this verification again. The bulk #{operation_type} will not be allowed to move forward until all verification issues are resolved.")
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
|
21
|
+
def notify(subject: , message:)
|
22
|
+
options["notifications"].each do |email|
|
23
|
+
ActionMailer::Base.mail(from: "admin@digitalcollections.library.ucsc.edu",
|
24
|
+
to: email,
|
25
|
+
subject: subject,
|
26
|
+
body: message).deliver
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_file_field?(fieldname)
|
31
|
+
return false if fieldname.blank?
|
32
|
+
field_parts = fieldname.underscore.humanize.downcase.gsub(/[-_]/,' ').split(" ")
|
33
|
+
return false unless field_parts.any?{ |field_type| BulkOps::WorkProxy::FILE_FIELDS.include?(field_type) }
|
34
|
+
return "remove" if field_parts.any?{ |field_type| ['remove','delete'].include?(field_type) }
|
35
|
+
return "add"
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_field_name(fieldname)
|
39
|
+
name = fieldname.dup
|
40
|
+
name.gsub!(/[_\s-]?[aA]ttributes$/,'')
|
41
|
+
name.gsub!(/[_\s-]?[lL]abel$/,'')
|
42
|
+
name.gsub!(/^[rR]emove[_\s-]?/,'')
|
43
|
+
name.gsub!(/^[dD]elete[_\s-]?/,'')
|
44
|
+
possible_fields = Work.attribute_names + schema.all_field_names
|
45
|
+
matching_fields = possible_fields.select{|pfield| pfield.gsub(/[_\s-]/,'').parameterize == name.gsub(/[_\s-]/,'').parameterize }
|
46
|
+
return false if matching_fields.blank?
|
47
|
+
# raise Exception "Ambiguous metadata fields!" if matching_fields.uniq.count > 1
|
48
|
+
return matching_fields.first
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_file_paths(filestring)
|
52
|
+
return [] if filestring.blank?
|
53
|
+
filenames = filestring.split(BulkOps::WorkProxy::SEPARATOR)
|
54
|
+
filenames.map { |filename| File.join(BulkOps::Operation::INGEST_MEDIA_PATH, options['file_prefix'] || "", filename) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def record_exists? id
|
58
|
+
begin
|
59
|
+
return true if SolrDocument.find(id)
|
60
|
+
rescue Blacklight::Exceptions::RecordNotFound
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def verify_files
|
68
|
+
file_errors = []
|
69
|
+
get_spreadsheet.each_with_index do |row, row_num|
|
70
|
+
file_fields = row.select { |field, value| is_file_field?(field) }
|
71
|
+
file_fields.each do |column_name, filestring|
|
72
|
+
next if filestring.blank? or column_name == filestring
|
73
|
+
get_file_paths(filestring).each do |filepath|
|
74
|
+
file_errors << BulkOps::Error.new({type: :cannot_find_file, file: filepath}) unless File.file? filepath
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@verification_errors.concat file_errors
|
79
|
+
return file_errors
|
80
|
+
end
|
81
|
+
|
82
|
+
def verify_configuration
|
83
|
+
BulkOps::Operation::OPTION_REQUIREMENTS.each do |option_name, option_info|
|
84
|
+
# Make sure it's present if required
|
85
|
+
if (option_info["required"].to_s == "true") || (option_info["required"].to_s == type)
|
86
|
+
if options[option_name].blank?
|
87
|
+
@verification_errors << BulkOps::Error.new({type: :missing_required_option, option_name: option_name})
|
88
|
+
end
|
89
|
+
end
|
90
|
+
# Make sure the values are acceptable if present
|
91
|
+
unless (values = option_info.values).blank? || options[option_name].blank?
|
92
|
+
unless values.include? option[option_name]
|
93
|
+
values_string = values.reduce{|a,b| "#{a}, #{b}"}
|
94
|
+
@verification_errors << BulkOps::Error.new({type: :invalid_config_value, option_name: option_name, option_values: values_string})
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def downcase_first_letter(str)
|
101
|
+
str[0].downcase + str[1..-1]
|
102
|
+
end
|
103
|
+
|
104
|
+
# Make sure the headers in the spreadsheet are matching to properties
|
105
|
+
def verify_column_headers
|
106
|
+
|
107
|
+
unless (headers = get_spreadsheet.headers)
|
108
|
+
# log an error if we can't get the metadata headers
|
109
|
+
@verification_errors << BulkOps::Error.new({type: :bad_header, field: column_name})
|
110
|
+
end
|
111
|
+
|
112
|
+
headers.each do |column_name|
|
113
|
+
next if column_name.blank?
|
114
|
+
column_name_redux = column_name.downcase.parameterize.gsub(/[_\s-]/,"")
|
115
|
+
# Ignore everything marked as a label
|
116
|
+
next if column_name_redux.ends_with? "label"
|
117
|
+
# Ignore any column names with special meaning in hyrax
|
118
|
+
next if BulkOps::Operation::SPECIAL_COLUMNS.any?{|col| col.downcase.parameterize.gsub(/[_\s-]/,"") == column_name_redux }
|
119
|
+
# Ignore any columns speficied to be ignored in the configuration
|
120
|
+
ignored = options["ignored headers"] || []
|
121
|
+
next if ignored.any?{|col| col.downcase.parameterize.gsub(/[_\s-]/,"") == column_name_redux }
|
122
|
+
# Column names corresponding to work attributes are legit
|
123
|
+
next if Work.attribute_names.any?{|col| col.downcase.parameterize.gsub(/[_\s-]/,"") == column_name_redux }
|
124
|
+
@verification_errors << BulkOps::Error.new({type: :bad_header, field: column_name})
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def verify_remote_urls
|
129
|
+
get_spreadsheet.each do |row, row_num|
|
130
|
+
schema.controlled_field_names.each do |controlled_field_name|
|
131
|
+
next unless (url = row[controlled_field_name])
|
132
|
+
label = ::WorkIndexer.fetch_remote_label(url)
|
133
|
+
if !label || label.blank?
|
134
|
+
@verification_errors << BulkOps::Error.new({type: :cannot_retrieve_label, row: row_num + ROW_OFFSET, field: controlled_field_name, url: url})
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def get_id_from_row row
|
141
|
+
ref_id = get_ref_id(row).to_sym
|
142
|
+
return :id if ref_id == :id
|
143
|
+
normrow = row.mapgsub(//,'').parameterize
|
144
|
+
if row.key?(ref_id)
|
145
|
+
|
146
|
+
# TODO if ref_id is another column
|
147
|
+
# TODO implement solr search
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def verify_works_to_update
|
153
|
+
return [] unless operation_type == "update"
|
154
|
+
get_spreadsheet.each_with_index do |row, row_num|
|
155
|
+
id = get_ref_id(row)
|
156
|
+
#TODO: find by other field. for now just id
|
157
|
+
unless (record_exists(id))
|
158
|
+
@verification_errors << BulkOps::Error.new(type: :cannot_find_work, id: id)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def get_ref_id row
|
164
|
+
row.each do |field,value|
|
165
|
+
next if field.blank? or value.blank? or field === value
|
166
|
+
next unless BulkOps::WorkProxy::REFERENCE_IDENTIFIER_FIELDS.any?{ |ref_field| normalize_field(ref_field) == normalize_field(field) }
|
167
|
+
return value
|
168
|
+
end
|
169
|
+
# No reference identifier specified in the row. Use the default for the operation.
|
170
|
+
return reference_identifier || :id
|
171
|
+
end
|
172
|
+
|
173
|
+
def normalize_field field
|
174
|
+
return '' if field.nil?
|
175
|
+
field.downcase.parameterize.gsub(/[_\s-]/,'')
|
176
|
+
end
|
177
|
+
|
178
|
+
def verify_internal_references
|
179
|
+
# TODO
|
180
|
+
# This is sketchy. Redo it.
|
181
|
+
get_spreadsheet.each do |row,row_num|
|
182
|
+
ref_id = get_ref_id(row)
|
183
|
+
BulkOps::Operation::RELATIONSHIP_COLUMNS.each do |relationship|
|
184
|
+
next unless (obj_id = row[relationship])
|
185
|
+
if (split = obj_id.split(':')).count == 2
|
186
|
+
ref_id = split[0].downcase
|
187
|
+
obj_id = split[1]
|
188
|
+
end
|
189
|
+
|
190
|
+
if ref_id == "row" || (ref_id == "id/row" && obj_id.is_a?(Integer))
|
191
|
+
# This is a row number reference. It should be an integer in the range of possible row numbers.
|
192
|
+
unless obj_id.is_a? Integer && obj_id > 0 && obj_id <= metadata.count
|
193
|
+
@verification_errors << BulkOps::Error.new({type: :bad_object_reference, object_id: obj_id, row_number: row_num + ROW_OFFSET})
|
194
|
+
end
|
195
|
+
elsif ref_id == "id" || ref_id == "hyrax id" || (ref_id == "id/row" && (obj_id.is_a? Integer))
|
196
|
+
# This is a hydra id reference. It should correspond to an object already in the repo
|
197
|
+
unless record_exists?(obj_id)
|
198
|
+
@verification_errors << BulkOps::Error.new({type: :bad_object_reference, object_id: obj_id, row_number: row_num+ROW_OFFSET})
|
199
|
+
end
|
200
|
+
else
|
201
|
+
|
202
|
+
# This must be based on some other presumably unique field in hyrax, or a dummy field in the spreadsheet. We haven't added this functionality yet. Ignore for now.
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#require 'hydra/access_controls'
|
2
|
+
#require 'hyrax/workflow/activate_object'
|
3
|
+
|
4
|
+
class BulkOps::VerificationJob < ActiveJob::Base
|
5
|
+
|
6
|
+
attr_accessor :operation
|
7
|
+
|
8
|
+
queue_as :default
|
9
|
+
|
10
|
+
def perform(operation)
|
11
|
+
|
12
|
+
if operation.verify
|
13
|
+
operation.set_stage "authorize"
|
14
|
+
if operation.create_pull_request
|
15
|
+
operation.notify(subject: "Bulk Operation Verification Successful", message: "Your bulk ingest has passed verification, and we have requested to start applying the operation. It may required one final approval from an administrator before the operation proceeds.")
|
16
|
+
else
|
17
|
+
operation.notify(subject: "Bulk Operation - Error creating Github pull request", message: "Your bulk ingest has passed verification, but we had a problem creating a pull request on Github in order to merge this operation with the master branch. Please check your github configuration.")
|
18
|
+
end
|
19
|
+
else
|
20
|
+
operation.set_stage "pending"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#require 'hydra/access_controls'
|
2
|
+
#require 'hyrax/workflow/activate_object'
|
3
|
+
|
4
|
+
class BulkOps::WorkJob < ActiveJob::Base
|
5
|
+
attr_accessor :status, :work, :type
|
6
|
+
|
7
|
+
queue_as :ingest
|
8
|
+
|
9
|
+
after_perform do |job|
|
10
|
+
|
11
|
+
# update BulkOperationsWorkProxy status
|
12
|
+
@work ||= ActiveFedora.find(@work_proxy.work_id)
|
13
|
+
if @work.id.nil?
|
14
|
+
status = "error"
|
15
|
+
else
|
16
|
+
@work_proxy.work_id = @work.id
|
17
|
+
status = "complete"
|
18
|
+
end
|
19
|
+
update_status status
|
20
|
+
|
21
|
+
# Attempt to resolve all of the relationships defined in this row
|
22
|
+
@work_proxy.relationships.each do |relationship|
|
23
|
+
relationship.resolve!
|
24
|
+
end
|
25
|
+
|
26
|
+
# Attempt to resolve each dangling (objectless) relationships using
|
27
|
+
# this work as an object
|
28
|
+
BulkOps::Relationship.where(:status => "objectless").each do |relationship|
|
29
|
+
relationship.resolve! @work.id
|
30
|
+
end
|
31
|
+
|
32
|
+
# Delete any UploadedFiles. These take up tons of unnecessary disk space.
|
33
|
+
@work.file_sets.each do |fileset|
|
34
|
+
if uf = Hyrax::UploadedFile.find_by(file: fileset.label)
|
35
|
+
uf.destroy!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Remove any edit holds placed on an item
|
40
|
+
@work_proxy.lift_hold
|
41
|
+
|
42
|
+
# Check if the parent operation is finished
|
43
|
+
# and do any cleanup if so
|
44
|
+
@work_proxy.operation.check_if_finished
|
45
|
+
end
|
46
|
+
|
47
|
+
def perform(workClass,user_email,attributes,work_proxy_id,visibility="private")
|
48
|
+
update_status "starting", "Initializing the job"
|
49
|
+
@work_proxy = BulkOps::WorkProxy.find(work_proxy_id)
|
50
|
+
unless @work_proxy
|
51
|
+
report_error("Cannot find work proxy with id: #{work_proxy_id}")
|
52
|
+
return
|
53
|
+
end
|
54
|
+
if record_exists?(@work_proxy.work_id)
|
55
|
+
# The work exists in Solr. Presumably we're updating it.
|
56
|
+
# Report an error if we can't retrieve the work from Fedora.
|
57
|
+
begin
|
58
|
+
@work = ActiveFedora::Base.find(@work_proxy.work_id)
|
59
|
+
rescue ActiveFedora::ObjectNotFoundError
|
60
|
+
report_error "Could not find work to update in Fedora (though it shows up in Solr). Work id: #{@work_proxy.work_id}"
|
61
|
+
return
|
62
|
+
end
|
63
|
+
else # The work is not found in Solr. If we're trying to update a work, we're in trouble.
|
64
|
+
if (type == "update")
|
65
|
+
report_error "Could not find work to update with id: #{@work_proxy.work_id}"
|
66
|
+
return
|
67
|
+
end
|
68
|
+
# Create the work we are ingesting
|
69
|
+
@work = workClass.capitalize.constantize.new
|
70
|
+
end
|
71
|
+
user = User.find_by_email(user_email)
|
72
|
+
update_status "running", "Started background task at #{DateTime.now.strftime("%d/%m/%Y %H:%M")}"
|
73
|
+
ability = Ability.new(user)
|
74
|
+
env = Hyrax::Actors::Environment.new(@work, ability, attributes)
|
75
|
+
update_status "complete", Hyrax::CurationConcern.actor.send(type,env)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def record_exists? id
|
81
|
+
begin
|
82
|
+
return true if SolrDocument.find(id)
|
83
|
+
rescue Blacklight::Exceptions::RecordNotFound
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def report_error message=nil
|
89
|
+
update_status "job_error", message: message
|
90
|
+
end
|
91
|
+
|
92
|
+
def type
|
93
|
+
#override this, setting as ingest by default
|
94
|
+
:create
|
95
|
+
end
|
96
|
+
|
97
|
+
def update_status status, message=false
|
98
|
+
return false unless @work_proxy
|
99
|
+
atts = {status: status}
|
100
|
+
atts[:message] = message if message
|
101
|
+
@work_proxy.update(atts)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|