bulkrax 1.0.2 → 2.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/controllers/bulkrax/exporters_controller.rb +12 -4
  4. data/app/controllers/bulkrax/importers_controller.rb +22 -17
  5. data/app/factories/bulkrax/object_factory.rb +36 -59
  6. data/app/jobs/bulkrax/create_relationships_job.rb +187 -0
  7. data/app/jobs/bulkrax/delete_work_job.rb +6 -2
  8. data/app/jobs/bulkrax/export_work_job.rb +3 -1
  9. data/app/jobs/bulkrax/exporter_job.rb +1 -0
  10. data/app/jobs/bulkrax/{import_work_collection_job.rb → import_collection_job.rb} +2 -2
  11. data/app/jobs/bulkrax/importer_job.rb +16 -1
  12. data/app/matchers/bulkrax/application_matcher.rb +5 -5
  13. data/app/models/bulkrax/csv_collection_entry.rb +8 -6
  14. data/app/models/bulkrax/csv_entry.rb +124 -66
  15. data/app/models/bulkrax/entry.rb +19 -8
  16. data/app/models/bulkrax/exporter.rb +12 -5
  17. data/app/models/bulkrax/importer.rb +12 -5
  18. data/app/models/bulkrax/oai_entry.rb +5 -1
  19. data/app/models/bulkrax/rdf_entry.rb +16 -7
  20. data/app/models/bulkrax/xml_entry.rb +4 -0
  21. data/app/models/concerns/bulkrax/export_behavior.rb +2 -2
  22. data/app/models/concerns/bulkrax/has_matchers.rb +44 -13
  23. data/app/models/concerns/bulkrax/import_behavior.rb +35 -5
  24. data/app/models/concerns/bulkrax/importer_exporter_behavior.rb +19 -0
  25. data/app/models/concerns/bulkrax/status_info.rb +4 -4
  26. data/app/parsers/bulkrax/application_parser.rb +59 -84
  27. data/app/parsers/bulkrax/bagit_parser.rb +12 -3
  28. data/app/parsers/bulkrax/csv_parser.rb +117 -63
  29. data/app/parsers/bulkrax/oai_dc_parser.rb +5 -2
  30. data/app/parsers/bulkrax/xml_parser.rb +5 -0
  31. data/app/views/bulkrax/exporters/_form.html.erb +1 -1
  32. data/app/views/bulkrax/exporters/show.html.erb +2 -1
  33. data/app/views/bulkrax/importers/index.html.erb +15 -17
  34. data/app/views/bulkrax/importers/show.html.erb +6 -2
  35. data/config/locales/bulkrax.en.yml +1 -0
  36. data/db/migrate/20190731114016_change_importer_and_exporter_to_polymorphic.rb +5 -1
  37. data/db/migrate/20211004170708_change_bulkrax_statuses_error_message_column_type_to_text.rb +5 -0
  38. data/db/migrate/20211203195233_rename_children_counters_to_relationships.rb +6 -0
  39. data/lib/bulkrax/engine.rb +1 -1
  40. data/lib/bulkrax/version.rb +1 -1
  41. data/lib/bulkrax.rb +9 -17
  42. data/lib/generators/bulkrax/templates/bin/importer +17 -11
  43. data/lib/generators/bulkrax/templates/config/bulkrax_api.yml +3 -1
  44. data/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb +7 -12
  45. metadata +6 -4
  46. data/app/jobs/bulkrax/child_relationships_job.rb +0 -128
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2cad330885f5f4d2dce25c989ebc7552b49b2212b68434d5def942fff61ad23a
4
- data.tar.gz: 2b1e71044b26ff6ab9b25822ee969a7e886e095bbd2147b9b240406634e8f832
3
+ metadata.gz: 56a6005830d733023f9455ebb9e0565081dacbfbf1a36ebad290d594d74499f4
4
+ data.tar.gz: dbfe501d7c62a47091e23fbc9b7b7e8aff3147f88c999eb9d55bc6e6bf27ae05
5
5
  SHA512:
