bulkrax 1.0.1 → 2.0.2
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 +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