bulkrax 1.0.0

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