6
- metadata.gz: 18e70353c64be13d686ff1da35d01c932422da49f9fd0ebf08470fdc0edc9333a9b51633b158cfaedf020ae5e3830574eb192a69ba498dff81e92847de4235f7
7
- data.tar.gz: 6502ec16bc63aefed3c678ec062d3bc923c159260ac39278e692f4628bfe05acd675d49193b92c9e42f2ab50976d48c3d608d77f8db1d45774a664fd74b09bce
6
+ metadata.gz: 1054dbc43420ad3fba9f75e8c88cec4b795c55a1dc5416b5b37a7a75eff994f629aa7740dda54f635be406ec2b7c4f913b1de7426cbd1a378573cd42d526e5c7
7
+ data.tar.gz: 6eb81924d7587caddcea1ec4b7d71b41324336a85ea2ae6662662028ccc3c5b92f93b5aa02fe7d0a9c19cb5e16db560ff95cfc74b85f475bae0c425ecb96824c
data/README.md CHANGED
@@ -16,7 +16,7 @@ gem 'bulkrax', git: 'https://github.com/samvera-labs/bulkrax.git'
16
16
 
17
17
  And then execute:
18
18
  ```bash
19
- $ bundle update
19
+ $ bundle install
20
20
  $ rails generate bulkrax:install
21
21
  ```
22
22
 
@@ -51,9 +51,12 @@ module Bulkrax
51
51
  if @exporter.save
52
52
  if params[:commit] == 'Create and Export'
53
53
  # Use perform now for export
54
- Bulkrax::ExporterJob.perform_now(@exporter.id)
54
+ Bulkrax::ExporterJob.perform_later(@exporter.id)
55
+ message = 'Exporter was successfully created. A download link will appear once it completes.'
56
+ else
57
+ message = 'Exporter was successfully created.'
55
58
  end
56
- redirect_to exporters_path, notice: 'Exporter was successfully created.'
59
+ redirect_to exporters_path, notice: message
57
60
  else
58
61
  render :new
59
62
  end
@@ -63,8 +66,13 @@ module Bulkrax
63
66
  def update
64
67
  field_mapping_params
65
68
  if @exporter.update(exporter_params)
66
- Bulkrax::ExporterJob.perform_now(@exporter.id) if params[:commit] == 'Update and Re-Export All Items'
67
- redirect_to exporters_path, notice: 'Exporter was successfully updated.'
69
+ if params[:commit] == 'Update and Re-Export All Items'
70
+ Bulkrax::ExporterJob.perform_later(@exporter.id)
71
+ message = 'Exporter was successfully updated. A download link will appear once it completes.'
72
+ else
73
+ 'Exporter was successfully updated.'
74
+ end
75
+ redirect_to exporters_path, notice: message
68
76
  else
69
77
  render :edit
70
78
  end
@@ -113,23 +113,9 @@ module Bulkrax
113
113
  if @importer.update(importer_params)
114
114
  files_for_import(file, cloud_files) unless file.nil? && cloud_files.nil?
115
115
  # do not perform the import
116
- if params[:commit] == 'Update Importer'
117
- # do nothing
118
- # OAI-only - selective re-harvest
119
- elsif params[:commit] == 'Update and Harvest Updated Items'
120
- Bulkrax::ImporterJob.perform_later(@importer.id, true)
121
- elsif params[:commit] == 'Update Metadata and Files'
122
- @importer.parser_fields['update_files'] = true
123
- @importer.save
124
- Bulkrax::ImporterJob.perform_later(@importer.id)
125
- # Perform a full metadata and files re-import; do the same for an OAI re-harvest of all items
126
- elsif params[:commit] == ('Update and Replace Files' || 'Update and Re-Harvest All Items')
127
- @importer.parser_fields['replace_files'] = true
128
- @importer.save
129
- Bulkrax::ImporterJob.perform_later(@importer.id)
130
- # In all other cases, perform a metadata-only re-import
131
- else
132
- Bulkrax::ImporterJob.perform_later(@importer.id)
116
+ unless params[:commit] == 'Update Importer'
117
+ set_files_parser_fields
118
+ Bulkrax::ImporterJob.send(@importer.parser.perform_method, @importer.id, update_harvest)
133
119
  end
