bulkrax 1.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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