bulkrax 1.0.2 → 2.1.0
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 +23 -17
- data/app/factories/bulkrax/object_factory.rb +84 -63
- data/app/jobs/bulkrax/create_relationships_job.rb +156 -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} +4 -2
- data/app/jobs/bulkrax/import_file_set_job.rb +69 -0
- data/app/jobs/bulkrax/import_work_job.rb +2 -0
- data/app/jobs/bulkrax/importer_job.rb +18 -1
- data/app/matchers/bulkrax/application_matcher.rb +5 -5
- data/app/models/bulkrax/csv_collection_entry.rb +8 -6
- data/app/models/bulkrax/csv_entry.rb +132 -65
- data/app/models/bulkrax/csv_file_set_entry.rb +26 -0
- data/app/models/bulkrax/entry.rb +19 -8
- data/app/models/bulkrax/exporter.rb +12 -5
- data/app/models/bulkrax/importer.rb +24 -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/dynamic_record_lookup.rb +39 -0
- data/app/models/concerns/bulkrax/export_behavior.rb +2 -2
- data/app/models/concerns/bulkrax/has_matchers.rb +44 -13
- data/app/models/concerns/bulkrax/import_behavior.rb +40 -5
- data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +23 -2
- data/app/models/concerns/bulkrax/status_info.rb +4 -4
- data/app/parsers/bulkrax/application_parser.rb +67 -84
- data/app/parsers/bulkrax/bagit_parser.rb +13 -4
- data/app/parsers/bulkrax/csv_parser.rb +170 -64
- data/app/parsers/bulkrax/oai_dc_parser.rb +6 -3
- 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 +2 -1
- data/app/views/bulkrax/importers/index.html.erb +17 -17
- data/app/views/bulkrax/importers/show.html.erb +52 -6
- 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/db/migrate/20211220195027_add_file_set_counters_to_importer_runs.rb +7 -0
- data/db/migrate/20220118001339_add_import_attempts_to_entries.rb +5 -0
- data/db/migrate/20220119213325_add_work_counters_to_importer_runs.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 +22 -10
- data/app/jobs/bulkrax/child_relationships_job.rb +0 -128
@@ -2,31 +2,61 @@
|
|
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 - file_sets
|
42
|
+
end
|
43
|
+
|
44
|
+
def works_total
|
45
|
+
works.size
|
46
|
+
end
|
47
|
+
|
48
|
+
def file_sets
|
49
|
+
records.map do |r|
|
50
|
+
file_sets = []
|
51
|
+
model_field_mappings.each do |model_mapping|
|
52
|
+
file_sets << r if r[model_mapping.to_sym]&.downcase == 'fileset'
|
53
|
+
end
|
54
|
+
file_sets
|
55
|
+
end.flatten.compact.uniq
|
56
|
+
end
|
57
|
+
|
58
|
+
def file_sets_total
|
59
|
+
file_sets.size
|
30
60
|
end
|
31
61
|
|
32
62
|
# We could use CsvEntry#fields_from_data(data) but that would mean re-reading the data
|
@@ -44,8 +74,9 @@ module Bulkrax
|
|
44
74
|
end
|
45
75
|
|
46
76
|
def valid_import?
|
47
|
-
|
48
|
-
|
77
|
+
import_strings = keys_without_numbers(import_fields.map(&:to_s))
|
78
|
+
error_alert = "Missing at least one required element, missing element(s) are: #{missing_elements(import_strings).join(', ')}"
|
79
|
+
raise StandardError, error_alert unless required_elements?(import_strings)
|
49
80
|
|
50
81
|
file_paths.is_a?(Array)
|
51
82
|
rescue StandardError => e
|
@@ -56,26 +87,46 @@ module Bulkrax
|
|
56
87
|
def create_collections
|
57
88
|
collections.each_with_index do |collection, index|
|
58
89
|
next if collection.blank?
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
90
|
+
break if records.find_index(collection).present? && limit_reached?(limit, records.find_index(collection))
|
91
|
+
ActiveSupport::Deprecation.warn(
|
92
|
+
'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
|
93
|
+
' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
|
94
|
+
)
|
95
|
+
|
96
|
+
## BEGIN
|
97
|
+
# Add required metadata to collections being imported using the collection_field_mapping, which only have a :title
|
98
|
+
# TODO: Remove once collection_field_mapping is removed
|
99
|
+
metadata = if collection.delete(:from_collection_field_mapping)
|
100
|
+
uci = unique_collection_identifier(collection)
|
101
|
+
{
|
102
|
+
title: [collection[:title]],
|
103
|
+
work_identifier => uci,
|
104
|
+
source_identifier => uci,
|
105
|
+
visibility: 'open',
|
106
|
+
collection_type_gid: ::Hyrax::CollectionType.find_or_create_default_collection_type.gid
|
107
|
+
}
|
108
|
+
end
|
109
|
+
collection_hash = metadata.presence || collection
|
110
|
+
## END
|
111
|
+
|
112
|
+
new_entry = find_or_create_entry(collection_entry_class, collection_hash[source_identifier], 'Bulkrax::Importer', collection_hash)
|
113
|
+
# TODO: add support for :delete option
|
114
|
+
ImportCollectionJob.perform_now(new_entry.id, current_run.id)
|
115
|
+
increment_counters(index, collection: true)
|
68
116
|
end
|
117
|
+
importer.record_status
|
118
|
+
rescue StandardError => e
|
119
|
+
status_info(e)
|
69
120
|
end
|
70
121
|
|
71
122
|
def create_works
|
72
|
-
|
73
|
-
next unless record_has_source_identifier(
|
74
|
-
break if limit_reached?(limit,
|
123
|
+
works.each_with_index do |work, index|
|
124
|
+
next unless record_has_source_identifier(work, records.find_index(work))
|
125
|
+
break if limit_reached?(limit, records.find_index(work))
|
75
126
|
|
76
|
-
seen[
|
77
|
-
new_entry = find_or_create_entry(entry_class,
|
78
|
-
if
|
127
|
+
seen[work[source_identifier]] = true
|
128
|
+
new_entry = find_or_create_entry(entry_class, work[source_identifier], 'Bulkrax::Importer', work.to_h)
|
129
|
+
if work[:delete].present?
|
79
130
|
DeleteWorkJob.send(perform_method, new_entry, current_run)
|
80
131
|
else
|
81
132
|
ImportWorkJob.send(perform_method, new_entry.id, current_run.id)
|
@@ -87,6 +138,20 @@ module Bulkrax
|
|
87
138
|
status_info(e)
|
88
139
|
end
|
89
140
|
|
141
|
+
def create_file_sets
|
142
|
+
file_sets.each_with_index do |file_set, index|
|
143
|
+
next unless record_has_source_identifier(file_set, records.find_index(file_set))
|
144
|
+
break if limit_reached?(limit, records.find_index(file_set))
|
145
|
+
|
146
|
+
new_entry = find_or_create_entry(file_set_entry_class, file_set[source_identifier], 'Bulkrax::Importer', file_set.to_h)
|
147
|
+
ImportFileSetJob.perform_later(new_entry.id, current_run.id)
|
148
|
+
increment_counters(index, file_set: true)
|
149
|
+
end
|
150
|
+
importer.record_status
|
151
|
+
rescue StandardError => e
|
152
|
+
status_info(e)
|
153
|
+
end
|
154
|
+
|
90
155
|
def write_partial_import_file(file)
|
91
156
|
import_filename = import_file_path.split('/').last
|
92
157
|
partial_import_filename = "#{File.basename(import_filename, '.csv')}_corrected_entries.csv"
|
@@ -99,10 +164,6 @@ module Bulkrax
|
|
99
164
|
path
|
100
165
|
end
|
101
166
|
|
102
|
-
def create_parent_child_relationships
|
103
|
-
super
|
104
|
-
end
|
105
|
-
|
106
167
|
def extra_filters
|
107
168
|
output = ""
|
108
169
|
if importerexporter.start_date.present?
|
@@ -117,6 +178,8 @@ module Bulkrax
|
|
117
178
|
|
118
179
|
def current_work_ids
|
119
180
|
case importerexporter.export_from
|
181
|
+
when 'all'
|
182
|
+
ActiveFedora::SolrService.query("has_model_ssim:(#{Hyrax.config.curation_concerns.join(' OR ')}) #{extra_filters}", rows: 2_147_483_647).map(&:id)
|
120
183
|
when 'collection'
|
121
184
|
ActiveFedora::SolrService.query("member_of_collection_ids_ssim:#{importerexporter.export_source + extra_filters}", rows: 2_000_000_000).map(&:id)
|
122
185
|
when 'worktype'
|
@@ -126,9 +189,16 @@ module Bulkrax
|
|
126
189
|
complete_statuses = Bulkrax::Status.latest_by_statusable
|
127
190
|
.includes(:statusable)
|
128
191
|
.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
192
|
|
131
|
-
|
193
|
+
complete_entry_identifiers = complete_statuses.map { |s| s.statusable&.identifier&.gsub(':', '\:') }
|
194
|
+
extra_filters = extra_filters.presence || '*:*'
|
195
|
+
|
196
|
+
ActiveFedora::SolrService.get(
|
197
|
+
extra_filters.to_s,
|
198
|
+
fq: "#{work_identifier}_sim:(#{complete_entry_identifiers.join(' OR ')})",
|
199
|
+
fl: 'id',
|
200
|
+
rows: 2_000_000_000
|
201
|
+
)['response']['docs'].map { |obj| obj['id'] }
|
132
202
|
end
|
133
203
|
end
|
134
204
|
|
@@ -136,12 +206,18 @@ module Bulkrax
|
|
136
206
|
current_work_ids.each_with_index do |wid, index|
|
137
207
|
break if limit_reached?(limit, index)
|
138
208
|
new_entry = find_or_create_entry(entry_class, wid, 'Bulkrax::Exporter')
|
139
|
-
|
209
|
+
begin
|
210
|
+
entry = Bulkrax::ExportWorkJob.perform_now(new_entry.id, current_run.id)
|
211
|
+
rescue => e
|
212
|
+
Rails.logger.info("#{e.message} was detected during export")
|
213
|
+
end
|
214
|
+
self.headers |= entry.parsed_metadata.keys if entry
|
140
215
|
end
|
141
216
|
end
|
142
217
|
alias create_from_collection create_new_entries
|
143
218
|
alias create_from_importer create_new_entries
|
144
219
|
alias create_from_worktype create_new_entries
|
220
|
+
alias create_from_all create_new_entries
|
145
221
|
|
146
222
|
def entry_class
|
147
223
|
CsvEntry
|
@@ -151,22 +227,18 @@ module Bulkrax
|
|
151
227
|
CsvCollectionEntry
|
152
228
|
end
|
153
229
|
|
230
|
+
def file_set_entry_class
|
231
|
+
CsvFileSetEntry
|
232
|
+
end
|
233
|
+
|
154
234
|
# See https://stackoverflow.com/questions/2650517/count-the-number-of-lines-in-a-file-without-reading-entire-file-into-memory
|
155
235
|
# Changed to grep as wc -l counts blank lines, and ignores the final unescaped line (which may or may not contain data)
|
156
236
|
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
|
237
|
+
@total = importer.parser_fields['total'] || 0 if importer?
|
238
|
+
@total = importerexporter.entries.count if exporter?
|
239
|
+
|
240
|
+
return @total || 0
|
241
|
+
rescue StandardError
|
170
242
|
@total = 0
|
171
243
|
end
|
172
244
|
|
@@ -201,32 +273,58 @@ module Bulkrax
|
|
201
273
|
end
|
202
274
|
end
|
203
275
|
|
204
|
-
def
|
205
|
-
|
206
|
-
new_entry(entry_class, 'Bulkrax::Exporter').field_supported?(key) &&
|
276
|
+
def export_key_allowed(key)
|
277
|
+
new_entry(entry_class, 'Bulkrax::Exporter').field_supported?(key) &&
|
207
278
|
key != source_identifier.to_s
|
208
279
|
end
|
209
280
|
|
210
281
|
# All possible column names
|
211
282
|
def export_headers
|
212
|
-
headers =
|
213
|
-
|
214
|
-
|
215
|
-
headers
|
216
|
-
|
217
|
-
headers
|
283
|
+
headers = sort_headers(self.headers)
|
284
|
+
|
285
|
+
# we don't want access_control_id exported and we want file at the end
|
286
|
+
headers.delete('access_control_id') if headers.include?('access_control_id')
|
287
|
+
|
288
|
+
# add the headers below at the beginning or end to maintain the preexisting export behavior
|
289
|
+
headers.prepend('model')
|
290
|
+
headers.prepend(source_identifier.to_s)
|
291
|
+
headers.prepend('id')
|
292
|
+
|
218
293
|
headers.uniq
|
219
294
|
end
|
220
295
|
|
296
|
+
def object_names
|
297
|
+
return @object_names if @object_names
|
298
|
+
|
299
|
+
@object_names = mapping.values.map { |value| value['object'] }
|
300
|
+
@object_names.uniq!.delete(nil)
|
301
|
+
|
302
|
+
@object_names
|
303
|
+
end
|
304
|
+
|
305
|
+
def sort_headers(headers)
|
306
|
+
# converting headers like creator_name_1 to creator_1_name so they get sorted by numerical order
|
307
|
+
# while keeping objects grouped together
|
308
|
+
headers.sort_by do |item|
|
309
|
+
number = item.match(/\d+/)&.[](0) || 0.to_s
|
310
|
+
sort_number = number.rjust(4, "0")
|
311
|
+
object_prefix = object_names.detect { |o| item.match(/^#{o}/) } || item
|
312
|
+
remainder = item.gsub(/^#{object_prefix}_/, '').gsub(/_#{number}/, '')
|
313
|
+
"#{object_prefix}_#{sort_number}_#{remainder}"
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
221
317
|
# in the parser as it is specific to the format
|
222
318
|
def setup_export_file
|
223
|
-
File.join(importerexporter.exporter_export_path,
|
319
|
+
File.join(importerexporter.exporter_export_path, "export_#{importerexporter.export_source}_from_#{importerexporter.export_from}.csv")
|
224
320
|
end
|
225
321
|
|
226
322
|
# Retrieve file paths for [:file] mapping in records
|
227
323
|
# and check all listed files exist.
|
228
324
|
def file_paths
|
229
325
|
raise StandardError, 'No records were found' if records.blank?
|
326
|
+
return [] if importerexporter.metadata_only?
|
327
|
+
|
230
328
|
@file_paths ||= records.map do |r|
|
231
329
|
file_mapping = Bulkrax.field_mappings.dig(self.class.to_s, 'file', :from)&.first&.to_sym || :file
|
232
330
|
next if r[file_mapping].blank?
|
@@ -245,23 +343,31 @@ module Bulkrax
|
|
245
343
|
# Retrieve the path where we expect to find the files
|
246
344
|
def path_to_files
|
247
345
|
@path_to_files ||= File.join(
|
248
|
-
|
346
|
+
zip? ? importer_unzip_path : File.dirname(import_file_path),
|
249
347
|
'files'
|
250
348
|
)
|
251
349
|
end
|
252
350
|
|
253
351
|
private
|
254
352
|
|
353
|
+
def unique_collection_identifier(collection_hash)
|
354
|
+
entry_uid = collection_hash[source_identifier]
|
355
|
+
entry_uid ||= if Bulkrax.fill_in_blank_source_identifiers.present?
|
356
|
+
Bulkrax.fill_in_blank_source_identifiers.call(self, records.find_index(collection_hash))
|
357
|
+
else
|
358
|
+
collection_hash[:title].split(/\s*[;|]\s*/).first
|
359
|
+
end
|
360
|
+
|
361
|
+
entry_uid
|
362
|
+
end
|
363
|
+
|
255
364
|
# Override to return the first CSV in the path, if a zip file is supplied
|
256
365
|
# We expect a single CSV at the top level of the zip in the CSVParser
|
257
366
|
# but we are willing to go look for it if need be
|
258
367
|
def real_import_file_path
|
259
|
-
if file? && zip?
|
260
|
-
|
261
|
-
|
262
|
-
else
|
263
|
-
parser_fields['import_file_path']
|
264
|
-
end
|
368
|
+
return Dir["#{importer_unzip_path}/**/*.csv"].first if file? && zip?
|
369
|
+
|
370
|
+
parser_fields['import_file_path']
|
265
371
|
end
|
266
372
|
end
|
267
373
|
end
|
@@ -75,8 +75,8 @@ 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
|
-
|
79
|
-
increment_counters(index, true)
|
78
|
+
ImportCollectionJob.perform_now(new_entry.id, importerexporter.current_run.id)
|
79
|
+
increment_counters(index, collection: true)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -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 ...',
|
@@ -57,8 +57,9 @@
|
|
57
57
|
<strong><%= t('bulkrax.exporter.labels.limit') %>:</strong>
|
58
58
|
<%= @exporter.limit %>
|
59
59
|
</p>
|
60
|
+
<%= render partial: 'bulkrax/shared/bulkrax_errors', locals: {item: @exporter} %>
|
60
61
|
|
61
|
-
|
62
|
+
<%= render partial: 'bulkrax/shared/bulkrax_field_mapping', locals: {item: @exporter} %>
|
62
63
|
|
63
64
|
<%# Currently, no parser-specific fields exist on Exporter,
|
64
65
|
thus there's no real reason to always show this field %>
|
@@ -24,6 +24,7 @@
|
|
24
24
|
<th scope="col">Entries Deleted Upstream</th>
|
25
25
|
<th scope="col">Total Collection Entries</th>
|
26
26
|
<th scope="col">Total Work Entries</th>
|
27
|
+
<th scope="col">Total File Set Entries</th>
|
27
28
|
<th scope="col"></th>
|
28
29
|
<th scope="col"></th>
|
29
30
|
<th scope="col"></th>
|
@@ -31,23 +32,22 @@
|
|
31
32
|
</thead>
|
32
33
|
<tbody>
|
33
34
|
<% @importers.each do |importer| %>
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
</tr>
|
35
|
+
<tr>
|
36
|
+
<th scope="row"><%= link_to importer.name, importer_path(importer) %></th>
|
37
|
+
<td><%= importer.status %></td>
|
38
|
+
<td><%= importer.last_imported_at.strftime("%b %d, %Y") if importer.last_imported_at %></td>
|
39
|
+
<td><%= importer.next_import_at.strftime("%b %d, %Y") if importer.next_import_at %></td>
|
40
|
+
<td><%= importer.last_run&.enqueued_records %></td>
|
41
|
+
<td><%= (importer.last_run&.processed_records || 0) %></td>
|
42
|
+
<td><%= (importer.last_run&.failed_records || 0) %></td>
|
43
|
+
<td><%= importer.last_run&.deleted_records %></td>
|
44
|
+
<td><%= importer.last_run&.total_collection_entries %></td>
|
45
|
+
<td><%= importer.last_run&.total_work_entries %></td>
|
46
|
+
<td><%= importer.last_run&.total_file_set_entries %></td>
|
47
|
+
<td><%= link_to raw('<span class="glyphicon glyphicon-info-sign"></span>'), importer_path(importer) %></td>
|
48
|
+
<td><%= link_to raw('<span class="glyphicon glyphicon-pencil"></span>'), edit_importer_path(importer) %></td>
|
49
|
+
<td><%= link_to raw('<span class="glyphicon glyphicon-remove"></span>'), importer, method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
50
|
+
</tr>
|
51
51
|
<% end %>
|
52
52
|
</tbody>
|
53
53
|
</table>
|
@@ -56,14 +56,19 @@
|
|
56
56
|
|
57
57
|
<%= render partial: 'bulkrax/shared/bulkrax_field_mapping', locals: {item: @importer} %>
|
58
58
|
|
59
|
-
<p class="bulkrax-p-align">
|
59
|
+
<p class="bulkrax-p-align" title="<%= @importer.last_run&.processed_works %> processed, <%= @importer.last_run&.failed_works %> failed">
|
60
60
|
<strong>Total Works:</strong>
|
61
|
-
<%= @importer.
|
61
|
+
<%= @importer.last_run&.total_work_entries %>
|
62
62
|
</p>
|
63
63
|
|
64
|
-
<p class="bulkrax-p-align">
|
64
|
+
<p class="bulkrax-p-align" title="<%= @importer.last_run&.processed_collections %> processed, <%= @importer.last_run&.failed_collections %> failed">
|
65
65
|
<strong>Total Collections:</strong>
|
66
|
-
<%= @importer.
|
66
|
+
<%= @importer.last_run&.total_collection_entries %>
|
67
|
+
</p>
|
68
|
+
|
69
|
+
<p class="bulkrax-p-align" title="<%= @importer.last_run&.processed_file_sets %> processed, <%= @importer.last_run&.failed_file_sets %> failed">
|
70
|
+
<strong>Total File Sets:</strong>
|
71
|
+
<%= @importer.last_run&.total_file_set_entries %>
|
67
72
|
</p>
|
68
73
|
|
69
74
|
<div class="bulkrax-nav-tab-bottom-margin">
|
@@ -71,6 +76,7 @@
|
|
71
76
|
<ul class="bulkrax-nav-tab-top-margin tab-nav nav nav-tabs" role="tablist">
|
72
77
|
<li role="presentation" class='active'><a href="#work-entries" aria-controls="work-entries" role="tab" data-toggle="tab">Work Entries</a></li>
|
73
78
|
<li role="presentation"><a href="#collection-entries" aria-controls="collection-entries" role="tab" data-toggle="tab">Collection Entries</a></li>
|
79
|
+
<li role="presentation"><a href="#file-set-entries" aria-controls="file-set-entries" role="tab" data-toggle="tab">File Set Entries</a></li>
|
74
80
|
</ul>
|
75
81
|
<!-- Tab panes -->
|
76
82
|
<div class="tab-content outline">
|
@@ -101,8 +107,10 @@
|
|
101
107
|
<td><%= e.id %></td>
|
102
108
|
<% if e.status == "Complete" %>
|
103
109
|
<td><span class="glyphicon glyphicon-ok" style="color: green;"></span> <%= e.status %></td>
|
110
|
+
<% elsif e.status == "Pending" %>
|
111
|
+
<td><span class="glyphicon glyphicon-option-horizontal" style="color: blue;"></span> <%= e.status %></td>
|
104
112
|
<% else %>
|
105
|
-
<td><span class="glyphicon glyphicon-remove" style="color: red
|
113
|
+
<td><span class="glyphicon glyphicon-remove" style="color: <%= e.status == 'Deleted' ? 'green' : 'red' %>;"></span> <%= e.status %></td>
|
106
114
|
<% end %>
|
107
115
|
<% if e.last_error.present? %>
|
108
116
|
<td><%= link_to e.last_error.dig("error_class"), bulkrax.importer_entry_path(@importer.id, e.id) %></td>
|
@@ -137,8 +145,10 @@
|
|
137
145
|
<td><%= e.id %></td>
|
138
146
|
<% if e.status == "Complete" %>
|
139
147
|
<td><span class="glyphicon glyphicon-ok" style="color: green;"></span> <%= e.status %></td>
|
148
|
+
<% elsif e.status == "Pending" %>
|
149
|
+
<td><span class="glyphicon glyphicon-option-horizontal" style="color: blue;"></span> <%= e.status %></td>
|
140
150
|
<% else %>
|
141
|
-
<td><span class="glyphicon glyphicon-remove" style="color: red
|
151
|
+
<td><span class="glyphicon glyphicon-remove" style="color: <%= e.status == 'Deleted' ? 'green' : 'red' %>;"></span> <%= e.status %></td>
|
142
152
|
<% end %>
|
143
153
|
<% if e.last_error.present? %>
|
144
154
|
<td><%= link_to e.last_error.dig("error_class"), bulkrax.importer_entry_path(@importer.id, e.id) %></td>
|
@@ -154,6 +164,42 @@
|
|
154
164
|
<%= page_entries_info(@collection_entries) %><br />
|
155
165
|
<%= paginate(@collection_entries, theme: 'blacklight', param_name: :collections_entries_page, params: {anchor: 'collection-entries'}) %>
|
156
166
|
</div>
|
167
|
+
<div role="tabpanel" class="tab-pane bulkrax-nav-tab-table-left-align" id="file-set-entries">
|
168
|
+
<table class='table table-striped'>
|
169
|
+
<thead>
|
170
|
+
<tr>
|
171
|
+
<th>Identifier</th>
|
172
|
+
<th>Entry ID</th>
|
173
|
+
<th>Status</th>
|
174
|
+
<th>Errors</th>
|
175
|
+
<th>Status Set At</th>
|
176
|
+
<th>Actions</th>
|
177
|
+
</tr>
|
178
|
+
</thead>
|
179
|
+
<tbody>
|
180
|
+
<% @file_set_entries.each do |e| %>
|
181
|
+
<tr>
|
182
|
+
<td><%= link_to e.identifier, bulkrax.importer_entry_path(@importer.id, e.id) %></td>
|
183
|
+
<td><%= e.id %></td>
|
184
|
+
<% if e.status == "Complete" %>
|
185
|
+
<td><span class="glyphicon glyphicon-ok" style="color: green;"></span> <%= e.status %></td>
|
186
|
+
<% else %>
|
187
|
+
<td><span class="glyphicon glyphicon-remove" style="color: red;"></span> <%= e.status %></td>
|
188
|
+
<% end %>
|
189
|
+
<% if e.last_error.present? %>
|
190
|
+
<td><%= link_to e.last_error.dig("error_class"), bulkrax.importer_entry_path(@importer.id, e.id) %></td>
|
191
|
+
<% else %>
|
192
|
+
<td></td>
|
193
|
+
<% end %>
|
194
|
+
<td><%= e.status_at %></td>
|
195
|
+
<td><%= link_to raw('<span class="glyphicon glyphicon-info-sign"></span>'), bulkrax.importer_entry_path(@importer.id, e.id) %></td>
|
196
|
+
</tr>
|
197
|
+
<% end %>
|
198
|
+
</tbody>
|
199
|
+
</table>
|
200
|
+
<%= page_entries_info(@file_set_entries) %><br />
|
201
|
+
<%= paginate(@file_set_entries, theme: 'blacklight', param_name: :file_set_entries_page, params: {anchor: 'file-set-entries'}) %>
|
202
|
+
</div>
|
157
203
|
</div>
|
158
204
|
</div>
|
159
205
|
|
@@ -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
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class AddFileSetCountersToImporterRuns < ActiveRecord::Migration[5.2]
|
2
|
+
def change
|
3
|
+
add_column :bulkrax_importer_runs, :processed_file_sets, :integer, default: 0 unless column_exists?(:bulkrax_importer_runs, :processed_file_sets)
|
4
|
+
add_column :bulkrax_importer_runs, :failed_file_sets, :integer, default: 0 unless column_exists?(:bulkrax_importer_runs, :failed_file_sets)
|
5
|
+
add_column :bulkrax_importer_runs, :total_file_set_entries, :integer, default: 0 unless column_exists?(:bulkrax_importer_runs, :total_file_set_entries)
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
class AddWorkCountersToImporterRuns < ActiveRecord::Migration[5.2]
|
2
|
+
def change
|
3
|
+
add_column :bulkrax_importer_runs, :processed_works, :integer, default: 0 unless column_exists?(:bulkrax_importer_runs, :processed_works)
|
4
|
+
add_column :bulkrax_importer_runs, :failed_works, :integer, default: 0 unless column_exists?(:bulkrax_importer_runs, :failed_works)
|
5
|
+
end
|
6
|
+
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