134
120
  if api_request?
135
121
  json_response('updated', :ok, 'Importer was successfully updated.')
@@ -310,6 +296,25 @@ module Bulkrax
310
296
  redirect_to path, notice: message
311
297
  end
312
298
  end
299
+
300
+ # update methods (for commit deciphering)
301
+ def update_harvest
302
+ # OAI-only - selective re-harvest
303
+ params[:commit] == 'Update and Harvest Updated Items'
304
+ end
305
+
306
+ def set_files_parser_fields
307
+ if params[:commit] == 'Update Metadata and Files'
308
+ @importer.parser_fields['update_files'] = true
309
+ elsif params[:commit] == ('Update and Replace Files' || 'Update and Re-Harvest All Items')
310
+ @importer.parser_fields['replace_files'] = true
311
+ elsif params[:commit] == 'Update and Harvest Updated Items'
312
+ return
313
+ else
314
+ @importer.parser_fields['metadata_only'] = true
315
+ end
316
+ @importer.save
317
+ end
313
318
  end
314
319
  # rubocop:enable Metrics/ClassLength
315
320
  end
@@ -5,15 +5,20 @@ module Bulkrax
5
5
  extend ActiveModel::Callbacks
6
6
  include Bulkrax::FileFactory
7
7
  define_model_callbacks :save, :create
8
- attr_reader :attributes, :object, :source_identifier_value, :klass, :replace_files, :update_files, :work_identifier
8
+ attr_reader :attributes, :object, :source_identifier_value, :klass, :replace_files, :update_files, :work_identifier, :collection_field_mapping
9
9
 
10
10
  # rubocop:disable Metrics/ParameterLists
11
- def initialize(attributes:, source_identifier_value:, work_identifier:, replace_files: false, user: nil, klass: nil, update_files: false)
11
+ def initialize(attributes:, source_identifier_value:, work_identifier:, collection_field_mapping:, replace_files: false, user: nil, klass: nil, update_files: false)
12
+ ActiveSupport::Deprecation.warn(
13
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
14
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
15
+ )
12
16
  @attributes = ActiveSupport::HashWithIndifferentAccess.new(attributes)
13
17
  @replace_files = replace_files
14
18
  @update_files = update_files
15
19
  @user = user || User.batch_user
16
20
  @work_identifier = work_identifier
21
+ @collection_field_mapping = collection_field_mapping
17
22
  @source_identifier_value = source_identifier_value
18
23
  @klass = klass || Bulkrax.default_work_type.constantize
19
24
  end
@@ -41,6 +46,7 @@ module Bulkrax
41
46
  self.run
42
47
  # Create the error exception if the object is not validly saved for some reason
43
48
  raise ActiveFedora::RecordInvalid, object if !object.persisted? || object.changed?
49
+ object
44
50
  end
45
51
 
46
52
  def update
@@ -54,7 +60,7 @@ module Bulkrax
54
60
  end
55
61
 
56
62
  def find
57
- return find_by_id if attributes[:id]
63
+ return find_by_id if attributes[:id].present?
58
64
  return search_by_identifier if attributes[work_identifier].present?
59
65
  end
60
66
 
@@ -121,52 +127,33 @@ module Bulkrax
121
127
  end
122
128
 
123
129
  def create_collection(attrs)
130
+ ActiveSupport::Deprecation.warn(
131
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
132
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
133
+ )
124
134
  attrs = collection_type(attrs)
