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