bulkrax 9.5.0 → 10.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +49 -0
  3. data/app/controllers/bulkrax/application_controller.rb +83 -0
  4. data/app/controllers/bulkrax/entries_controller.rb +16 -13
  5. data/app/controllers/bulkrax/exporters_controller.rb +21 -25
  6. data/app/controllers/bulkrax/guided_imports_controller.rb +4 -8
  7. data/app/controllers/bulkrax/importers_controller.rb +26 -29
  8. data/app/controllers/concerns/bulkrax/datatables_behavior.rb +18 -12
  9. data/app/controllers/concerns/bulkrax/importer_file_handler.rb +1 -1
  10. data/app/factories/bulkrax/object_factory.rb +2 -2
  11. data/app/factories/bulkrax/valkyrie_object_factory.rb +29 -17
  12. data/app/helpers/bulkrax/validation_helper.rb +1 -1
  13. data/app/jobs/bulkrax/create_relationships_job.rb +1 -1
  14. data/app/jobs/bulkrax/import_collection_job.rb +9 -2
  15. data/app/matchers/bulkrax/application_matcher.rb +5 -2
  16. data/app/models/bulkrax/csv_entry.rb +1 -1
  17. data/app/models/bulkrax/current.rb +7 -0
  18. data/app/models/bulkrax/export_scope.rb +21 -0
  19. data/app/models/bulkrax/exporter.rb +2 -2
  20. data/app/models/bulkrax/importer.rb +1 -1
  21. data/app/models/concerns/bulkrax/ability_behavior.rb +139 -0
  22. data/app/models/concerns/bulkrax/has_matchers.rb +15 -2
  23. data/app/models/concerns/bulkrax/import_behavior.rb +3 -3
  24. data/app/parsers/bulkrax/csv_parser.rb +13 -12
  25. data/app/parsers/bulkrax/oai_dc_parser.rb +1 -1
  26. data/app/parsers/bulkrax/parser_export_record_set.rb +26 -8
  27. data/app/parsers/concerns/bulkrax/csv_parser/csv_template_generation.rb +1 -1
  28. data/app/parsers/concerns/bulkrax/csv_parser/csv_validation.rb +1 -2
  29. data/app/parsers/concerns/bulkrax/csv_parser/csv_validation_helpers.rb +18 -1
  30. data/app/parsers/concerns/bulkrax/csv_parser/csv_validation_hierarchy.rb +2 -2
  31. data/app/search_builders/bulkrax/export_search_builder.rb +9 -0
  32. data/app/services/bulkrax/csv_template/column_builder.rb +2 -2
  33. data/app/services/bulkrax/csv_template/mapping_manager.rb +9 -7
  34. data/app/services/bulkrax/csv_template/schema_analyzer.rb +1 -5
  35. data/lib/bulkrax/engine.rb +1 -1
  36. data/lib/bulkrax/version.rb +1 -1
  37. data/lib/bulkrax.rb +76 -10
  38. data/lib/generators/bulkrax/install_generator.rb +22 -10
  39. data/lib/generators/bulkrax/templates/config/initializers/bulkrax.rb +1 -1
  40. metadata +33 -13
  41. data/lib/wings/custom_queries/find_by_source_identifier.rb +0 -41
@@ -35,16 +35,18 @@ module Bulkrax
35
35
 
36
36
  # Returns the column names that target a given object name via the
37
37
  # `object:` field-mapping pattern. The template generator uses this to
38
- # emit the per-child columns (e.g. redirect_path, redirect_canonical,
39
- # redirect_sequence) instead of the bare property name (redirects).
40
- # Numbering is intentionally omitted — the template shows the column
41
- # shape once; CSV rows can repeat the column with numeric suffixes
42
- # (e.g. redirect_path_1, redirect_path_2) at import time.
38
+ # emit the per-child columns (e.g. redirect_path, redirect_display_url)
39
+ # instead of the bare property name (redirects). Numbering is
40
+ # intentionally omitted — the template shows the column shape once;
41
+ # CSV rows can repeat the column with numeric suffixes (e.g.
42
+ # redirect_path_1, redirect_path_2) at import time.
43
+ # An import accepts every `from:` alias, but offering them all here would
44
+ # put two columns for the same field on the template.
43
45
  def object_columns_for(object_name)
44
46
  @mappings
45
47
  .select { |_k, v| v.is_a?(Hash) && v["object"] == object_name }