125
- object.members = members
126
- object.member_of_collections = member_of_collections
135
+ persist_collection_memberships(parent: object, child: find_collection(attributes[:child_collection_id])) if attributes[:child_collection_id].present?
136
+ persist_collection_memberships(parent: find_collection(attributes[collection_field_mapping]), child: object) if attributes[collection_field_mapping].present?
127
137
  object.attributes = attrs
128
138
  object.apply_depositor_metadata(@user)
129
139
  object.save!
130
140
  end
131
141
 
132
142
  def update_collection(attrs)
133
- object.members = members
134
- object.member_of_collections = member_of_collections
143
+ ActiveSupport::Deprecation.warn(
144
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
145
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
146
+ )
147
+ persist_collection_memberships(parent: object, child: find_collection(attributes[:child_collection_id])) if attributes[:child_collection_id].present?
148
+ persist_collection_memberships(parent: find_collection(attributes[collection_field_mapping]), child: object) if attributes[collection_field_mapping].present?
135
149
  object.attributes = attrs
136
150
  object.save!
137
151
  end
138
152
 
139
- # Collections don't respond to member_of_collections_attributes or member_of_collection_ids=
140
- # or member_ids=
141
- # Add them directly with members / member_of_collections
142
- # collection should be in the form { id: collection_id }
143
- # and collections [{ id: collection_id }]
144
- # member_ids comes from
145
- # @todo - consider performance implications although we wouldn't expect a Collection to be a member of many Collections
146
- def members
147
- ms = object.members.to_a
148
- [:children].each do |atat|
149
- next if attributes[atat].blank?
150
- ms.concat(
151
- Array.wrap(
152
- find_collection(attributes[atat])
153
- )
154
- )
155
- end
156
- ms.flatten.compact.uniq
157
- end
158
-
159
- def member_of_collections
160
- ms = object.member_of_collection_ids.to_a.map { |id| find_collection(id) }
161
- [:collection, :collections].each do |atat|
162
- next if attributes[atat].blank?
163
- ms.concat(
164
- Array.wrap(
165
- find_collection(attributes[atat])
166
- )
167
- )
168
- end
169
- ms.flatten.compact.uniq
153
+ # Add child to parent's #member_collections
154
+ # Add parent to child's #member_of_collections
155
+ def persist_collection_memberships(parent:, child:)
156
+ ::Hyrax::Collections::NestedCollectionPersistenceService.persist_nested_collection_for(parent: parent, child: child)
170
157
  end
171
158
 
172
159
  def find_collection(id)
@@ -192,32 +179,22 @@ module Bulkrax
192
179
  # which is used by Hyrax::Actors::AddAsMemberOfCollectionsActor
193
180
  def create_attributes
194
181
  return transform_attributes if klass == Collection
195
- if attributes[:collection].present?
196
- transform_attributes.except(:collection).merge(member_of_collections_attributes: { 0 => { id: collection.id } })
197
- elsif attributes[:collections].present?
198
- collection_ids = attributes[:collections].each.with_index.each_with_object({}) do |(element, index), ids|
199
- ids[index] = { id: element }
200
- end
201
- transform_attributes.except(:collections).merge(member_of_collections_attributes: collection_ids)
202
- else
203
- transform_attributes
204
- end
182
+ ActiveSupport::Deprecation.warn(
183
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
184
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
185
+ )
186
+ transform_attributes.except(:collections, :collection, collection_field_mapping)
205
187
  end
206
188
 
207
189
  # Strip out the :collection key, and add the member_of_collection_ids,
208
190
  # which is used by Hyrax::Actors::AddAsMemberOfCollectionsActor
209
191
  def attribute_update
210
192
  return transform_attributes.except(:id) if klass == Collection
