bulkrax 1.0.2 → 2.0.0

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