46
- .values
47
- .flat_map { |v| Array(v["from"]) }
48
+ .keys
49
+ .map { |key| key_to_mapped_column(key) }
48
50
  .uniq
49
51
  end
50
52
 
@@ -36,11 +36,7 @@ module Bulkrax
36
36
  def load_schema
37
37
  return nil unless @klass.respond_to?(:schema)
38
38
 
39
- if @admin_set_id.present? && defined?(Hyrax) && Hyrax.respond_to?(:schema_for)
40
- Hyrax.schema_for(klass: @klass, admin_set_id: @admin_set_id)
41
- else
42
- @klass.new.singleton_class.schema || @klass.schema
43
- end
39
+ Bulkrax::ValkyrieObjectFactory.cached_schema_for(klass: @klass, admin_set_id: @admin_set_id)
44
40
  rescue StandardError
45
41
  nil
46
42
  end
@@ -26,7 +26,7 @@ module Bulkrax
26
26
  config.after_initialize do
27
27
  # We want to ensure that Bulkrax is earlier in the lookup for view_paths than Hyrax. That is
28
28
  # we favor view in Bulkrax over those in Hyrax.
29
- if defined?(Hyrax)
29
+ if Bulkrax.hyrax_loaded?
30
30
  my_engine_root = Bulkrax::Engine.root.to_s
31
31
  hyrax_engine_root = Hyrax::Engine.root.to_s
32
32
  paths = ActionController::Base.view_paths.collect(&:to_s)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bulkrax
4
- VERSION = '9.5.0'
4
+ VERSION = '10.0.0'
5
5
  end
data/lib/bulkrax.rb CHANGED
@@ -6,6 +6,7 @@ require 'active_support/all'
6
6
 
7
7
  require 'coderay'
8
8
  require 'csv'
9
+ require 'deprecation'
9
10
  require 'denormalize_fields'
10
11
  require 'erb'
11
12
  require 'iso8601'
@@ -15,8 +16,6 @@ require 'nokogiri'
15
16
  require 'ostruct'
16
17
  require 'zip'
17
18
 
18
- require 'wings/custom_queries/find_by_source_identifier'
19
-
20
19
  def conditional_require(gem_name)
21
20
  require gem_name
22
21
  rescue LoadError
@@ -31,6 +30,10 @@ module Bulkrax
31
30
  extend self # rubocop:disable Style/ModuleFunction
32
31
  extend Forwardable
33
32
 
33
+ def hyrax_loaded?
34
+ defined?(::Hyrax::Engine) ? true : false
35
+ end
36
+
34
37
  ##
35
38
  # @api public
36
39
  class Configuration
@@ -85,7 +88,7 @@ module Bulkrax
85
88
  def solr_key_for_member_file_ids
86
89
  return @solr_key_for_member_file_ids if @solr_key_for_member_file_ids.present?
87
90
 
88
- return "member_ids_ssim" if defined?(Hyrax)
91
+ return "member_ids_ssim" if Bulkrax.hyrax_loaded?
89
92
 
90
93
  "#{file_model_class.name.to_s.underscore}_ids_ssim"
91
94
  end
@@ -110,10 +113,13 @@ module Bulkrax
110
113
  end
111
114
 
112
115
  def collection_model_class
113
- @collection_model_class ||= Collection if defined?(::Hyrax)
116
+ @collection_model_class ||= Collection if Bulkrax.hyrax_loaded?
114
117
  end
115
118
 
116
- attr_writer :collection_model_class
119
+ def collection_model_class=(klass)
120
+ @collection_model_names = nil
121
+ @collection_model_class = klass
122
+ end
117
123
 
118
124
  def collection_model_internal_resource
119
125
  # WARN: Using #try on :internal_resource can yield unexpected results.
@@ -129,11 +135,30 @@ module Bulkrax
129
135
  instance.respond_to?(:internal_resource) ? instance.internal_resource : collection_model_class.to_s
130
136
  end
131
137
 
138
+ # A sheet written against either side of a Wings pair has to import, since
139
+ # both names resolve to the same object.
140
+ def collection_model_names
141
+ @collection_model_names ||=
142
+ model_names_for(collection_model_class, twin: curation_concern_twin_for(collection_model_class))
143
+ end
144
+
145
+ attr_writer :collection_model_names
146
+
147
+ def collection_model_name?(model_name)
148
+ name = model_name.to_s.strip
149
+ return false if name.empty?
150
+
151
+ collection_model_names.any? { |known| name.casecmp(known).zero? }
152
+ end
153
+
132
154
  def file_model_class