211
- if attributes[:collection].present?
212
- transform_attributes.except(:id).except(:collection).merge(member_of_collections_attributes: { "0" => { id: collection.id } })
213
- elsif attributes[:collections].present?
214
- collection_ids = attributes[:collections].each.with_index.each_with_object({}) do |(element, index), ids|
215
- ids[index.to_s] = element
216
- end
217
- transform_attributes.except(:id).except(:collections).merge(member_of_collections_attributes: collection_ids)
218
- else
219
- transform_attributes.except(:id)
220
- end
193
+ ActiveSupport::Deprecation.warn(
194
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
195
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
196
+ )
197
+ transform_attributes.except(:id, :collections, :collection, collection_field_mapping)
221
198
  end
222
199
 
223
200
  # Override if we need to map the attributes from the parser in
@@ -230,7 +207,7 @@ module Bulkrax
230
207
 
231
208
  # Regardless of what the Parser gives us, these are the properties we are prepared to accept.
232
209
  def permitted_attributes
233
- klass.properties.keys.map(&:to_sym) + %i[id edit_users edit_groups read_groups visibility work_members_attributes admin_set_id]
210
+ klass.properties.keys.map(&:to_sym) + %i[id edit_users edit_groups read_groups visibility work_members_attributes admin_set_id member_of_collections_attributes]
234
211
  end
235
212
  end
236
213
  end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bulkrax
