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.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +205 -0
  3. data/README.md +202 -0
  4. data/Rakefile +42 -0
  5. data/app/assets/config/bulkrax_manifest.js +2 -0
  6. data/app/assets/javascripts/bulkrax/application.js +14 -0
  7. data/app/assets/javascripts/bulkrax/bulkrax.js +11 -0
  8. data/app/assets/javascripts/bulkrax/entries.js +15 -0
  9. data/app/assets/javascripts/bulkrax/exporters.js +60 -0
  10. data/app/assets/javascripts/bulkrax/importers.js.erb +166 -0
  11. data/app/assets/stylesheets/bulkrax/accordion.scss +40 -0
  12. data/app/assets/stylesheets/bulkrax/application.css +15 -0
  13. data/app/assets/stylesheets/bulkrax/coderay.scss +264 -0
  14. data/app/assets/stylesheets/bulkrax/import_export.scss +37 -0
  15. data/app/controllers/bulkrax/application_controller.rb +8 -0
  16. data/app/controllers/bulkrax/entries_controller.rb +44 -0
  17. data/app/controllers/bulkrax/exporters_controller.rb +125 -0
  18. data/app/controllers/bulkrax/importers_controller.rb +315 -0
  19. data/app/controllers/concerns/bulkrax/api.rb +29 -0
  20. data/app/factories/bulkrax/object_factory.rb +230 -0
  21. data/app/helpers/bulkrax/application_helper.rb +15 -0
  22. data/app/helpers/bulkrax/exporters_helper.rb +6 -0
  23. data/app/helpers/bulkrax/importers_helper.rb +13 -0
  24. data/app/helpers/bulkrax/validation_helper.rb +153 -0
  25. data/app/jobs/bulkrax/application_job.rb +6 -0
  26. data/app/jobs/bulkrax/child_relationships_job.rb +128 -0
  27. data/app/jobs/bulkrax/delete_work_job.rb +16 -0
  28. data/app/jobs/bulkrax/download_cloud_file_job.rb +18 -0
  29. data/app/jobs/bulkrax/export_work_job.rb +37 -0
  30. data/app/jobs/bulkrax/exporter_job.rb +14 -0
  31. data/app/jobs/bulkrax/import_work_collection_job.rb +41 -0
  32. data/app/jobs/bulkrax/import_work_job.rb +32 -0
  33. data/app/jobs/bulkrax/importer_job.rb +26 -0
  34. data/app/mailers/bulkrax/application_mailer.rb +8 -0
  35. data/app/matchers/bulkrax/application_matcher.rb +113 -0
  36. data/app/matchers/bulkrax/bagit_matcher.rb +6 -0
  37. data/app/matchers/bulkrax/csv_matcher.rb +6 -0
  38. data/app/matchers/bulkrax/oai_matcher.rb +6 -0
  39. data/app/models/bulkrax/application_record.rb +7 -0
  40. data/app/models/bulkrax/csv_collection_entry.rb +19 -0
  41. data/app/models/bulkrax/csv_entry.rb +163 -0
  42. data/app/models/bulkrax/entry.rb +104 -0
  43. data/app/models/bulkrax/exporter.rb +122 -0
  44. data/app/models/bulkrax/exporter_run.rb +7 -0
  45. data/app/models/bulkrax/import_failed.rb +13 -0
  46. data/app/models/bulkrax/importer.rb +155 -0
  47. data/app/models/bulkrax/importer_run.rb +8 -0
  48. data/app/models/bulkrax/oai_dc_entry.rb +6 -0
  49. data/app/models/bulkrax/oai_entry.rb +74 -0
  50. data/app/models/bulkrax/oai_qualified_dc_entry.rb +6 -0
  51. data/app/models/bulkrax/oai_set_entry.rb +19 -0
  52. data/app/models/bulkrax/rdf_collection_entry.rb +19 -0
  53. data/app/models/bulkrax/rdf_entry.rb +90 -0
  54. data/app/models/bulkrax/status.rb +25 -0
  55. data/app/models/bulkrax/xml_entry.rb +73 -0
  56. data/app/models/concerns/bulkrax/download_behavior.rb +61 -0
  57. data/app/models/concerns/bulkrax/errored_entries.rb +45 -0
  58. data/app/models/concerns/bulkrax/export_behavior.rb +58 -0
  59. data/app/models/concerns/bulkrax/file_factory.rb +140 -0
  60. data/app/models/concerns/bulkrax/has_local_processing.rb +7 -0
  61. data/app/models/concerns/bulkrax/has_matchers.rb +155 -0
  62. data/app/models/concerns/bulkrax/import_behavior.rb +90 -0
  63. data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +34 -0
  64. data/app/models/concerns/bulkrax/status_info.rb +56 -0
  65. data/app/parsers/bulkrax/application_parser.rb +299 -0
  66. data/app/parsers/bulkrax/bagit_parser.rb +157 -0
  67. data/app/parsers/bulkrax/csv_parser.rb +266 -0
  68. data/app/parsers/bulkrax/oai_dc_parser.rb +130 -0
  69. data/app/parsers/bulkrax/oai_qualified_dc_parser.rb +9 -0
  70. data/app/parsers/bulkrax/xml_parser.rb +103 -0
  71. data/app/views/bulkrax/entries/_parsed_metadata.html.erb +19 -0
  72. data/app/views/bulkrax/entries/_raw_metadata.html.erb +19 -0
  73. data/app/views/bulkrax/entries/show.html.erb +63 -0
  74. data/app/views/bulkrax/exporters/_form.html.erb +120 -0
  75. data/app/views/bulkrax/exporters/edit.html.erb +23 -0
  76. data/app/views/bulkrax/exporters/index.html.erb +67 -0
  77. data/app/views/bulkrax/exporters/new.html.erb +23 -0
  78. data/app/views/bulkrax/exporters/show.html.erb +124 -0
  79. data/app/views/bulkrax/importers/_bagit_fields.html.erb +54 -0
  80. data/app/views/bulkrax/importers/_browse_everything.html.erb +12 -0
  81. data/app/views/bulkrax/importers/_csv_fields.html.erb +39 -0
  82. data/app/views/bulkrax/importers/_edit_form_buttons.html.erb +16 -0
  83. data/app/views/bulkrax/importers/_form.html.erb +35 -0
  84. data/app/views/bulkrax/importers/_oai_fields.html.erb +42 -0
  85. data/app/views/bulkrax/importers/_xml_fields.html.erb +60 -0
  86. data/app/views/bulkrax/importers/edit.html.erb +20 -0
  87. data/app/views/bulkrax/importers/index.html.erb +77 -0
  88. data/app/views/bulkrax/importers/new.html.erb +25 -0
  89. data/app/views/bulkrax/importers/show.html.erb +175 -0
  90. data/app/views/bulkrax/importers/upload_corrected_entries.html.erb +37 -0
  91. data/app/views/bulkrax/shared/_bulkrax_errors.html.erb +52 -0
  92. data/app/views/bulkrax/shared/_bulkrax_field_mapping.html.erb +39 -0
  93. data/app/views/hyrax/dashboard/sidebar/_bulkrax_sidebar_additions.html.erb +6 -0
  94. data/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb +19 -0
  95. data/app/views/layouts/bulkrax/application.html.erb +14 -0
  96. data/config/locales/bulkrax.en.yml +36 -0
  97. data/config/routes.rb +18 -0
  98. data/db/migrate/20181011230201_create_bulkrax_importers.rb +18 -0
  99. data/db/migrate/20181011230228_create_bulkrax_importer_runs.rb +16 -0
  100. data/db/migrate/20190325183136_create_bulkrax_entries.rb +16 -0
  101. data/db/migrate/20190601221109_add_status_to_entry.rb +9 -0
  102. data/db/migrate/20190715161939_add_collections_to_importer_runs.rb +6 -0
  103. data/db/migrate/20190715162044_change_collection_ids_on_entries.rb +5 -0
  104. data/db/migrate/20190729124607_create_bulkrax_exporters.rb +19 -0
  105. data/db/migrate/20190729134158_create_bulkrax_exporter_runs.rb +14 -0
  106. data/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb +12 -0
  107. data/db/migrate/20191203225129_add_total_collection_records_to_importer_runs.rb +5 -0
  108. data/db/migrate/20191204191623_add_children_to_importer_runs.rb +6 -0
  109. data/db/migrate/20191204223857_change_total_records_to_total_work_entries.rb +6 -0
  110. data/db/migrate/20191212155530_change_entry_last_error.rb +19 -0
  111. data/db/migrate/20200108194557_add_validate_only_to_bulkrax_importers.rb +5 -0
  112. data/db/migrate/20200301232856_add_status_to_importers.rb +9 -0
  113. data/db/migrate/20200312190638_remove_foreign_key_from_bulkrax_entries.rb +5 -0
  114. data/db/migrate/20200326235838_add_status_to_exporters.rb +7 -0
  115. data/db/migrate/20200601204556_add_invalid_record_to_importer_run.rb +5 -0
  116. data/db/migrate/20200818055819_create_bulkrax_statuses.rb +18 -0
  117. data/db/migrate/20200819054016_move_to_statuses.rb +30 -0
  118. data/db/migrate/20201106014204_add_date_filter_and_status_to_bulkrax_exporters.rb +7 -0
  119. data/db/migrate/20201117220007_add_workflow_status_to_bulkrax_exporter.rb +5 -0
  120. data/db/migrate/20210806044408_remove_unused_last_error.rb +7 -0
  121. data/db/migrate/20210806065737_increase_text_sizes.rb +12 -0
  122. data/lib/bulkrax.rb +161 -0
  123. data/lib/bulkrax/engine.rb +37 -0
  124. data/lib/bulkrax/version.rb +5 -0
  125. data/lib/generators/bulkrax/install_generator.rb +80 -0
  126. data/lib/generators/bulkrax/templates/README +3 -0
  127. data/lib/generators/bulkrax/templates/app/assets/images/bulkrax/removed.png +0 -0
  128. data/lib/generators/bulkrax/templates/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
  129. data/lib/generators/bulkrax/templates/bin/importer +140 -0
  130. data/lib/generators/bulkrax/templates/config/bulkrax_api.yml +84 -0
  131. data/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb +72 -0
  132. data/lib/tasks/bulkrax_tasks.rake +6 -0
  133. 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