133
- @file_model_class ||= defined?(::Hyrax) ? ::FileSet : File
155
+ @file_model_class ||= Bulkrax.hyrax_loaded? ? ::FileSet : File
134
156
  end
135
157
 
136
- attr_writer :file_model_class
158
+ def file_model_class=(klass)
159
+ @file_model_names = nil
160
+ @file_model_class = klass
161
+ end
137
162
 
138
163
  def file_model_internal_resource
139
164
  # WARN: Using #try on :internal_resource can yield unexpected results.
@@ -149,8 +174,43 @@ module Bulkrax
149
174
  instance.respond_to?(:internal_resource) ? instance.internal_resource : file_model_class.to_s
150
175
  end
151
176
 
177
+ # As #collection_model_names, for file set rows. Wings pairs file sets by
178
+ # namespace rather than a `Resource` suffix: `Wings::ModelRegistry` maps
179
+ # both `FileSet` and `Hyrax::FileSet` onto the same object, so whichever
180
+ # one is configured, the other is its twin.
181
+ def file_model_names
182
+ @file_model_names ||= model_names_for(file_model_class, twin: file_set_twin_for(file_model_class))
183
+ end
184
+
185
+ attr_writer :file_model_names
186
+
187
+ def file_model_name?(model_name)
188
+ name = model_name.to_s.strip
189
+ return false if name.empty?
190
+
191
+ file_model_names.any? { |known| name.casecmp(known).zero? }
192
+ end
193
+
194
+ # Constantizing is what distinguishes a Wings install from a name that
195
+ # merely looks like one.
196
+ def model_names_for(klass, twin:)
197
+ names = [klass.to_s]
198
+ names << twin.to_s if twin.present? && twin.to_s.safe_constantize
199
+ names.uniq
200
+ end
201
+
202
+ def curation_concern_twin_for(klass)
203
+ name = klass.to_s
204
+ name.end_with?('Resource') ? name.delete_suffix('Resource') : "#{name}Resource"
205
+ end
206
+
207
+ def file_set_twin_for(klass)
208
+ name = klass.to_s
209
+ name.start_with?('Hyrax::') ? name.delete_prefix('Hyrax::') : "Hyrax::#{name}"
210
+ end
211
+
152
212
  def curation_concerns
153
- @curation_concerns ||= defined?(::Hyrax) ? ::Hyrax.config.curation_concerns : []
213
+ @curation_concerns ||= Bulkrax.hyrax_loaded? ? ::Hyrax.config.curation_concerns : []
154
214
  end
155
215
 
156
216
  attr_writer :curation_concerns
@@ -176,7 +236,7 @@ module Bulkrax
176
236
  # @return [String, Proc]
177
237
  def ingest_queue_name
178
238
  return @ingest_queue_name if @ingest_queue_name.present?
179
- return Hyrax.config.ingest_queue_name if defined?(Hyrax)
239
+ return Hyrax.config.ingest_queue_name if Bulkrax.hyrax_loaded?
180
240
  :import
181
241
  end
182
242
 
@@ -224,6 +284,9 @@ module Bulkrax
224
284
  :collection_model_class,
225
285
  :collection_model_internal_resource,
226
286
  :collection_model_class=,
287
+ :collection_model_name?,
288
+ :collection_model_names,
289
+ :collection_model_names=,
227
290
  :curation_concerns,
228
291
  :curation_concerns=,
229
292
  :curation_concern_internal_resources,
@@ -240,6 +303,9 @@ module Bulkrax
240
303
  :file_model_class,
241
304
  :file_model_class=,
242
305
  :file_model_internal_resource,
306
+ :file_model_name?,
307
+ :file_model_names,
308
+ :file_model_names=,
243
309
  :fill_in_blank_source_identifiers,
244
310
  :fill_in_blank_source_identifiers=,
245
311
  :generated_metadata_mapping,
@@ -433,7 +499,7 @@ module Bulkrax
433
499
  end
434
500
 
435
501
  def fallback_user_for_importer_exporter_processing
436
- return User.batch_user if defined?(Hyrax) && User.respond_to?(:batch_user)
502
+ return User.batch_user if Bulkrax.hyrax_loaded? && User.respond_to?(:batch_user)
437
503
 
438
504
  raise "We have no fallback user available for Bulkrax.fallback_user_for_importer_exporter_processing"