4
+ # Responsible for creating parent-child relationships between Works and Collections.
5
+ #
6
+ # Handles three kinds of relationships:
7
+ # - Work to Collection
8
+ # - Collection to Collection
9
+ # - Work to Work
10
+ #
11
+ # These can be established from either side of the relationship (i.e. from parent to child or from child to parent).
12
+ # This job only creates one relationship at a time. If a record needs multiple parents or children or both, individual
13
+ # jobs should be run for each of those relationships.
14
+ #
15
+ # NOTE: In the context of this job, "record" is used to generically refer
16
+ # to either an instance of a Work or an instance of a Collection.
17
+ # NOTE: In the context of this job, "identifier" is used to generically refer
18
+ # to either a record's ID or an Bulkrax::Entry's source_identifier.
19
+ class CreateRelationshipsJob < ApplicationJob
20
+ queue_as :import
21
+
22
+ attr_accessor :base_entry, :child_record, :parent_record, :importer_run
23
+
24
+ # @param entry_identifier [String] source_identifier of the base Bulkrax::Entry the job was triggered from (see #build_for_importer)
25
+ # @param parent_identifier [String] Work/Collection ID or Bulkrax::Entry source_identifier
26
+ # @param child_identifier [String] Work/Collection ID or Bulkrax::Entry source_identifier
27
+ # @param importer_run [Bulkrax::ImporterRun] current importer run (needed to properly update counters)
28
+ #
29
+ # The entry_identifier is used to lookup the @base_entry for the job (a.k.a. the entry the job was called from).
30
+ # The @base_entry defines the context of the relationship (e.g. "this entry (@base_entry) should have a parent").
31
+ # Whether the @base_entry is the parent or the child in the relationship is determined by the presence of a
32
+ # parent_identifier or child_identifier param. For example, if a parent_identifier is passed, we know @base_entry
33
+ # is the child in the relationship, and vice versa if a child_identifier is passed.
34
+ def perform(entry_identifier:, parent_identifier: nil, child_identifier: nil, importer_run:)
35
+ @base_entry = Entry.find_by(identifier: entry_identifier)
36
+ @importer_run = importer_run
37
+ if parent_identifier.present?
38
+ @child_record = find_record(entry_identifier)
39
+ @parent_record = find_record(parent_identifier)
40
+ elsif child_identifier.present?
41
+ @parent_record = find_record(entry_identifier)
42
+ @child_record = find_record(child_identifier)
43
+ else
44
+ raise ::StandardError, %("#{entry_identifier}" needs either a child or a parent to create a relationship)
45
+ end
46
+
47
+ if @child_record.blank? || @parent_record.blank?
48
+ reschedule(
49
+ entry_identifier: entry_identifier,
50
+ parent_identifier: parent_identifier,
51
+ child_identifier: child_identifier,
52
+ importer_run: importer_run
53
+ )
54
+ return false # stop current job from continuing to run after rescheduling
55
+ end
56
+
57
+ create_relationship
58
+ rescue ::StandardError => e
59
+ base_entry.status_info(e)
60
+ importer_run.increment!(:failed_relationships) # rubocop:disable Rails/SkipsModelValidations
61
+ end
62
+
63
+ private
64
+
65
+ def create_relationship
66
+ if parent_record.is_a?(::Collection) && child_record.is_a?(::Collection)
67
+ collection_parent_collection_child
68
+ elsif parent_record.is_a?(::Collection) && curation_concern?(child_record)
69
+ collection_parent_work_child
70
+ elsif curation_concern?(parent_record) && child_record.is_a?(::Collection)
71
+ raise ::StandardError, 'a Collection may not be assigned as a child of a Work'
72
+ else
73
+ work_parent_work_child
74
+ end
75
+ end
76
+
77
+ # This method allows us to create relationships with preexisting records (by their ID) OR
78
+ # with records that are concurrently being imported (by their Bulkrax::Entry source_identifier).
79
+ #
80
+ # @param identifier [String] Work/Collection ID or Bulkrax::Entry source_identifier
81
+ # @return [Work, Collection, nil] Work or Collection if found, otherwise nil
82
+ def find_record(identifier)
83
+ record = Entry.find_by(identifier: identifier)
84
+ record ||= ::Collection.where(id: identifier).first
85
+ if record.blank?
86
+ available_work_types.each do |work_type|
87
+ record ||= work_type.where(id: identifier).first
88
+ end
89
+ end
90
+ record = record.factory.find if record.is_a?(Entry)
91
+
92
+ record
93
+ end
94
+
95
+ # Check if the record is a Work
96
+ def curation_concern?(record)
97
+ available_work_types.include?(record.class)
98
+ end
99
+
100
+ # @return [Array<Class>] list of work type classes
101
+ def available_work_types
102
+ # If running in a Hyku app, do not reference disabled work types
103
+ @available_work_types ||= if defined?(::Hyku)
104
+ ::Site.instance.available_works.map(&:constantize)
105
+ else
106
+ ::Hyrax.config.curation_concerns
107
+ end
108
+ end
109
+
110
+ def user
111
+ @user ||= importer_run.importer.user
112
+ end
113
+
114
+ # Work-Collection membership is added to the child as member_of_collection_ids
115
+ # This is adding the reverse relationship, from the child to the parent
116
+ def collection_parent_work_child
117
+ ActiveSupport::Deprecation.warn(
118
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
119
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
120
+ )
121
+ attrs = { id: child_record.id, member_of_collections_attributes: { 0 => { id: parent_record.id } } }
122
+ ObjectFactory.new(
123
+ attributes: attrs,
124
+ source_identifier_value: nil, # sending the :id in the attrs means the factory doesn't need a :source_identifier_value
125
+ work_identifier: base_entry.parser.work_identifier,
126
+ collection_field_mapping: base_entry.parser.collection_field_mapping,
127
+ replace_files: false,
128
+ user: user,
129
+ klass: child_record.class
130
+ ).run
131
+ # TODO: add counters for :processed_parents and :failed_parents
132
+ importer_run.increment!(:processed_relationships) # rubocop:disable Rails/SkipsModelValidations
133
+ end
134
+
135
+ # Collection-Collection membership is added to the as member_ids
136
+ def collection_parent_collection_child
137
+ ActiveSupport::Deprecation.warn(
138
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
139
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
140
+ )
141
+ attrs = { id: parent_record.id, child_collection_id: child_record.id }
142
+ ObjectFactory.new(
143
+ attributes: attrs,
144
+ source_identifier_value: nil, # sending the :id in the attrs means the factory doesn't need a :source_identifier_value
145
+ work_identifier: base_entry.parser.work_identifier,
146
+ collection_field_mapping: base_entry.parser.collection_field_mapping,
147
+ replace_files: false,
148
+ user: user,
149
+ klass: parent_record.class
150
+ ).run
151
+ # TODO: add counters for :processed_parents and :failed_parents
152
+ importer_run.increment!(:processed_relationships) # rubocop:disable Rails/SkipsModelValidations
153
+ end
154
+
155
+ # Work-Work membership is added to the parent as member_ids
156
+ def work_parent_work_child
157
+ ActiveSupport::Deprecation.warn(
158
+ 'Creating Collections using the collection_field_mapping will no longer be supported as of Bulkrax version 3.0.' \
159
+ ' Please configure Bulkrax to use related_parents_field_mapping and related_children_field_mapping instead.'
160
+ )
161
+ attrs = {
162
+ id: parent_record.id,
163
+ work_members_attributes: { 0 => { id: child_record.id } }
164
+ }
165
+ ObjectFactory.new(
166
+ attributes: attrs,
167
+ source_identifier_value: nil, # sending the :id in the attrs means the factory doesn't need a :source_identifier_value
168
+ work_identifier: base_entry.parser.work_identifier,
169
+ collection_field_mapping: base_entry.parser.collection_field_mapping,
170
+ replace_files: false,
171
+ user: user,
172
+ klass: parent_record.class
173
+ ).run
174
+ # TODO: add counters for :processed_parents and :failed_parents
175
+ importer_run.increment!(:processed_relationships) # rubocop:disable Rails/SkipsModelValidations
176
+ end
177
+
178
+ def reschedule(entry_identifier:, parent_identifier:, child_identifier:, importer_run:)
179
+ CreateRelationshipsJob.set(wait: 10.minutes).perform_later(
180
+ entry_identifier: entry_identifier,
181
+ parent_identifier: parent_identifier,
182
+ child_identifier: child_identifier,
183
+ importer_run: importer_run
184
+ )
185
+ end
186
+ end
187
+ end
@@ -8,8 +8,12 @@ module Bulkrax
8
8
  def perform(entry, importer_run)
