bulkrax 1.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/controllers/bulkrax/exporters_controller.rb +12 -4
- data/app/controllers/bulkrax/importers_controller.rb +22 -17
- data/app/factories/bulkrax/object_factory.rb +44 -61
- data/app/jobs/bulkrax/create_relationships_job.rb +187 -0
- data/app/jobs/bulkrax/delete_work_job.rb +6 -2
- data/app/jobs/bulkrax/export_work_job.rb +3 -1
- data/app/jobs/bulkrax/exporter_job.rb +1 -0
- data/app/jobs/bulkrax/{import_work_collection_job.rb → import_collection_job.rb} +2 -2
- data/app/jobs/bulkrax/importer_job.rb +16 -1
- data/app/matchers/bulkrax/application_matcher.rb +9 -6
- data/app/models/bulkrax/csv_collection_entry.rb +8 -6
- data/app/models/bulkrax/csv_entry.rb +139 -45
- data/app/models/bulkrax/entry.rb +19 -8
- data/app/models/bulkrax/exporter.rb +12 -5
- data/app/models/bulkrax/importer.rb +22 -5
- data/app/models/bulkrax/oai_entry.rb +5 -1
- data/app/models/bulkrax/rdf_entry.rb +16 -7
- data/app/models/bulkrax/xml_entry.rb +4 -0
- data/app/models/concerns/bulkrax/export_behavior.rb +2 -2
- data/app/models/concerns/bulkrax/file_factory.rb +2 -1
- data/app/models/concerns/bulkrax/has_matchers.rb +59 -16
- data/app/models/concerns/bulkrax/import_behavior.rb +39 -5
- data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +19 -0
- data/app/models/concerns/bulkrax/status_info.rb +4 -4
- data/app/parsers/bulkrax/application_parser.rb +59 -84
- data/app/parsers/bulkrax/bagit_parser.rb +12 -3
- data/app/parsers/bulkrax/csv_parser.rb +137 -63
- data/app/parsers/bulkrax/oai_dc_parser.rb +5 -2
- data/app/parsers/bulkrax/xml_parser.rb +5 -0
- data/app/views/bulkrax/exporters/_form.html.erb +1 -1
- data/app/views/bulkrax/exporters/show.html.erb +13 -1
- data/app/views/bulkrax/importers/_edit_form_buttons.html.erb +45 -14
- data/app/views/bulkrax/importers/edit.html.erb +2 -0
- data/app/views/bulkrax/importers/index.html.erb +15 -17
- data/app/views/bulkrax/importers/show.html.erb +6 -2
- data/config/locales/bulkrax.en.yml +1 -0
- data/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb +5 -1
- data/db/migrate/20211004170708_change_bulkrax_statuses_error_message_column_type_to_text.rb +5 -0
- data/db/migrate/20211203195233_rename_children_counters_to_relationships.rb +6 -0
- data/lib/bulkrax/engine.rb +1 -1
- data/lib/bulkrax/version.rb +1 -1
- data/lib/bulkrax.rb +9 -17
- data/lib/generators/bulkrax/templates/bin/importer +17 -11
- data/lib/generators/bulkrax/templates/config/bulkrax_api.yml +3 -1
- data/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb +7 -12
- metadata +12 -6
- data/app/jobs/bulkrax/child_relationships_job.rb +0 -128
@@ -2,31 +2,47 @@
|
|
2
2
|
|
3
3
|
require 'csv'
|
4
4
|
module Bulkrax
|
5
|
-
class CsvParser < ApplicationParser
|
5
|
+
class CsvParser < ApplicationParser # rubocop:disable Metrics/ClassLength
|
6
6
|
include ErroredEntries
|
7
7
|
def self.export_supported?
|
8
8
|
true
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
11
|
+
def records(_opts = {})
|
12
|
+
file_for_import = only_updates ? parser_fields['partial_import_file_path'] : import_file_path
|
13
|
+
# data for entry does not need source_identifier for csv, because csvs are read sequentially and mapped after raw data is read.
|
14
|
+
csv_data = entry_class.read_data(file_for_import)
|
15
|
+
importer.parser_fields['total'] = csv_data.count
|
16
|
+
importer.save
|
17
|
+
@records ||= csv_data.map { |record_data| entry_class.data_for_entry(record_data, nil) }
|
13
18
|
end
|
14
19
|
|
15
20
|
def collections
|
16
|
-
|
17
|
-
|
21
|
+
ActiveSupport::Deprecation.warn(
|
22
|
+
'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
|
23
|
+
' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
|
24
|
+
)
|
18
25
|
# retrieve a list of unique collections
|
19
|
-
records.map
|
26
|
+
records.map do |r|
|
27
|
+
collections = []
|
28
|
+
r[collection_field_mapping].split(/\s*[;|]\s*/).each { |title| collections << { title: title, from_collection_field_mapping: true } } if r[collection_field_mapping].present?
|
29
|
+
model_field_mappings.each do |model_mapping|
|
30
|
+
collections << r if r[model_mapping.to_sym]&.downcase == 'collection'
|
31
|
+
end
|
32
|
+
collections
|
33
|
+
end.flatten.compact.uniq
|
20
34
|
end
|
21
35
|
|
22
36
|
def collections_total
|
23
37
|
collections.size
|
24
38
|
end
|
25
39
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
40
|
+
def works
|
41
|
+
records - collections
|
42
|
+
end
|
43
|
+
|
44
|
+
def works_total
|
45
|
+
works.size
|
30
46
|
end
|
31
47
|
|
32
48
|
# We could use CsvEntry#fields_from_data(data) but that would mean re-reading the data
|
@@ -44,8 +60,9 @@ module Bulkrax
|
|
44
60
|
end
|
45
61
|
|
46
62
|
def valid_import?
|
47
|
-
|
48
|
-
|
63
|
+
import_strings = keys_without_numbers(import_fields.map(&:to_s))
|
64
|
+
error_alert = "Missing at least one required element, missing element(s) are: #{missing_elements(import_strings).join(', ')}"
|
65
|
+
raise StandardError, error_alert unless required_elements?(import_strings)
|
49
66
|
|
50
67
|
file_paths.is_a?(Array)
|
51
68
|
rescue StandardError => e
|
@@ -56,26 +73,46 @@ module Bulkrax
|
|
56
73
|
def create_collections
|
57
74
|
collections.each_with_index do |collection, index|
|
58
75
|
next if collection.blank?
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
76
|
+
break if records.find_index(collection).present? && limit_reached?(limit, records.find_index(collection))
|
77
|
+
ActiveSupport::Deprecation.warn(
|
78
|
+
'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
|
79
|
+
' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
|
80
|
+
)
|
81
|
+
|
82
|
+
## BEGIN
|
83
|
+
# Add required metadata to collections being imported using the collection_field_mapping, which only have a :title
|
84
|
+
# TODO: Remove once collection_field_mapping is removed
|
85
|
+
metadata = if collection.delete(:from_collection_field_mapping)
|
86
|
+
uci = unique_collection_identifier(collection)
|
87
|
+
{
|
88
|
+
title: [collection[:title]],
|
89
|
+
work_identifier => uci,
|
90
|
+
source_identifier => uci,
|
91
|
+
visibility: 'open',
|
92
|
+
collection_type_gid: ::Hyrax::CollectionType.find_or_create_default_collection_type.gid
|
93
|
+
}
|
94
|
+
end
|
95
|
+
collection_hash = metadata.presence || collection
|
96
|
+
## END
|
97
|
+
|
98
|
+
new_entry = find_or_create_entry(collection_entry_class, collection_hash[source_identifier], 'Bulkrax::Importer', collection_hash)
|
99
|
+
# TODO: add support for :delete option
|
100
|
+
ImportCollectionJob.perform_now(new_entry.id, current_run.id)
|
67
101
|
increment_counters(index, true)
|
68
102
|
end
|
103
|
+
importer.record_status
|
104
|
+
rescue StandardError => e
|
105
|
+
status_info(e)
|
69
106
|
end
|
70
107
|
|
71
108
|
def create_works
|
72
|
-
|
73
|
-
next unless record_has_source_identifier(
|
74
|
-
break if limit_reached?(limit,
|
109
|
+
works.each_with_index do |work, index|
|
110
|
+
next unless record_has_source_identifier(work, records.find_index(work))
|
111
|
+
break if limit_reached?(limit, records.find_index(work))
|
75
112
|
|
76
|
-
seen[
|
77
|
-
new_entry = find_or_create_entry(entry_class,
|
78
|
-
if
|
113
|
+
seen[work[source_identifier]] = true
|
114
|
+
new_entry = find_or_create_entry(entry_class, work[source_identifier], 'Bulkrax::Importer', work.to_h)
|
115
|
+
if work[:delete].present?
|
79
116
|
DeleteWorkJob.send(perform_method, new_entry, current_run)
|
80
117
|
else
|
81
118
|
ImportWorkJob.send(perform_method, new_entry.id, current_run.id)
|
@@ -99,10 +136,6 @@ module Bulkrax
|
|
99
136
|
path
|
100
137
|
end
|
101
138
|
|
102
|
-
def create_parent_child_relationships
|
103
|
-
super
|
104
|
-
end
|
105
|
-
|
106
139
|
def extra_filters
|
107
140
|
output = ""
|
108
141
|
if importerexporter.start_date.present?
|
@@ -117,6 +150,8 @@ module Bulkrax
|
|
117
150
|
|
118
151
|
def current_work_ids
|
119
152
|
case importerexporter.export_from
|
153
|
+
when 'all'
|
154
|
+
ActiveFedora::SolrService.query("has_model_ssim:(#{Hyrax.config.curation_concerns.join(' OR ')}) #{extra_filters}", rows: 2_147_483_647).map(&:id)
|
120
155
|
when 'collection'
|
121
156
|
ActiveFedora::SolrService.query("member_of_collection_ids_ssim:#{importerexporter.export_source + extra_filters}", rows: 2_000_000_000).map(&:id)
|
122
157
|
when 'worktype'
|
@@ -126,9 +161,16 @@ module Bulkrax
|
|
126
161
|
complete_statuses = Bulkrax::Status.latest_by_statusable
|
127
162
|
.includes(:statusable)
|
128
163
|
.where('bulkrax_statuses.statusable_id IN (?) AND bulkrax_statuses.statusable_type = ? AND status_message = ?', entry_ids, 'Bulkrax::Entry', 'Complete')
|
129
|
-
complete_entry_identifiers = complete_statuses.map { |s| s.statusable&.identifier }
|
130
164
|
|
131
|
-
|
165
|
+
complete_entry_identifiers = complete_statuses.map { |s| s.statusable&.identifier&.gsub(':', '\:') }
|
166
|
+
extra_filters = extra_filters.presence || '*:*'
|
167
|
+
|
168
|
+
ActiveFedora::SolrService.get(
|
169
|
+
extra_filters.to_s,
|
170
|
+
fq: "#{work_identifier}_sim:(#{complete_entry_identifiers.join(' OR ')})",
|
171
|
+
fl: 'id',
|
172
|
+
rows: 2_000_000_000
|
173
|
+
)['response']['docs'].map { |obj| obj['id'] }
|
132
174
|
end
|
133
175
|
end
|
134
176
|
|
@@ -136,12 +178,18 @@ module Bulkrax
|
|
136
178
|
current_work_ids.each_with_index do |wid, index|
|
137
179
|
break if limit_reached?(limit, index)
|
138
180
|
new_entry = find_or_create_entry(entry_class, wid, 'Bulkrax::Exporter')
|
139
|
-
|
181
|
+
begin
|
182
|
+
entry = Bulkrax::ExportWorkJob.perform_now(new_entry.id, current_run.id)
|
183
|
+
rescue => e
|
184
|
+
Rails.logger.info("#{e.message} was detected during export")
|
185
|
+
end
|
186
|
+
self.headers |= entry.parsed_metadata.keys if entry
|
140
187
|
end
|
141
188
|
end
|
142
189
|
alias create_from_collection create_new_entries
|
143
190
|
alias create_from_importer create_new_entries
|
144
191
|
alias create_from_worktype create_new_entries
|
192
|
+
alias create_from_all create_new_entries
|
145
193
|
|
146
194
|
def entry_class
|
147
195
|
CsvEntry
|
@@ -154,19 +202,11 @@ module Bulkrax
|
|
154
202
|
# See https://stackoverflow.com/questions/2650517/count-the-number-of-lines-in-a-file-without-reading-entire-file-into-memory
|
155
203
|
# Changed to grep as wc -l counts blank lines, and ignores the final unescaped line (which may or may not contain data)
|
156
204
|
def total
|
157
|
-
if importer?
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
@total = `grep -vc ^$ #{real_import_file_path}`.to_i - 1 if @total < 1
|
163
|
-
elsif exporter?
|
164
|
-
@total = importerexporter.entries.count
|
165
|
-
else
|
166
|
-
@total = 0
|
167
|
-
end
|
168
|
-
return @total
|
169
|
-
rescue StandardErrorr
|
205
|
+
@total = importer.parser_fields['total'] || 0 if importer?
|
206
|
+
@total = importerexporter.entries.count if exporter?
|
207
|
+
|
208
|
+
return @total || 0
|
209
|
+
rescue StandardError
|
170
210
|
@total = 0
|
171
211
|
end
|
172
212
|
|
@@ -201,32 +241,58 @@ module Bulkrax
|
|
201
241
|
end
|
202
242
|
end
|
203
243
|
|
204
|
-
def
|
205
|
-
|
206
|
-
new_entry(entry_class, 'Bulkrax::Exporter').field_supported?(key) &&
|
244
|
+
def export_key_allowed(key)
|
245
|
+
new_entry(entry_class, 'Bulkrax::Exporter').field_supported?(key) &&
|
207
246
|
key != source_identifier.to_s
|
208
247
|
end
|
209
248
|
|
210
249
|
# All possible column names
|
211
250
|
def export_headers
|
212
|
-
headers =
|
213
|
-
|
214
|
-
|
215
|
-
headers
|
216
|
-
|
217
|
-
headers
|
251
|
+
headers = sort_headers(self.headers)
|
252
|
+
|
253
|
+
# we don't want access_control_id exported and we want file at the end
|
254
|
+
headers.delete('access_control_id') if headers.include?('access_control_id')
|
255
|
+
|
256
|
+
# add the headers below at the beginning or end to maintain the preexisting export behavior
|
257
|
+
headers.prepend('model')
|
258
|
+
headers.prepend(source_identifier.to_s)
|
259
|
+
headers.prepend('id')
|
260
|
+
|
218
261
|
headers.uniq
|
219
262
|
end
|
220
263
|
|
264
|
+
def object_names
|
265
|
+
return @object_names if @object_names
|
266
|
+
|
267
|
+
@object_names = mapping.values.map { |value| value['object'] }
|
268
|
+
@object_names.uniq!.delete(nil)
|
269
|
+
|
270
|
+
@object_names
|
271
|
+
end
|
272
|
+
|
273
|
+
def sort_headers(headers)
|
274
|
+
# converting headers like creator_name_1 to creator_1_name so they get sorted by numerical order
|
275
|
+
# while keeping objects grouped together
|
276
|
+
headers.sort_by do |item|
|
277
|
+
number = item.match(/\d+/)&.[](0) || 0.to_s
|
278
|
+
sort_number = number.rjust(4, "0")
|
279
|
+
object_prefix = object_names.detect { |o| item.match(/^#{o}/) } || item
|
280
|
+
remainder = item.gsub(/^#{object_prefix}_/, '').gsub(/_#{number}/, '')
|
281
|
+
"#{object_prefix}_#{sort_number}_#{remainder}"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
221
285
|
# in the parser as it is specific to the format
|
222
286
|
def setup_export_file
|
223
|
-
File.join(importerexporter.exporter_export_path,
|
287
|
+
File.join(importerexporter.exporter_export_path, "export_#{importerexporter.export_source}_from_#{importerexporter.export_from}.csv")
|
224
288
|
end
|
225
289
|
|
226
290
|
# Retrieve file paths for [:file] mapping in records
|
227
291
|
# and check all listed files exist.
|
228
292
|
def file_paths
|
229
293
|
raise StandardError, 'No records were found' if records.blank?
|
294
|
+
return [] if importerexporter.metadata_only?
|
295
|
+
|
230
296
|
@file_paths ||= records.map do |r|
|
231
297
|
file_mapping = Bulkrax.field_mappings.dig(self.class.to_s, 'file', :from)&.first&.to_sym || :file
|
232
298
|
next if r[file_mapping].blank?
|
@@ -245,23 +311,31 @@ module Bulkrax
|
|
245
311
|
# Retrieve the path where we expect to find the files
|
246
312
|
def path_to_files
|
247
313
|
@path_to_files ||= File.join(
|
248
|
-
|
314
|
+
zip? ? importer_unzip_path : File.dirname(import_file_path),
|
249
315
|
'files'
|
250
316
|
)
|
251
317
|
end
|
252
318
|
|
253
319
|
private
|
254
320
|
|
321
|
+
def unique_collection_identifier(collection_hash)
|
322
|
+
entry_uid = collection_hash[source_identifier]
|
323
|
+
entry_uid ||= if Bulkrax.fill_in_blank_source_identifiers.present?
|
324
|
+
Bulkrax.fill_in_blank_source_identifiers.call(self, records.find_index(collection_hash))
|
325
|
+
else
|
326
|
+
collection_hash[:title].split(/\s*[;|]\s*/).first
|
327
|
+
end
|
328
|
+
|
329
|
+
entry_uid
|
330
|
+
end
|
331
|
+
|
255
332
|
# Override to return the first CSV in the path, if a zip file is supplied
|
256
333
|
# We expect a single CSV at the top level of the zip in the CSVParser
|
257
334
|
# but we are willing to go look for it if need be
|
258
335
|
def real_import_file_path
|
259
|
-
if file? && zip?
|
260
|
-
|
261
|
-
|
262
|
-
else
|
263
|
-
parser_fields['import_file_path']
|
264
|
-
end
|
336
|
+
return Dir["#{importer_unzip_path}/**/*.csv"].first if file? && zip?
|
337
|
+
|
338
|
+
parser_fields['import_file_path']
|
265
339
|
end
|
266
340
|
end
|
267
341
|
end
|
@@ -75,7 +75,7 @@ module Bulkrax
|
|
75
75
|
|
76
76
|
new_entry = collection_entry_class.where(importerexporter: importerexporter, identifier: unique_collection_identifier, raw_metadata: metadata).first_or_create!
|
77
77
|
# perform now to ensure this gets created before work imports start
|
78
|
-
|
78
|
+
ImportCollectionJob.perform_now(new_entry.id, importerexporter.current_run.id)
|
79
79
|
increment_counters(index, true)
|
80
80
|
end
|
81
81
|
end
|
@@ -119,7 +119,10 @@ module Bulkrax
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
|
122
|
+
# TODO: change to differentiate between collection and work records when adding ability to import collection metadata
|
123
|
+
def works_total
|
124
|
+
total
|
125
|
+
end
|
123
126
|
|
124
127
|
def total
|
125
128
|
@total ||= records(quick: true).doc.find(".//resumptionToken").to_a.first.attributes["completeListSize"].to_i
|
@@ -12,6 +12,11 @@ module Bulkrax
|
|
12
12
|
# @todo not yet supported
|
13
13
|
def create_collections; end
|
14
14
|
|
15
|
+
# TODO: change to differentiate between collection and work records when adding ability to import collection metadata
|
16
|
+
def works_total
|
17
|
+
total
|
18
|
+
end
|
19
|
+
|
15
20
|
# @todo not yet supported
|
16
21
|
def import_fields; end
|
17
22
|
|
@@ -32,7 +32,7 @@
|
|
32
32
|
prompt: 'Select from the list',
|
33
33
|
label_html: { class: 'importer export-source-option hidden' },
|
34
34
|
input_html: { class: 'importer export-source-option hidden' },
|
35
|
-
collection: form.object.importers_list %>
|
35
|
+
collection: form.object.importers_list.sort %>
|
36
36
|
|
37
37
|
<%= form.input :export_source_collection,
|
38
38
|
prompt: 'Start typing ...',
|
@@ -7,6 +7,13 @@
|
|
7
7
|
<div class='panel panel-default'>
|
8
8
|
<div class='panel-body'>
|
9
9
|
|
10
|
+
<% if File.exist?(@exporter.exporter_export_zip_path) %>
|
11
|
+
<p class='bulkrax-p-align'>
|
12
|
+
<strong>Download:</strong>
|
13
|
+
<%= link_to raw('<span class="glyphicon glyphicon-download"></span>'), exporter_download_path(@exporter) %>
|
14
|
+
</p>
|
15
|
+
<% end %>
|
16
|
+
|
10
17
|
<p class='bulkrax-p-align'>
|
11
18
|
<strong><%= t('bulkrax.exporter.labels.name') %>:</strong>
|
12
19
|
<%= @exporter.name %>
|
@@ -50,8 +57,9 @@
|
|
50
57
|
<strong><%= t('bulkrax.exporter.labels.limit') %>:</strong>
|
51
58
|
<%= @exporter.limit %>
|
52
59
|
</p>
|
60
|
+
<%= render partial: 'bulkrax/shared/bulkrax_errors', locals: {item: @exporter} %>
|
53
61
|
|
54
|
-
|
62
|
+
<%= render partial: 'bulkrax/shared/bulkrax_field_mapping', locals: {item: @exporter} %>
|
55
63
|
|
56
64
|
<%# Currently, no parser-specific fields exist on Exporter,
|
57
65
|
thus there's no real reason to always show this field %>
|
@@ -116,6 +124,10 @@
|
|
116
124
|
<%= page_entries_info(@work_entries) %><br>
|
117
125
|
<%= paginate(@work_entries, param_name: :work_entries_page) %>
|
118
126
|
<br>
|
127
|
+
<% if File.exist?(@exporter.exporter_export_zip_path) %>
|
128
|
+
<%= link_to 'Download', exporter_download_path(@exporter) %>
|
129
|
+
|
|
130
|
+
<% end %>
|
119
131
|
<%= link_to 'Edit', edit_exporter_path(@exporter) %>
|
120
132
|
|
|
121
133
|
<%= link_to 'Back', exporters_path %>
|
@@ -1,16 +1,47 @@
|
|
1
|
+
<div class="modal fade" id="bulkraxModal" tabindex="-1" role="dialog" aria-labelledby="bulkraxModalLabel">
|
2
|
+
<div class="modal-dialog" role="document">
|
3
|
+
<div class="modal-content">
|
4
|
+
<div class="modal-body">
|
5
|
+
<h5>Options for Updating the Importer</h5>
|
6
|
+
<hr />
|
1
7
|
|
2
|
-
|
8
|
+
<% if @importer.importer_runs.blank? %>
|
9
|
+
<p>Only update the values in the importer form. Do not import metadata or files for any works or collections.</p>
|
10
|
+
<%= form.button :submit, value: 'Update Importer', class: 'btn btn-primary' %>
|
11
|
+
<hr />
|
12
|
+
<p>Update the values in the importer form and run the importer for the first time.</p>
|
13
|
+
<%= form.button :submit, value: 'Update and Import', class: 'btn btn-primary' %>
|
14
|
+
<% elsif @importer.parser_klass.include?('Oai') %>
|
15
|
+
<p>Only update the values in the importer form. Do not update metadata or files for any works or collections.</p>
|
16
|
+
<%= form.button :submit, value: 'Update Importer', class: 'btn btn-primary' %>
|
17
|
+
<hr />
|
18
|
+
<p>Update the values in the importer form and update items that have changed at the source.</p>
|
19
|
+
<%= form.button :submit, value: 'Update and Harvest Updated Items', class: 'btn btn-primary' %>
|
20
|
+
<hr />
|
21
|
+
<p>Update the values in the importer form and recreate all items from the source.</p>
|
22
|
+
<%= form.button :submit, value: 'Update and Re-Harvest All Items', class: 'btn btn-primary' %>
|
23
|
+
<% else %>
|
24
|
+
<p>Only update the values in the importer form. Do not update metadata or files for any works or collections.</p>
|
25
|
+
<%= form.button :submit, value: 'Update Importer', class: 'btn btn-primary' %>
|
26
|
+
<hr />
|
27
|
+
<p>Update the values in the importer form and update the metadata for all works. Do not update any files.</p>
|
28
|
+
<%= form.button :submit, value: 'Update Metadata', class: 'btn btn-primary' %>
|
29
|
+
<hr />
|
30
|
+
<p>Update the values in the importer form and update the metadata and files for all works. Creates new versions of the files and retains the old versions.</p>
|
31
|
+
<%= form.button :submit, value: 'Update Metadata and Files', class: 'btn btn-primary' %>
|
32
|
+
<hr />
|
33
|
+
<p>Update the values in the importer form and update the metadata. Completely removes all files attached to works for this importer and recreates the files from scratch.</p>
|
34
|
+
<%= form.button :submit,
|
35
|
+
value: 'Update and Replace Files',
|
36
|
+
class: 'btn btn-primary',
|
37
|
+
data: {confirm: "Are you sure? This will remove all files before adding them from the import."} %>
|
38
|
+
<% end %>
|
39
|
+
<hr />
|
3
40
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
<% else %>
|
12
|
-
<%= form.button :submit, value: 'Update Importer', class: 'btn btn-primary' %>
|
13
|
-
| <%= form.button :submit, value: 'Update and Re-Import (update metadata only)', class: 'btn btn-primary' %>
|
14
|
-
| <%= form.button :submit, value: 'Update All (update metadata and update files)', class: 'btn btn-primary' %>
|
15
|
-
| <%= form.button :submit, value: 'Update and Re-Import (update metadata and replace files)', class: 'btn btn-primary', data: {confirm: "Are you sure? This will remove all files before adding them from the import."} %>
|
16
|
-
<% end %>
|
41
|
+
</div>
|
42
|
+
<div class="modal-footer">
|
43
|
+
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t('helpers.action.cancel') %></button>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
</div>
|
@@ -5,10 +5,12 @@
|
|
5
5
|
<div class="row">
|
6
6
|
<div class="col-md-12">
|
7
7
|
<div class="panel panel-default tabs">
|
8
|
+
|
8
9
|
<%= simple_form_for @importer, html: { multipart: true } do |form| %>
|
9
10
|
<%= render 'form', importer: @importer, form: form %>
|
10
11
|
<div class="panel-footer">
|
11
12
|
<div class='pull-right'>
|
13
|
+
<%= link_to 'Update Importer', '#bulkraxModal', class: "btn btn-primary", data: { toggle: 'modal' } %>
|
12
14
|
<%= render 'edit_form_buttons', form: form %>
|
13
15
|
<% cancel_path = form.object.persisted? ? importer_path(form.object) : importers_path %>
|
14
16
|
| <%= link_to t('.cancel'), cancel_path, class: 'btn btn-default ' %>
|
@@ -31,23 +31,21 @@
|
|
31
31
|
</thead>
|
32
32
|
<tbody>
|
33
33
|
<% @importers.each do |importer| %>
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
<td><%= link_to raw('<span class="glyphicon glyphicon-remove"></span>'), importer, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
50
|
-
</tr>
|
34
|
+
<tr>
|
35
|
+
<th scope="row"><%= link_to importer.name, importer_path(importer) %></th>
|
36
|
+
<td><%= importer.status %></td>
|
37
|
+
<td><%= importer.last_imported_at.strftime("%b %d, %Y") if importer.last_imported_at %></td>
|
38
|
+
<td><%= importer.next_import_at.strftime("%b %d, %Y") if importer.next_import_at %></td>
|
39
|
+
<td><%= importer.importer_runs.last&.enqueued_records %></td>
|
40
|
+
<td><%= (importer.importer_runs.last&.processed_collections || 0) + (importer.importer_runs.last&.processed_records || 0) %></td>
|
41
|
+
<td><%= (importer.importer_runs.last&.failed_collections || 0) + (importer.importer_runs.last&.failed_records || 0) %></td>
|
42
|
+
<td><%= importer.importer_runs.last&.deleted_records %></td>
|
43
|
+
<td><%= importer.importer_runs.last&.total_collection_entries %></td>
|
44
|
+
<td><%= importer.importer_runs.last&.total_work_entries %></td>
|
45
|
+
<td><%= link_to raw('<span class="glyphicon glyphicon-info-sign"></span>'), importer_path(importer) %></td>
|
46
|
+
<td><%= link_to raw('<span class="glyphicon glyphicon-pencil"></span>'), edit_importer_path(importer) %></td>
|
47
|
+
<td><%= link_to raw('<span class="glyphicon glyphicon-remove"></span>'), importer, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
48
|
+
</tr>
|
51
49
|
<% end %>
|
52
50
|
</tbody>
|
53
51
|
</table>
|
@@ -101,8 +101,10 @@
|
|
101
101
|
<td><%= e.id %></td>
|
102
102
|
<% if e.status == "Complete" %>
|
103
103
|
<td><span class="glyphicon glyphicon-ok" style="color: green;"></span> <%= e.status %></td>
|
104
|
+
<% elsif e.status == "Pending" %>
|
105
|
+
<td><span class="glyphicon glyphicon-option-horizontal" style="color: blue;"></span> <%= e.status %></td>
|
104
106
|
<% else %>
|
105
|
-
<td><span class="glyphicon glyphicon-remove" style="color: red
|
107
|
+
<td><span class="glyphicon glyphicon-remove" style="color: <%= e.status == 'Deleted' ? 'green' : 'red' %>;"></span> <%= e.status %></td>
|
106
108
|
<% end %>
|
107
109
|
<% if e.last_error.present? %>
|
108
110
|
<td><%= link_to e.last_error.dig("error_class"), bulkrax.importer_entry_path(@importer.id, e.id) %></td>
|
@@ -137,8 +139,10 @@
|
|
137
139
|
<td><%= e.id %></td>
|
138
140
|
<% if e.status == "Complete" %>
|
139
141
|
<td><span class="glyphicon glyphicon-ok" style="color: green;"></span> <%= e.status %></td>
|
142
|
+
<% elsif e.status == "Pending" %>
|
143
|
+
<td><span class="glyphicon glyphicon-option-horizontal" style="color: blue;"></span> <%= e.status %></td>
|
140
144
|
<% else %>
|
141
|
-
<td><span class="glyphicon glyphicon-remove" style="color: red
|
145
|
+
<td><span class="glyphicon glyphicon-remove" style="color: <%= e.status == 'Deleted' ? 'green' : 'red' %>;"></span> <%= e.status %></td>
|
142
146
|
<% end %>
|
143
147
|
<% if e.last_error.present? %>
|
144
148
|
<td><%= link_to e.last_error.dig("error_class"), bulkrax.importer_entry_path(@importer.id, e.id) %></td>
|
@@ -6,7 +6,11 @@ end
|
|
6
6
|
|
7
7
|
class ChangeImporterAndExporterToPolymorphic < ActiveRecord::Migration[5.1]
|
8
8
|
def change
|
9
|
-
|
9
|
+
if column_exists?(:bulkrax_entries, :importer_id)
|
10
|
+
remove_foreign_key :bulkrax_entries, column: :importer_id
|
11
|
+
remove_index :bulkrax_entries, :importer_id
|
12
|
+
rename_column :bulkrax_entries, :importer_id, :importerexporter_id
|
13
|
+
end
|
10
14
|
add_column :bulkrax_entries, :importerexporter_type, :string, after: :id, default: 'Bulkrax::Importer' unless column_exists?(:bulkrax_entries, :importerexporter_type)
|
11
15
|
end
|
12
16
|
end
|
data/lib/bulkrax/engine.rb
CHANGED
@@ -25,7 +25,7 @@ module Bulkrax
|
|
25
25
|
config.after_initialize do
|
26
26
|
my_engine_root = Bulkrax::Engine.root.to_s
|
27
27
|
paths = ActionController::Base.view_paths.collect(&:to_s)
|
28
|
-
hyrax_path = paths.detect { |path| path.match(
|
28
|
+
hyrax_path = paths.detect { |path| path.match(/\/hyrax-[\d\.]+.*/) }
|
29
29
|
paths = if hyrax_path
|
30
30
|
paths.insert(paths.index(hyrax_path), my_engine_root + '/app/views')
|
31
31
|
else
|
data/lib/bulkrax/version.rb
CHANGED