439
505
  end
@@ -58,18 +58,30 @@ class Bulkrax::InstallGenerator < Rails::Generators::Base
58
58
  def add_ability
59
59
  file = 'app/models/ability.rb'
60
60
  file_text = File.read(file)
61
- import_line = 'def can_import_works?'
62
- export_line = 'def can_export_works?'
63
- unless file_text.include?(import_line)
64
- insert_into_file file, before: /^end/ do
65
- " def can_import_works?\n can_create_any_work?\n end"
66
- end
67
- end
61
+ include_line = 'include Bulkrax::AbilityBehavior'
68
62
 
69
63
  # rubocop:disable Style/GuardClause
70
- unless file_text.include?(export_line)
71
- insert_into_file file, before: /^end/ do
72
- " def can_export_works?\n can_create_any_work?\n end"
64
+ unless file_text.include?(include_line)
65
+ insert_into_file file, after: /include\s+\S+Ability[^\n]*\n/ do
66
+ " include Bulkrax::AbilityBehavior\n" \
67
+ " self.ability_logic += [:bulkrax_default_abilities]\n\n" \
68
+ " # Override Bulkrax::AbilityBehavior methods as needed, for example:\n" \
69
+ " #\n" \
70
+ " # def can_import_works?\n" \
71
+ " # can_create_any_work?\n" \
72
+ " # end\n" \
73
+ " #\n" \
74
+ " # def can_export_works?\n" \
75
+ " # can_create_any_work?\n" \
76
+ " # end\n" \
77
+ " #\n" \
78
+ " # def can_admin_importers?\n" \
79
+ " # current_user.admin?\n" \
80
+ " # end\n" \
81
+ " #\n" \
82
+ " # def can_admin_exporters?\n" \
83
+ " # current_user.admin?\n" \
84
+ " # end\n"
73
85
  end
74
86
  end
75
87
  # rubocop:enable Style/GuardClause
@@ -83,6 +83,6 @@ end
83
83
 
84
84
  # Sidebar for hyrax 3+ support
85
85
  # rubocop:disable Style/IfUnlessModifier
86
- if Object.const_defined?(:Hyrax) && ::Hyrax::DashboardController&.respond_to?(:sidebar_partials)
86
+ if Bulkrax.hyrax_loaded? && ::Hyrax::DashboardController&.respond_to?(:sidebar_partials)
87
87
  Hyrax::DashboardController.sidebar_partials[:repository_content] << "hyrax/dashboard/sidebar/bulkrax_sidebar_additions"
88
88
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulkrax
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.5.0
4
+ version: 10.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Kaufman
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-05-08 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -16,20 +15,20 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 5.1.6
18
+ version: '5.2'
20
19
  - - "<"
21
20
  - !ruby/object:Gem::Version
22
- version: 8.0.0
21
+ version: 8.2.0
23
22
  type: :runtime
24
23
  prerelease: false
25
24
  version_requirements: !ruby/object:Gem::Requirement
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- version: 5.1.6
28
+ version: '5.2'
30
29
  - - "<"
31
30
  - !ruby/object:Gem::Version
32
- version: 8.0.0
31
+ version: 8.2.0
33
32
  - !ruby/object:Gem::Dependency
34
33
  name: bagit
35
34
  requirement: !ruby/object:Gem::Requirement
@@ -72,6 +71,20 @@ dependencies:
72
71
  - - ">="
73
72
  - !ruby/object:Gem::Version
74
73
  version: '0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: deprecation
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.0'
81
+ type: :runtime
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.0'
75
88
  - !ruby/object:Gem::Dependency
76
89
  name: marcel
77
90
  requirement: !ruby/object:Gem::Requirement
@@ -262,16 +275,22 @@ dependencies:
262
275
  name: sqlite3
263
276
  requirement: !ruby/object:Gem::Requirement
264
277
  requirements:
265
- - - "~>"
278
+ - - ">="
266
279
  - !ruby/object:Gem::Version
267
280
  version: '1.4'
281
+ - - "<"
282
+ - !ruby/object:Gem::Version
283
+ version: '3'
268
284
  type: :development
269
285
  prerelease: false
270
286
  version_requirements: !ruby/object:Gem::Requirement
271
287
  requirements:
272
- - - "~>"
288
+ - - ">="
273
289
  - !ruby/object:Gem::Version
274
290
  version: '1.4'