9
9
  work = entry.factory.find
10
10
  work&.delete
11
- importer_run.increment!(:deleted_records)
12
- importer_run.decrement!(:enqueued_records)
11
+ ImporterRun.find(importer_run.id).increment!(:deleted_records)
12
+ ImporterRun.find(importer_run.id).decrement!(:enqueued_records)
13
+ entry.save!
14
+ entry.importer.current_run = ImporterRun.find(importer_run.id)
15
+ entry.importer.record_status
16
+ entry.status_info("Deleted", ImporterRun.find(importer_run.id))
13
17
  end
14
18
  # rubocop:enable Rails/SkipsModelValidations
15
19
  end
@@ -26,12 +26,14 @@ module Bulkrax
26
26
  # rubocop:enable Rails/SkipsModelValidations
27
27
  end
28
28
  exporter_run = ExporterRun.find(args[1])
29
- return if exporter_run.enqueued_records.positive?
29
+ return entry if exporter_run.enqueued_records.positive?
30
30
  if exporter_run.failed_records.positive?
31
31
  exporter_run.exporter.status_info('Complete (with failures)')
32
32
  else
33
33
  exporter_run.exporter.status_info('Complete')
34
34
  end
35
+
36
+ return entry
35
37
  end
36
38
  end
37
39
  end
@@ -8,6 +8,7 @@ module Bulkrax
8
8
  exporter = Exporter.find(exporter_id)
9
9
  exporter.export
10
10
  exporter.write
11
+ exporter.save
11
12
  true
12
13
  end
13
14
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bulkrax
4
- class ImportWorkCollectionJob < ApplicationJob
4
+ class ImportCollectionJob < ApplicationJob
5
5
  queue_as :import
6
6
 
7
7
  # rubocop:disable Rails/SkipsModelValidations
