bulkrax 1.0.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 +7 -0
- data/LICENSE +205 -0
- data/README.md +202 -0
- data/Rakefile +42 -0
- data/app/assets/config/bulkrax_manifest.js +2 -0
- data/app/assets/javascripts/bulkrax/application.js +14 -0
- data/app/assets/javascripts/bulkrax/bulkrax.js +11 -0
- data/app/assets/javascripts/bulkrax/entries.js +15 -0
- data/app/assets/javascripts/bulkrax/exporters.js +60 -0
- data/app/assets/javascripts/bulkrax/importers.js.erb +166 -0
- data/app/assets/stylesheets/bulkrax/accordion.scss +40 -0
- data/app/assets/stylesheets/bulkrax/application.css +15 -0
- data/app/assets/stylesheets/bulkrax/coderay.scss +264 -0
- data/app/assets/stylesheets/bulkrax/import_export.scss +37 -0
- data/app/controllers/bulkrax/application_controller.rb +8 -0
- data/app/controllers/bulkrax/entries_controller.rb +44 -0
- data/app/controllers/bulkrax/exporters_controller.rb +125 -0
- data/app/controllers/bulkrax/importers_controller.rb +315 -0
- data/app/controllers/concerns/bulkrax/api.rb +29 -0
- data/app/factories/bulkrax/object_factory.rb +230 -0
- data/app/helpers/bulkrax/application_helper.rb +15 -0
- data/app/helpers/bulkrax/exporters_helper.rb +6 -0
- data/app/helpers/bulkrax/importers_helper.rb +13 -0
- data/app/helpers/bulkrax/validation_helper.rb +153 -0
- data/app/jobs/bulkrax/application_job.rb +6 -0
- data/app/jobs/bulkrax/child_relationships_job.rb +128 -0
- data/app/jobs/bulkrax/delete_work_job.rb +16 -0
- data/app/jobs/bulkrax/download_cloud_file_job.rb +18 -0
- data/app/jobs/bulkrax/export_work_job.rb +37 -0
- data/app/jobs/bulkrax/exporter_job.rb +14 -0
- data/app/jobs/bulkrax/import_work_collection_job.rb +41 -0
- data/app/jobs/bulkrax/import_work_job.rb +32 -0
- data/app/jobs/bulkrax/importer_job.rb +26 -0
- data/app/mailers/bulkrax/application_mailer.rb +8 -0
- data/app/matchers/bulkrax/application_matcher.rb +113 -0
- data/app/matchers/bulkrax/bagit_matcher.rb +6 -0
- data/app/matchers/bulkrax/csv_matcher.rb +6 -0
- data/app/matchers/bulkrax/oai_matcher.rb +6 -0
- data/app/models/bulkrax/application_record.rb +7 -0
- data/app/models/bulkrax/csv_collection_entry.rb +19 -0
- data/app/models/bulkrax/csv_entry.rb +163 -0
- data/app/models/bulkrax/entry.rb +104 -0
- data/app/models/bulkrax/exporter.rb +122 -0
- data/app/models/bulkrax/exporter_run.rb +7 -0
- data/app/models/bulkrax/import_failed.rb +13 -0
- data/app/models/bulkrax/importer.rb +155 -0
- data/app/models/bulkrax/importer_run.rb +8 -0
- data/app/models/bulkrax/oai_dc_entry.rb +6 -0
- data/app/models/bulkrax/oai_entry.rb +74 -0
- data/app/models/bulkrax/oai_qualified_dc_entry.rb +6 -0
- data/app/models/bulkrax/oai_set_entry.rb +19 -0
- data/app/models/bulkrax/rdf_collection_entry.rb +19 -0
- data/app/models/bulkrax/rdf_entry.rb +90 -0
- data/app/models/bulkrax/status.rb +25 -0
- data/app/models/bulkrax/xml_entry.rb +73 -0
- data/app/models/concerns/bulkrax/download_behavior.rb +61 -0
- data/app/models/concerns/bulkrax/errored_entries.rb +45 -0
- data/app/models/concerns/bulkrax/export_behavior.rb +58 -0
- data/app/models/concerns/bulkrax/file_factory.rb +140 -0
- data/app/models/concerns/bulkrax/has_local_processing.rb +7 -0
- data/app/models/concerns/bulkrax/has_matchers.rb +155 -0
- data/app/models/concerns/bulkrax/import_behavior.rb +90 -0
- data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +34 -0
- data/app/models/concerns/bulkrax/status_info.rb +56 -0
- data/app/parsers/bulkrax/application_parser.rb +299 -0
- data/app/parsers/bulkrax/bagit_parser.rb +157 -0
- data/app/parsers/bulkrax/csv_parser.rb +266 -0
- data/app/parsers/bulkrax/oai_dc_parser.rb +130 -0
- data/app/parsers/bulkrax/oai_qualified_dc_parser.rb +9 -0
- data/app/parsers/bulkrax/xml_parser.rb +103 -0
- data/app/views/bulkrax/entries/_parsed_metadata.html.erb +19 -0
- data/app/views/bulkrax/entries/_raw_metadata.html.erb +19 -0
- data/app/views/bulkrax/entries/show.html.erb +63 -0
- data/app/views/bulkrax/exporters/_form.html.erb +120 -0
- data/app/views/bulkrax/exporters/edit.html.erb +23 -0
- data/app/views/bulkrax/exporters/index.html.erb +67 -0
- data/app/views/bulkrax/exporters/new.html.erb +23 -0
- data/app/views/bulkrax/exporters/show.html.erb +124 -0
- data/app/views/bulkrax/importers/_bagit_fields.html.erb +54 -0
- data/app/views/bulkrax/importers/_browse_everything.html.erb +12 -0
- data/app/views/bulkrax/importers/_csv_fields.html.erb +39 -0
- data/app/views/bulkrax/importers/_edit_form_buttons.html.erb +16 -0
- data/app/views/bulkrax/importers/_form.html.erb +35 -0
- data/app/views/bulkrax/importers/_oai_fields.html.erb +42 -0
- data/app/views/bulkrax/importers/_xml_fields.html.erb +60 -0
- data/app/views/bulkrax/importers/edit.html.erb +20 -0
- data/app/views/bulkrax/importers/index.html.erb +77 -0
- data/app/views/bulkrax/importers/new.html.erb +25 -0
- data/app/views/bulkrax/importers/show.html.erb +175 -0
- data/app/views/bulkrax/importers/upload_corrected_entries.html.erb +37 -0
- data/app/views/bulkrax/shared/_bulkrax_errors.html.erb +52 -0
- data/app/views/bulkrax/shared/_bulkrax_field_mapping.html.erb +39 -0
- data/app/views/hyrax/dashboard/sidebar/_bulkrax_sidebar_additions.html.erb +6 -0
- data/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb +19 -0
- data/app/views/layouts/bulkrax/application.html.erb +14 -0
- data/config/locales/bulkrax.en.yml +36 -0
- data/config/routes.rb +18 -0
- data/db/migrate/20181011230201_create_bulkrax_importers.rb +18 -0
- data/db/migrate/20181011230228_create_bulkrax_importer_runs.rb +16 -0
- data/db/migrate/20190325183136_create_bulkrax_entries.rb +16 -0
- data/db/migrate/20190601221109_add_status_to_entry.rb +9 -0
- data/db/migrate/20190715161939_add_collections_to_importer_runs.rb +6 -0
- data/db/migrate/20190715162044_change_collection_ids_on_entries.rb +5 -0
- data/db/migrate/20190729124607_create_bulkrax_exporters.rb +19 -0
- data/db/migrate/20190729134158_create_bulkrax_exporter_runs.rb +14 -0
- data/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb +12 -0
- data/db/migrate/20191203225129_add_total_collection_records_to_importer_runs.rb +5 -0
- data/db/migrate/20191204191623_add_children_to_importer_runs.rb +6 -0
- data/db/migrate/20191204223857_change_total_records_to_total_work_entries.rb +6 -0
- data/db/migrate/20191212155530_change_entry_last_error.rb +19 -0
- data/db/migrate/20200108194557_add_validate_only_to_bulkrax_importers.rb +5 -0
- data/db/migrate/20200301232856_add_status_to_importers.rb +9 -0
- data/db/migrate/20200312190638_remove_foreign_key_from_bulkrax_entries.rb +5 -0
- data/db/migrate/20200326235838_add_status_to_exporters.rb +7 -0
- data/db/migrate/20200601204556_add_invalid_record_to_importer_run.rb +5 -0
- data/db/migrate/20200818055819_create_bulkrax_statuses.rb +18 -0
- data/db/migrate/20200819054016_move_to_statuses.rb +30 -0
- data/db/migrate/20201106014204_add_date_filter_and_status_to_bulkrax_exporters.rb +7 -0
- data/db/migrate/20201117220007_add_workflow_status_to_bulkrax_exporter.rb +5 -0
- data/db/migrate/20210806044408_remove_unused_last_error.rb +7 -0
- data/db/migrate/20210806065737_increase_text_sizes.rb +12 -0
- data/lib/bulkrax.rb +161 -0
- data/lib/bulkrax/engine.rb +37 -0
- data/lib/bulkrax/version.rb +5 -0
- data/lib/generators/bulkrax/install_generator.rb +80 -0
- data/lib/generators/bulkrax/templates/README +3 -0
- data/lib/generators/bulkrax/templates/app/assets/images/bulkrax/removed.png +0 -0
- data/lib/generators/bulkrax/templates/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
- data/lib/generators/bulkrax/templates/bin/importer +140 -0
- data/lib/generators/bulkrax/templates/config/bulkrax_api.yml +84 -0
- data/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb +72 -0
- data/lib/tasks/bulkrax_tasks.rake +6 -0
- metadata +388 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bulkrax
|
4
|
+
# Import Behavior for Entry classes
|
5
|
+
module ImportBehavior
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def build_for_importer
|
9
|
+
begin
|
10
|
+
build_metadata
|
11
|
+
unless self.importerexporter.validate_only
|
12
|
+
raise CollectionsCreatedError unless collections_created?
|
13
|
+
@item = factory.run!
|
14
|
+
end
|
15
|
+
rescue RSolr::Error::Http, CollectionsCreatedError => e
|
16
|
+
raise e
|
17
|
+
rescue StandardError => e
|
18
|
+
status_info(e)
|
19
|
+
else
|
20
|
+
status_info
|
21
|
+
end
|
22
|
+
return @item
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_or_create_collection_ids
|
26
|
+
self.collection_ids
|
27
|
+
end
|
28
|
+
|
29
|
+
# override this in a sub-class of Entry to ensure any collections have been created before building the work
|
30
|
+
def collections_created?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_metadata
|
35
|
+
raise StandardError, 'Not Implemented'
|
36
|
+
end
|
37
|
+
|
38
|
+
def rights_statement
|
39
|
+
parser.parser_fields['rights_statement']
|
40
|
+
end
|
41
|
+
|
42
|
+
# try and deal with a couple possible states for this input field
|
43
|
+
def override_rights_statement
|
44
|
+
%w[true 1].include?(parser.parser_fields['override_rights_statement'].to_s)
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_rights_statement
|
48
|
+
self.parsed_metadata['rights_statement'] = [parser.parser_fields['rights_statement']] if override_rights_statement || self.parsed_metadata['rights_statement'].blank?
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_visibility
|
52
|
+
self.parsed_metadata['visibility'] = importerexporter.visibility if self.parsed_metadata['visibility'].blank?
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_admin_set_id
|
56
|
+
self.parsed_metadata['admin_set_id'] = importerexporter.admin_set_id if self.parsed_metadata['admin_set_id'].blank?
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_collections
|
60
|
+
return if find_or_create_collection_ids.blank?
|
61
|
+
self.parsed_metadata['collections'] = []
|
62
|
+
self.parsed_metadata['collections'] += find_or_create_collection_ids.map { |c| { id: c } }
|
63
|
+
end
|
64
|
+
|
65
|
+
def factory
|
66
|
+
@factory ||= Bulkrax::ObjectFactory.new(attributes: self.parsed_metadata,
|
67
|
+
source_identifier_value: identifier,
|
68
|
+
work_identifier: parser.work_identifier,
|
69
|
+
replace_files: replace_files,
|
70
|
+
user: user,
|
71
|
+
klass: factory_class,
|
72
|
+
update_files: update_files)
|
73
|
+
end
|
74
|
+
|
75
|
+
def factory_class
|
76
|
+
fc = if self.parsed_metadata&.[]('model').present?
|
77
|
+
self.parsed_metadata&.[]('model').is_a?(Array) ? self.parsed_metadata&.[]('model')&.first : self.parsed_metadata&.[]('model')
|
78
|
+
elsif self.mapping&.[]('work_type').present?
|
79
|
+
self.parsed_metadata&.[]('work_type').is_a?(Array) ? self.parsed_metadata&.[]('work_type')&.first : self.parsed_metadata&.[]('work_type')
|
80
|
+
else
|
81
|
+
Bulkrax.default_work_type
|
82
|
+
end
|
83
|
+
fc.constantize
|
84
|
+
rescue NameError
|
85
|
+
nil
|
86
|
+
rescue
|
87
|
+
Bulkrax.default_work_type.constantize
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bulkrax
|
4
|
+
module ImporterExporterBehavior
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def parser
|
8
|
+
@parser ||= parser_class.new(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def parser_class
|
12
|
+
self.parser_klass.constantize
|
13
|
+
end
|
14
|
+
|
15
|
+
def last_imported_at
|
16
|
+
@last_imported_at ||= self.importer_runs.last&.created_at
|
17
|
+
end
|
18
|
+
|
19
|
+
def next_import_at
|
20
|
+
(last_imported_at || Time.current) + frequency.to_seconds if schedulable? && last_imported_at.present?
|
21
|
+
end
|
22
|
+
|
23
|
+
def increment_counters(index, collection = false)
|
24
|
+
# Only set the totals if they were not set on initialization
|
25
|
+
if collection
|
26
|
+
current_run.total_collection_entries = index + 1 unless parser.collections_total.positive?
|
27
|
+
else
|
28
|
+
current_run.total_work_entries = index + 1 unless limit.to_i.positive? || parser.total.positive?
|
29
|
+
end
|
30
|
+
current_run.enqueued_records = index + 1
|
31
|
+
current_run.save!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Bulkrax
|
3
|
+
module StatusInfo
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :statuses, as: :statusable, dependent: :destroy
|
8
|
+
has_one :latest_status,
|
9
|
+
-> { merge(Status.latest_by_statusable) },
|
10
|
+
as: :statusable,
|
11
|
+
class_name: "Bulkrax::Status",
|
12
|
+
inverse_of: :statusable
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_status
|
16
|
+
last_status = self.statuses.last
|
17
|
+
last_status if last_status && last_status.runnable == last_run
|
18
|
+
end
|
19
|
+
|
20
|
+
def failed?
|
21
|
+
current_status&.status_message&.match(/fail/i)
|
22
|
+
end
|
23
|
+
|
24
|
+
def succeeded?
|
25
|
+
current_status&.status_message&.match(/^Complete$/)
|
26
|
+
end
|
27
|
+
|
28
|
+
def status
|
29
|
+
current_status&.status_message || 'Pending'
|
30
|
+
end
|
31
|
+
|
32
|
+
def status_at
|
33
|
+
current_status&.created_at
|
34
|
+
end
|
35
|
+
|
36
|
+
def status_info(e = nil)
|
37
|
+
if e.nil?
|
38
|
+
self.statuses.create!(status_message: 'Complete', runnable: last_run)
|
39
|
+
elsif e.is_a?(String)
|
40
|
+
self.statuses.create!(status_message: e, runnable: last_run)
|
41
|
+
else
|
42
|
+
self.statuses.create!(status_message: 'Failed', runnable: last_run, error_class: e.class.to_s, error_message: e.message, error_backtrace: e.backtrace)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# api compatible with previous error structure
|
47
|
+
def last_error
|
48
|
+
return unless current_status && current_status.error_class.present?
|
49
|
+
{
|
50
|
+
error_class: current_status.error_class,
|
51
|
+
error_message: current_status.error_message,
|
52
|
+
error_trace: current_status.error_backtrace
|
53
|
+
}.with_indifferent_access
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bulkrax
|
4
|
+
class ApplicationParser
|
5
|
+
attr_accessor :importerexporter
|
6
|
+
alias importer importerexporter
|
7
|
+
alias exporter importerexporter
|
8
|
+
delegate :only_updates, :limit, :current_run, :errors,
|
9
|
+
:seen, :increment_counters, :parser_fields, :user,
|
10
|
+
:exporter_export_path, :exporter_export_zip_path, :importer_unzip_path, :validate_only,
|
11
|
+
:status, :status_info, :status_at,
|
12
|
+
to: :importerexporter
|
13
|
+
|
14
|
+
def self.parser_fields
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.export_supported?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.import_supported?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(importerexporter)
|
27
|
+
@importerexporter = importerexporter
|
28
|
+
end
|
29
|
+
|
30
|
+
# @api
|
31
|
+
def entry_class
|
32
|
+
raise StandardError, 'must be defined'
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api
|
36
|
+
def collection_entry_class
|
37
|
+
raise StandardError, 'must be defined'
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api
|
41
|
+
def records(_opts = {})
|
42
|
+
raise StandardError, 'must be defined'
|
43
|
+
end
|
44
|
+
|
45
|
+
def source_identifier
|
46
|
+
@source_identifier ||= identifier_hash.values.first&.[]("from")&.first&.to_sym || :source_identifier
|
47
|
+
end
|
48
|
+
|
49
|
+
def work_identifier
|
50
|
+
@work_identifier ||= identifier_hash.keys.first&.to_sym || :source
|
51
|
+
end
|
52
|
+
|
53
|
+
def identifier_hash
|
54
|
+
@identifier_hash ||= importerexporter.mapping.select do |_, h|
|
55
|
+
h.key?("source_identifier")
|
56
|
+
end
|
57
|
+
raise StandardError, "more than one source_identifier declared: #{@identifier_hash.keys.join(', ')}" if @identifier_hash.length > 1
|
58
|
+
|
59
|
+
@identifier_hash
|
60
|
+
end
|
61
|
+
|
62
|
+
def perform_method
|
63
|
+
if self.validate_only
|
64
|
+
'perform_now'
|
65
|
+
else
|
66
|
+
'perform_later'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def visibility
|
71
|
+
@visibility ||= self.parser_fields['visibility'] || 'open'
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_collections
|
75
|
+
raise StandardError, 'must be defined' if importer?
|
76
|
+
end
|
77
|
+
|
78
|
+
def create_works
|
79
|
+
raise StandardError, 'must be defined' if importer?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Optional, define if using browse everything for file upload
|
83
|
+
def retrieve_cloud_files(files); end
|
84
|
+
|
85
|
+
def write_import_file(file)
|
86
|
+
path = File.join(path_for_import, file.original_filename)
|
87
|
+
FileUtils.mv(
|
88
|
+
file.path,
|
89
|
+
path
|
90
|
+
)
|
91
|
+
path
|
92
|
+
end
|
93
|
+
|
94
|
+
# Path where we'll store the import metadata and files
|
95
|
+
# this is used for uploaded and cloud files
|
96
|
+
def path_for_import
|
97
|
+
@path_for_import = File.join(Bulkrax.import_path, importerexporter.path_string)
|
98
|
+
FileUtils.mkdir_p(@path_for_import) unless File.exist?(@path_for_import)
|
99
|
+
@path_for_import
|
100
|
+
end
|
101
|
+
|
102
|
+
# Optional, only used by certain parsers
|
103
|
+
# Other parsers should override with a custom or empty method
|
104
|
+
# Will be skipped unless the #record is a Hash
|
105
|
+
def create_parent_child_relationships
|
106
|
+
parents.each do |key, value|
|
107
|
+
parent = entry_class.where(
|
108
|
+
identifier: key,
|
109
|
+
importerexporter_id: importerexporter.id,
|
110
|
+
importerexporter_type: 'Bulkrax::Importer'
|
111
|
+
).first
|
112
|
+
|
113
|
+
# not finding the entries here indicates that the given identifiers are incorrect
|
114
|
+
# in that case we should log that
|
115
|
+
children = value.map do |child|
|
116
|
+
entry_class.where(
|
117
|
+
identifier: child,
|
118
|
+
importerexporter_id: importerexporter.id,
|
119
|
+
importerexporter_type: 'Bulkrax::Importer'
|
120
|
+
).first
|
121
|
+
end.compact.uniq
|
122
|
+
|
123
|
+
if parent.present? && (children.length != value.length)
|
124
|
+
# Increment the failures for the number we couldn't find
|
125
|
+
# Because all of our entries have been created by now, if we can't find them, the data is wrong
|
126
|
+
Rails.logger.error("Expected #{value.length} children for parent entry #{parent.id}, found #{children.length}")
|
127
|
+
break if children.empty?
|
128
|
+
Rails.logger.warn("Adding #{children.length} children to parent entry #{parent.id} (expected #{value.length})")
|
129
|
+
end
|
130
|
+
parent_id = parent.id
|
131
|
+
child_entry_ids = children.map(&:id)
|
132
|
+
ChildRelationshipsJob.perform_later(parent_id, child_entry_ids, current_run.id)
|
133
|
+
end
|
134
|
+
rescue StandardError => e
|
135
|
+
status_info(e)
|
136
|
+
end
|
137
|
+
|
138
|
+
def parents
|
139
|
+
@parents ||= setup_parents
|
140
|
+
end
|
141
|
+
|
142
|
+
def setup_parents
|
143
|
+
pts = []
|
144
|
+
records.each do |record|
|
145
|
+
r = if record.respond_to?(:to_h)
|
146
|
+
record.to_h
|
147
|
+
else
|
148
|
+
record
|
149
|
+
end
|
150
|
+
next unless r.is_a?(Hash)
|
151
|
+
children = if r[:children].is_a?(String)
|
152
|
+
r[:children].split(/\s*[:;|]\s*/)
|
153
|
+
else
|
154
|
+
r[:children]
|
155
|
+
end
|
156
|
+
next if children.blank?
|
157
|
+
pts << {
|
158
|
+
r[source_identifier] => children
|
159
|
+
}
|
160
|
+
end
|
161
|
+
pts.blank? ? pts : pts.inject(:merge)
|
162
|
+
end
|
163
|
+
|
164
|
+
def setup_export_file
|
165
|
+
raise StandardError, 'must be defined' if exporter?
|
166
|
+
end
|
167
|
+
|
168
|
+
def write_files
|
169
|
+
raise StandardError, 'must be defined' if exporter?
|
170
|
+
end
|
171
|
+
|
172
|
+
def importer?
|
173
|
+
importerexporter.is_a?(Bulkrax::Importer)
|
174
|
+
end
|
175
|
+
|
176
|
+
def exporter?
|
177
|
+
importerexporter.is_a?(Bulkrax::Exporter)
|
178
|
+
end
|
179
|
+
|
180
|
+
# @param limit [Integer] limit set on the importerexporter
|
181
|
+
# @param index [Integer] index of current iteration
|
182
|
+
# @return [boolean]
|
183
|
+
def limit_reached?(limit, index)
|
184
|
+
return false if limit.nil? || limit.zero? # no limit
|
185
|
+
index >= limit
|
186
|
+
end
|
187
|
+
|
188
|
+
# Override to add specific validations
|
189
|
+
def valid_import?
|
190
|
+
true
|
191
|
+
end
|
192
|
+
|
193
|
+
def record_has_source_identifier(record, index)
|
194
|
+
if record[source_identifier].blank?
|
195
|
+
if Bulkrax.fill_in_blank_source_identifiers.present?
|
196
|
+
record[source_identifier] = Bulkrax.fill_in_blank_source_identifiers.call(self, index)
|
197
|
+
else
|
198
|
+
invalid_record("Missing #{source_identifier} for #{record.to_h}\n")
|
199
|
+
false
|
200
|
+
end
|
201
|
+
else
|
202
|
+
true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# rubocop:disable Rails/SkipsModelValidations
|
207
|
+
def invalid_record(message)
|
208
|
+
current_run.invalid_records ||= ""
|
209
|
+
current_run.invalid_records += message
|
210
|
+
current_run.save
|
211
|
+
ImporterRun.find(current_run.id).increment!(:failed_records)
|
212
|
+
ImporterRun.find(current_run.id).decrement!(:enqueued_records) unless ImporterRun.find(current_run.id).enqueued_records <= 0 # rubocop:disable Style/IdenticalConditionalBranches
|
213
|
+
end
|
214
|
+
# rubocop:enable Rails/SkipsModelValidations
|
215
|
+
|
216
|
+
def required_elements
|
217
|
+
if Bulkrax.fill_in_blank_source_identifiers
|
218
|
+
['title']
|
219
|
+
else
|
220
|
+
['title', source_identifier]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def new_entry(entryclass, type)
|
225
|
+
entryclass.new(
|
226
|
+
importerexporter_id: importerexporter.id,
|
227
|
+
importerexporter_type: type
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
def find_or_create_entry(entryclass, identifier, type, raw_metadata = nil)
|
232
|
+
entry = entryclass.where(
|
233
|
+
importerexporter_id: importerexporter.id,
|
234
|
+
importerexporter_type: type,
|
235
|
+
identifier: identifier
|
236
|
+
).first_or_create!
|
237
|
+
entry.raw_metadata = raw_metadata
|
238
|
+
entry.save!
|
239
|
+
entry
|
240
|
+
end
|
241
|
+
|
242
|
+
# @todo - review this method - is it ever used?
|
243
|
+
def record(identifier, _opts = {})
|
244
|
+
return @record if @record
|
245
|
+
|
246
|
+
@record = entry_class.new(self, identifier)
|
247
|
+
@record.build
|
248
|
+
return @record
|
249
|
+
end
|
250
|
+
|
251
|
+
def total
|
252
|
+
0
|
253
|
+
end
|
254
|
+
|
255
|
+
def collections_total
|
256
|
+
0
|
257
|
+
end
|
258
|
+
|
259
|
+
def write
|
260
|
+
write_files
|
261
|
+
zip
|
262
|
+
end
|
263
|
+
|
264
|
+
def unzip(file_to_unzip)
|
265
|
+
WillowSword::ZipPackage.new(file_to_unzip, importer_unzip_path).unzip_file
|
266
|
+
end
|
267
|
+
|
268
|
+
def zip
|
269
|
+
FileUtils.rm_rf(exporter_export_zip_path)
|
270
|
+
WillowSword::ZipPackage.new(exporter_export_path, exporter_export_zip_path).create_zip
|
271
|
+
end
|
272
|
+
|
273
|
+
# Is this a file?
|
274
|
+
def file?
|
275
|
+
parser_fields&.[]('import_file_path') && File.file?(parser_fields['import_file_path'])
|
276
|
+
end
|
277
|
+
|
278
|
+
# Is this a zip file?
|
279
|
+
def zip?
|
280
|
+
parser_fields&.[]('import_file_path') && MIME::Types.type_for(parser_fields['import_file_path']).include?('application/zip')
|
281
|
+
end
|
282
|
+
|
283
|
+
# Path for the import
|
284
|
+
def import_file_path
|
285
|
+
@import_file_path ||= real_import_file_path
|
286
|
+
end
|
287
|
+
|
288
|
+
private
|
289
|
+
|
290
|
+
def real_import_file_path
|
291
|
+
if file? && zip?
|
292
|
+
unzip(parser_fields['import_file_path'])
|
293
|
+
return importer_unzip_path
|
294
|
+
else
|
295
|
+
parser_fields['import_file_path']
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|