291
+ - - "<"
292
+ - !ruby/object:Gem::Version
293
+ version: '3'
275
294
  - !ruby/object:Gem::Dependency
276
295
  name: simplecov
277
296
  requirement: !ruby/object:Gem::Requirement
@@ -401,7 +420,9 @@ files:
401
420
  - app/models/bulkrax/csv_collection_entry.rb
402
421
  - app/models/bulkrax/csv_entry.rb
403
422
  - app/models/bulkrax/csv_file_set_entry.rb
423
+ - app/models/bulkrax/current.rb
404
424
  - app/models/bulkrax/entry.rb
425
+ - app/models/bulkrax/export_scope.rb
405
426
  - app/models/bulkrax/exporter.rb
406
427
  - app/models/bulkrax/exporter_run.rb
407
428
  - app/models/bulkrax/import_failed.rb
@@ -417,6 +438,7 @@ files:
417
438
  - app/models/bulkrax/rdf_file_set_entry.rb
418
439
  - app/models/bulkrax/status.rb
419
440
  - app/models/bulkrax/xml_entry.rb
441
+ - app/models/concerns/bulkrax/ability_behavior.rb
420
442
  - app/models/concerns/bulkrax/dynamic_record_lookup.rb
421
443
  - app/models/concerns/bulkrax/errored_entries.rb
422
444
  - app/models/concerns/bulkrax/export_behavior.rb
@@ -438,6 +460,7 @@ files:
438
460
  - app/parsers/concerns/bulkrax/csv_parser/csv_validation.rb
439
461
  - app/parsers/concerns/bulkrax/csv_parser/csv_validation_helpers.rb
440
462
  - app/parsers/concerns/bulkrax/csv_parser/csv_validation_hierarchy.rb
463
+ - app/search_builders/bulkrax/export_search_builder.rb
441
464
  - app/services/bulkrax/csv_template/column_builder.rb
442
465
  - app/services/bulkrax/csv_template/column_descriptor.rb
443
466
  - app/services/bulkrax/csv_template/csv_builder.rb
@@ -564,12 +587,10 @@ files:
564
587
  - lib/generators/bulkrax/templates/config/initializers/bulkrax.rb
565
588
  - lib/tasks/bulkrax_tasks.rake
566
589
  - lib/tasks/reset.rake
567
- - lib/wings/custom_queries/find_by_source_identifier.rb
568
590
  homepage: https://github.com/samvera-labs/bulkrax
569
591
  licenses:
570
592
  - Apache-2.0
571
593
  metadata: {}
572
- post_install_message:
573
594
  rdoc_options: []
574
595
  require_paths:
575
596
  - lib
@@ -584,8 +605,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
584
605
  - !ruby/object:Gem::Version
585
606
  version: '0'
586
607
  requirements: []
587
- rubygems_version: 3.5.3
588
- signing_key:
608
+ rubygems_version: 4.0.22
589
609
  specification_version: 4
590
610
  summary: Import and export tool for Hyrax and Hyku
591
611
  test_files: []
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Wings
4
- module CustomQueries
5
- class FindBySourceIdentifier
6
- # Custom query override specific to Wings
7
-
8
- def self.queries
9
- [:find_by_property_value]
10
- end
11
-
12
- attr_reader :query_service
13
- delegate :resource_factory, to: :query_service
14
-
15
- def initialize(query_service:)
16
- @query_service = query_service
17
- end
18
-
19
- # rubocop:disable Lint/UnusedMethodArgument
20
- def find_by_property_value(property:, value:, search_field:, use_valkyrie: Hyrax.config.use_valkyrie?)
21
- # rubocop:enable Lint/UnusedMethodArgument
22
- # NOTE: This is using the Bulkrax::ObjectFactory (e.g. the one envisioned for ActiveFedora).
23
- # In doing this, we avoid the situation where Bulkrax::ValkyrieObjectFactory calls this custom query.
24
-
25
- # This is doing a solr search first, so we have to use the search_field instead of the property for "field"
26
- # If it cannot find the object in Solr, it falls back to an ActiveFedora search, if the object is an ActiveFedora object
27
- af_object = Bulkrax::ObjectFactory.search_by_property(
28
- value: value,
29
- klass: ActiveFedora::Base,
30
- field: search_field,
31
- name_field: property
32
- )
33
-
34
- return if af_object.blank?
35
- return af_object unless use_valkyrie
36
-
37
- resource_factory.to_resource(object: af_object)
38
- end
39
- end
40
- end
41
- end