@@ -28,7 +28,7 @@ module Bulkrax
28
28
  collection = entry.factory.find
29
29
  permission_template = Hyrax::PermissionTemplate.find_or_create_by!(source_id: collection.id)
30
30
 
31
- Hyrax::PermissionTemplateAccess.create!(
31
+ Hyrax::PermissionTemplateAccess.find_or_create_by!(
32
32
  permission_template_id: permission_template.id,
33
33
  agent_id: user.user_key,
34
34
  agent_type: 'user',
@@ -6,17 +6,32 @@ module Bulkrax
6
6
 
7
7
  def perform(importer_id, only_updates_since_last_import = false)
8
8
  importer = Importer.find(importer_id)
9
+
9
10
  importer.current_run
11
+ unzip_imported_file(importer.parser)
10
12
  import(importer, only_updates_since_last_import)
13
+ update_current_run_counters(importer)
11
14
  schedule(importer) if importer.schedulable?
12
15
  end
13
16
 
14
17
  def import(importer, only_updates_since_last_import)
15
18
  importer.only_updates = only_updates_since_last_import || false
16
19
  return unless importer.valid_import?
20
+
17
21
  importer.import_collections
18
22
  importer.import_works
19
- importer.create_parent_child_relationships unless importer.validate_only
23
+ end
24
+
25
+ def unzip_imported_file(parser)
26
+ return unless parser.file? && parser.zip?
27
+
28
+ parser.unzip(parser.parser_fields['import_file_path'])
29
+ end
30
+
31
+ def update_current_run_counters(importer)
32
+ importer.current_run.total_work_entries = importer.limit || importer.parser.works_total
33
+ importer.current_run.total_collection_entries = importer.parser.collections_total
34
+ importer.current_run.save!
20
35
  end
21
36
 
22
37
  def schedule(importer)
@@ -20,9 +20,9 @@ module Bulkrax
20
20
  return unless content.send(self.if[0], Regexp.new(self.if[1]))
21
21
  end
22
22
 
23
- @result = content.to_s.gsub(/\s/, ' ') # remove any line feeds and tabs
24
- @result.strip!
25
- process_split
23
+ # @result will evaluate to an empty string for nil content values
24
+ @result = content.to_s.gsub(/\s/, ' ').strip # remove any line feeds and tabs
25
+ process_split if @result.present?
26
26
  @result = @result[0] if @result.is_a?(Array) && @result.size == 1
27
27
  process_parse
28
28
  return @result
@@ -66,14 +66,14 @@ module Bulkrax
66
66
  end
67
67
 
68
68
  def parse_subject(src)
69
- string = src.to_s.strip.downcase
69
+ string = src.strip.downcase
70
70
  return if string.blank?
71
71
 
72
72
  string.slice(0, 1).capitalize + string.slice(1..-1)
73
73
  end
74
74
 
75
75
  def parse_types(src)
76
- src.to_s.strip.titleize
76
+ src.strip.titleize
77
77
  end
78
78
 
79
79
  # Allow for mapping a model field to the work type or collection
@@ -6,14 +6,16 @@ module Bulkrax
6
6
  Collection
7
7
  end
8
8
 
9
- def build_metadata
10
- self.parsed_metadata = self.raw_metadata
11
- add_local
12
- return self.parsed_metadata
9
+ # Use identifier set by CsvParser#unique_collection_identifier, which falls back
10
+ # on the Collection's first title if record[source_identifier] is not present
11
+ def add_identifier
12
+ self.parsed_metadata[work_identifier] = self.identifier
13
13
  end
14
14
 
15
- def collections_created?
16
- true
15
+ def add_collection_type_gid
16
+ return if self.parsed_metadata['collection_type_gid'].present?
17
+
18
+ self.parsed_metadata['collection_type_gid'] = ::Hyrax::CollectionType.find_or_create_default_collection_type.gid
17
19
  end
18
20
  end
19
21
  end