hyrax 2.8.0 → 2.9.5

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +8 -8
  3. data/.gitignore +1 -0
  4. data/.regen +1 -1
  5. data/README.md +1 -1
  6. data/app/assets/javascripts/hyrax.js +1 -0
  7. data/app/assets/javascripts/hyrax/autocomplete.es6 +29 -0
  8. data/app/assets/javascripts/hyrax/editor.es6 +9 -10
  9. data/app/assets/javascripts/hyrax/skip_to_content.js +15 -0
  10. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +18 -7
  11. data/app/controllers/hyrax/file_sets_controller.rb +6 -1
  12. data/app/controllers/hyrax/users_controller.rb +1 -1
  13. data/app/helpers/hyrax/hyrax_helper_behavior.rb +1 -0
  14. data/app/helpers/hyrax/work_form_helper.rb +48 -0
  15. data/app/jobs/embargo_expiry_job.rb +15 -0
  16. data/app/jobs/iiif_manifest_cache_prewarm_job.rb +16 -0
  17. data/app/jobs/lease_expiry_job.rb +15 -0
  18. data/app/models/concerns/hyrax/ability.rb +1 -1
  19. data/app/models/concerns/hyrax/solr_document/characterization.rb +1 -1
  20. data/app/models/concerns/hyrax/solr_document/metadata.rb +1 -0
  21. data/app/models/concerns/hyrax/solr_document/ordered_members.rb +46 -0
  22. data/app/models/concerns/hyrax/solr_document_behavior.rb +10 -0
  23. data/app/presenters/hyrax/displays_image.rb +25 -21
  24. data/app/presenters/hyrax/iiif_manifest_presenter.rb +232 -0
  25. data/app/presenters/hyrax/member_presenter_factory.rb +1 -7
  26. data/app/services/hyrax/caching_iiif_manifest_builder.rb +53 -0
  27. data/app/services/hyrax/collection_types/permissions_service.rb +3 -3
  28. data/app/services/hyrax/collections/permissions_service.rb +1 -1
  29. data/app/services/hyrax/contextual_path.rb +1 -1
  30. data/app/services/hyrax/identifier/builder.rb +45 -0
  31. data/app/services/hyrax/identifier/dispatcher.rb +61 -0
  32. data/app/services/hyrax/identifier/registrar.rb +41 -0
  33. data/app/services/hyrax/manifest_builder_service.rb +88 -0
  34. data/app/services/hyrax/versioning_service.rb +9 -0
  35. data/app/views/hyrax/base/_form.html.erb +1 -1
  36. data/app/views/hyrax/base/_form_child_work_relationships.html.erb +1 -1
  37. data/app/views/hyrax/base/_form_progress.html.erb +4 -0
  38. data/app/views/hyrax/base/_form_visibility_error.html.erb +2 -0
  39. data/app/views/hyrax/base/_guts4form.html.erb +7 -1
  40. data/app/views/hyrax/base/_show_actions.html.erb +1 -1
  41. data/app/views/hyrax/batch_uploads/_form.html.erb +2 -2
  42. data/app/views/hyrax/dashboard/_sidebar.html.erb +1 -1
  43. data/config/features.rb +4 -0
  44. data/hyrax.gemspec +3 -2
  45. data/lib/generators/hyrax/templates/catalog_controller.rb +4 -0
  46. data/lib/generators/hyrax/templates/config/initializers/hyrax.rb +5 -0
  47. data/lib/generators/hyrax/templates/config/locales/hyrax.es.yml +1 -1
  48. data/lib/hyrax.rb +1 -0
  49. data/lib/hyrax/configuration.rb +23 -4
  50. data/lib/hyrax/engine.rb +1 -0
  51. data/lib/hyrax/specs/shared_specs.rb +1 -0
  52. data/lib/hyrax/specs/shared_specs/identifiers.rb +27 -0
  53. data/lib/hyrax/version.rb +1 -1
  54. data/template.rb +1 -1
  55. metadata +47 -8
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Identifier
4
+ ##
5
+ # Builds an identifier string.
6
+ #
7
+ # Implementations must accept a `prefix:` to `#initialize`, and a `hint:` to
8
+ # `#build`. Either or both may be used at the preference of the specific
9
+ # implementer or ignored entirely when `#build` is called.
10
+ #
11
+ # @example
12
+ # builder = Hyrax::Identifier::Builder.new(prefix: 'moomin')
13
+ # builder.build(hint: '1') # => "moomin/1"
14
+ class Builder
15
+ ##
16
+ # @!attribute prefix [rw]
17
+ # @return [String] the prefix to use when building identifiers
18
+ attr_accessor :prefix
19
+
20
+ ##
21
+ # @param prefix [String] the prefix to use when building identifiers
22
+ def initialize(prefix: 'pfx')
23
+ @prefix = prefix
24
+ end
25
+
26
+ ##
27
+ # @note this default builder requires a `hint` which it appends to the
28
+ # prefix to generate the identifier string.
29
+ #
30
+ # @param hint [#to_s] a string-able object which may be used by the builder
31
+ # to generate an identifier. Hints may be required by some builders, while
32
+ # others may ignore them to generate an identifier by other means.
33
+ #
34
+ # @return [String]
35
+ # @raise [ArgumentError] if an identifer can't be built from the provided
36
+ # hint.
37
+ def build(hint: nil)
38
+ raise(ArgumentError, "No hint provided to #{self.class}#build") if
39
+ hint.nil?
40
+
41
+ "#{prefix}/#{hint}"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Identifier
4
+ class Dispatcher
5
+ ##
6
+ # @!attribute [rw] registrar
7
+ # @return [Hyrax::Identifier::Registrar]
8
+ attr_accessor :registrar
9
+
10
+ ##
11
+ # @param registrar [Hyrax::Identifier::Registrar]
12
+ def initialize(registrar:)
13
+ @registrar = registrar
14
+ end
15
+
16
+ class << self
17
+ ##
18
+ # @param type [Symbol]
19
+ # @param registrar_opts [Hash]
20
+ # @option registrar_opts [Hyrax::Identifier::Builder] :builder
21
+ #
22
+ # @return [Hyrax::Identifier::Dispatcher] a dispatcher with an registrar for the
23
+ # given type
24
+ # @see IdentifierRegistrar.for
25
+ def for(type, **registrar_opts)
26
+ new(registrar: Hyrax::Identifier::Registrar.for(type, **registrar_opts))
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Assigns an identifier to the object.
32
+ #
33
+ # This involves two steps:
34
+ # - Registering the identifier with the registrar service via `registrar`.
35
+ # - Storing the new identifier on the object, in the provided `attribute`.
36
+ #
37
+ # @note the attribute for identifier storage must be multi-valued, and will
38
+ # be overwritten during assignment.
39
+ #
40
+ # @param attribute [Symbol] the attribute in which to store the identifier.
41
+ # This attribute will be overwritten during assignment.
42
+ # @param object [ActiveFedora::Base, Hyrax::Resource] the object to assign an identifier.
43
+ #
44
+ # @return [ActiveFedora::Base, Hyrax::Resource] object
45
+ def assign_for(object:, attribute: :identifier)
46
+ record = registrar.register!(object: object)
47
+ object.public_send("#{attribute}=".to_sym, [record.identifier])
48
+ object
49
+ end
50
+
51
+ ##
52
+ # Assigns an identifier and saves the object.
53
+ #
54
+ # @see #assign_for
55
+ def assign_for!(object:, attribute: :identifier)
56
+ assign_for(object: object, attribute: attribute).save!
57
+ object
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module Identifier
4
+ class Registrar
5
+ class << self
6
+ ##
7
+ # @param type [Symbol]
8
+ # @param opts [Hash]
9
+ # @option opts [Hyrax::Identifier::Builder] :builder
10
+ #
11
+ # @return [Hyrax::Identifier::Registrar] a registrar for the given type
12
+ def for(type, **opts)
13
+ return Hyrax.config.identifier_registrars[type].new(**opts) if Hyrax.config.identifier_registrars.include?(type)
14
+ raise ArgumentError, "Hyrax::Identifier::Registrar not found to handle #{type}"
15
+ end
16
+ end
17
+
18
+ ##
19
+ # @!attribute builder [rw]
20
+ # @return [Hyrax::Identifier::Builder]
21
+ attr_accessor :builder
22
+
23
+ ##
24
+ # @param builder [Hyrax::Identifier::Builder]
25
+ def initialize(builder:)
26
+ @builder = builder
27
+ end
28
+
29
+ ##
30
+ # @abstract
31
+ #
32
+ # @param object [#id]
33
+ #
34
+ # @return [#identifier]
35
+ # @raise [NotImplementedError] when the method is abstract
36
+ def register!(*)
37
+ raise NotImplementedError
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ ##
5
+ # A class responsible for converting a Hyrax::Work like thing into a IIIF
6
+ # manifest.
7
+ #
8
+ # @see !{.as_json}
9
+ class ManifestBuilderService
10
+ ##
11
+ # @api public
12
+ #
13
+ # @param presenter [Hyrax::WorkShowPresenter] the work presenter from which
14
+ # we'll build a manifest.
15
+ # @param iiif_manifest_factory [Class] a class that initializes with presenter
16
+ # object and returns an object that responds to `#to_h`
17
+ #
18
+ # @note While the :presenter may be a Hyrax::WorkShowPresenter it is likely
19
+ # defined by Hyrax::WorksControllerBehavior.show_presenter
20
+ #
21
+ # @return [Hash] a Ruby hash representation of a IIIF manifest document
22
+ #
23
+ # @see Hyrax::WorksControllerBehavior
24
+ def self.manifest_for(presenter:, iiif_manifest_factory: ::IIIFManifest::ManifestFactory)
25
+ new(iiif_manifest_factory: iiif_manifest_factory)
26
+ .manifest_for(presenter: presenter)
27
+ end
28
+
29
+ ##
30
+ # @!attribute [r] manifest_factory
31
+ # @return [#to_h]
32
+ attr_reader :manifest_factory
33
+
34
+ ##
35
+ # @api public
36
+ #
37
+ # @param iiif_manifest_factory [Class] a class that initializes with presenter
38
+ # object and returns an object that responds to `#to_h`
39
+ def initialize(iiif_manifest_factory: ::IIIFManifest::ManifestFactory)
40
+ @manifest_factory = iiif_manifest_factory
41
+ end
42
+
43
+ ##
44
+ # @api public
45
+ #
46
+ # @param presenter [Hyrax::WorkShowPresenter]
47
+ #
48
+ # @return [Hash] a Ruby hash representation of a IIIF manifest document
49
+ def manifest_for(presenter:)
50
+ sanitized_manifest(presenter: presenter)
51
+ end
52
+
53
+ private
54
+
55
+ ##
56
+ # @api private
57
+ # @param presenter [Hyrax::WorkShowPresenter]
58
+ def sanitized_manifest(presenter:)
59
+ # ::IIIFManifest::ManifestBuilder#to_h returns a
60
+ # IIIFManifest::ManifestBuilder::IIIFManifest, not a Hash.
61
+ # to get a Hash, we have to call its #to_json, then parse.
62
+ #
63
+ # wild times. maybe there's a better way to do this with the
64
+ # ManifestFactory interface?
65
+ manifest = manifest_factory.new(presenter).to_h
66
+ hash = JSON.parse(manifest.to_json)
67
+
68
+ hash['label'] = sanitize_value(hash['label']) if hash.key?('label')
69
+ hash['description'] = Array(hash['description'])&.collect { |elem| sanitize_value(elem) } if hash.key?('description')
70
+
71
+ hash['sequences']&.each do |sequence|
72
+ sequence['canvases']&.each do |canvas|
73
+ canvas['label'] = sanitize_value(canvas['label'])
74
+ end
75
+ end
76
+
77
+ hash
78
+ end
79
+
80
+ ##
81
+ # @api private
82
+ # @param [#to_s] text
83
+ # @return [String] a sanitized verison of `text`
84
+ def sanitize_value(text)
85
+ Loofah.fragment(text.to_s).scrub!(:prune).to_s
86
+ end
87
+ end
88
+ end
@@ -22,5 +22,14 @@ module Hyrax
22
22
  return if version.nil?
23
23
  VersionCommitter.create(version_id: version.uri, committer_login: user_key)
24
24
  end
25
+
26
+ # @param [ActiveFedora::File | Hyrax::FileMetadata] content
27
+ def self.versioned_file_id(file)
28
+ versions = file.versions.all
29
+
30
+ return ActiveFedora::Base.uri_to_id(versions.last.uri) if versions.present?
31
+
32
+ file.id
33
+ end
25
34
  end
26
35
  end
@@ -19,7 +19,7 @@
19
19
  <p class="switch-upload-type">To create a separate work for each of the files, go to <%= link_to "Batch upload", hyrax.new_batch_upload_path %></p>
20
20
  <% end %>
21
21
  <% end %>
22
- <%= render 'hyrax/base/guts4form', f: f %>
22
+ <%= render 'hyrax/base/guts4form', f: f, tabs: form_tabs_for(form: f.object) %>
23
23
  <% end %>
24
24
 
25
25
  <script type="text/javascript">
@@ -24,7 +24,7 @@ HTML Properties:
24
24
  </div>
25
25
  <div class="message has-warning hidden"></div>
26
26
  <div style="margin-top: 10px">
27
- <%= link_to t('.attach_new_work'), polymorphic_path([main_app, :new, :hyrax, :parent, curation_concern.model_name.singular], parent_id: curation_concern.id), target: "_blank", class: 'btn btn-primary' %>
27
+ <%= link_to t('.attach_new_work'), polymorphic_path([main_app, :new, :hyrax, :parent, curation_concern.model_name.singular.to_sym], parent_id: curation_concern.id), target: "_blank", class: 'btn btn-primary' %>
28
28
  </div>
29
29
  <table class="table table-striped">
30
30
  <caption><%= t('.caption') %></caption>
@@ -26,6 +26,10 @@
26
26
  <%= f.input :on_behalf_of, collection: current_user.can_make_deposits_for.map(&:user_key), prompt: "Yourself" %>
27
27
  </div>
28
28
  <% end %>
29
+
30
+ <% form_progress_sections_for(form: f.object).each do |section| %>
31
+ <%= render "form_progress_#{section}", f: f %>
32
+ <% end %>
29
33
  </div>
30
34
  <div class="panel-footer text-center">
31
35
  <% if ::Flipflop.show_deposit_agreement? %>
@@ -1,3 +1,5 @@
1
1
  <%= f.full_error(:visibility) %>
2
2
  <%= f.full_error(:embargo_release_date) %>
3
3
  <%= f.full_error(:visibility_after_embargo) %>
4
+ <%= f.full_error(:lease_expiration_date) %>
5
+ <%= f.full_error(:visibility_after_lease) %>
@@ -1,5 +1,11 @@
1
1
  <% # we will yield to content_for for each tab, e.g. :files_tab %>
2
- <% tabs ||= %w[metadata files relationships] # default tab order %>
2
+ <%# Not passing tabs local param to this partial is deprecated and the tabs param will be required in Hyrax 3.0 %>
3
+ <% unless defined?(tabs) %>
4
+ <% Deprecation.warn(self, "Passing the tabs local param to the _guts4form partial will be required in Hyrax 3.0. " \
5
+ "Consider removing overriding view partials and customizing the tab list " \
6
+ "by overriding the new form_tabs_for(form:) helper.") %>
7
+ <% tabs = form_tabs_for(form: f.object) # default tab order %>
8
+ <% end %>
3
9
  <div class="row">
4
10
  <div class="col-xs-12 col-sm-8">
5
11
  <div class="panel panel-default tabs" role="main">
@@ -15,7 +15,7 @@
15
15
  <ul class="dropdown-menu">
16
16
  <% presenter.valid_child_concerns.each do |concern| %>
17
17
  <li>
18
- <%= link_to "Attach #{concern.human_readable_type}", polymorphic_path([main_app, :new, :hyrax, :parent, concern.model_name.singular], parent_id: presenter.id) %>
18
+ <%= link_to "Attach #{concern.human_readable_type}", polymorphic_path([main_app, :new, :hyrax, :parent, concern.model_name.singular.to_sym], parent_id: presenter.id) %>
19
19
  </li>
20
20
  <% end %>
21
21
  </ul>
@@ -7,10 +7,10 @@
7
7
  <% provide :files_tab do %>
8
8
  <p class="instructions"><%= t("hyrax.batch_uploads.files.instructions") %></p>
9
9
  <p class="switch-upload-type"><%= t("hyrax.batch_uploads.files.upload_type_instructions") %>
10
- <%= link_to t("hyrax.batch_uploads.files.button_label"), [main_app, :new, Hyrax.primary_work_type.model_name.singular_route_key] %>
10
+ <%= link_to t("hyrax.batch_uploads.files.button_label"), [main_app, :new, Hyrax.primary_work_type.model_name.singular_route_key.to_sym] %>
11
11
  </p>
12
12
  <% end %>
13
- <%= render 'hyrax/base/guts4form', f: f, tabs: %w[files metadata relationships] %>
13
+ <%= render 'hyrax/base/guts4form', f: f, tabs: form_tabs_for(form: f.object) %>
14
14
  <%= f.hidden_field :payload_concern, value: @form.payload_concern %>
15
15
  <% end %>
16
16
 
@@ -1,6 +1,6 @@
1
1
  <% menu = Hyrax::MenuPresenter.new(self) %>
2
2
  <div class="sidebar-toggle"><span class="fa fa-chevron-circle-right"></span></div>
3
- <nav>
3
+ <nav aria-label="sidebar-nav">
4
4
  <ul class="nav nav-pills nav-stacked">
5
5
  <li>
6
6
  <div class="profile">
data/config/features.rb CHANGED
@@ -42,4 +42,8 @@ Flipflop.configure do
42
42
  feature :hide_users_list,
43
43
  default: true,
44
44
  description: "Do not show users list unless user has authenticated."
45
+
46
+ feature :cache_work_iiif_manifest,
47
+ default: false,
48
+ description: "Use Rails.cache to cache the JSON document for IIIF manifests"
45
49
  end
data/hyrax.gemspec CHANGED
@@ -39,6 +39,7 @@ SUMMARY
39
39
  spec.add_dependency 'browse-everything', '>= 0.16'
40
40
  spec.add_dependency 'carrierwave', '~> 1.0'
41
41
  spec.add_dependency 'clipboard-rails', '~> 1.5'
42
+ spec.add_dependency 'draper', '~> 4.0'
42
43
  spec.add_dependency 'dry-equalizer', '~> 0.2'
43
44
  spec.add_dependency 'dry-struct', '>= 0.1', '< 2.0'
44
45
  spec.add_dependency 'dry-transaction', '~> 0.11'
@@ -49,7 +50,7 @@ SUMMARY
49
50
  spec.add_dependency 'font-awesome-rails', '~> 4.2'
50
51
  spec.add_dependency 'hydra-derivatives', '~> 3.3'
51
52
  spec.add_dependency 'hydra-editor', '>= 3.3', '< 6.0'
52
- spec.add_dependency 'hydra-head', '>= 10.6.1'
53
+ spec.add_dependency 'hydra-head', '>= 10.6.1', '< 12'
53
54
  spec.add_dependency 'hydra-works', '>= 0.16', '< 2.0'
54
55
  spec.add_dependency 'iiif_manifest', '>= 0.3', '< 0.6'
55
56
  spec.add_dependency 'jquery-datatables-rails', '~> 3.4'
@@ -67,7 +68,7 @@ SUMMARY
67
68
  spec.add_dependency 'posix-spawn'
68
69
  spec.add_dependency 'power_converter', '~> 0.1', '>= 0.1.2'
69
70
  spec.add_dependency 'pul_uv_rails', '~> 2.0'
70
- spec.add_dependency 'qa', '~> 2.0' # questioning_authority
71
+ spec.add_dependency 'qa', '>= 2.0', '< 6.0' # questioning_authority
71
72
  spec.add_dependency 'rails_autolink', '~> 1.1'
72
73
  spec.add_dependency 'rdf-rdfxml' # controlled vocabulary importer
73
74
  spec.add_dependency 'rdf-vocab', '< 3.1.5'
@@ -20,6 +20,10 @@ class CatalogController < ApplicationController
20
20
  config.view.gallery.partials = [:index_header, :index]
21
21
  config.view.slideshow.partials = [:index]
22
22
 
23
+ # Because too many times on Samvera tech people raise a problem regarding a failed query to SOLR.
24
+ # Often, it's because they inadvertantly exceeded the character limit of a GET request.
25
+ config.http_method = :post
26
+
23
27
  ## Default parameters to send to solr for all search-like requests. See also SolrHelper#solr_search_params
24
28
  config.default_solr_params = {
25
29
  qt: "search",
@@ -266,6 +266,11 @@ Hyrax.config do |config|
266
266
  # mount point.
267
267
  #
268
268
  # config.whitelisted_ingest_dirs = []
269
+
270
+ ## Remote identifiers configuration
271
+ # Add registrar implementations by uncommenting and adding to the hash below.
272
+ # See app/services/hyrax/identifier/registrar.rb for the registrar interface
273
+ # config.identifier_registrars = {}
269
274
  end
270
275
 
271
276
  Date::DATE_FORMATS[:standard] = "%m/%d/%Y"
@@ -51,7 +51,7 @@ es:
51
51
  suffix: "@example.org"
52
52
  footer:
53
53
  copyright_html: "<strong>Copyright &copy; 2018 Samvera</strong> bajo licencia de Apache, Version 2.0"
54
- service_html: Un servicio de <a href="http://samvera.org/" class="navbar-link" target="_blank">Samvera/a>.
54
+ service_html: Un servicio de <a href="http://samvera.org/" class="navbar-link" target="_blank">Samvera</a>.
55
55
  institution_name: institución
56
56
  institution_name_full: El nombre de la institución
57
57
  product_name: Hyrax
data/lib/hyrax.rb CHANGED
@@ -8,6 +8,7 @@ require 'font-awesome-rails'
8
8
  require 'tinymce-rails'
9
9
  require 'blacklight'
10
10
  require 'blacklight/gallery'
11
+ require 'iiif_manifest'
11
12
  require 'noid-rails'
12
13
  require 'hydra/head'
13
14
  require 'hydra-editor'
@@ -431,6 +431,16 @@ module Hyrax
431
431
  end
432
432
  attr_writer :iiif_metadata_fields
433
433
 
434
+ # Duration in which we should cache the generated IIIF manifest.
435
+ # Default is 30 days (in seconds).
436
+ #
437
+ # @return [Integer] number of seconds
438
+ # @see https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html#method-i-fetch
439
+ def iiif_manifest_cache_duration
440
+ @iiif_manifest_cache_duration ||= 30.days.to_i
441
+ end
442
+ attr_writer :iiif_manifest_cache_duration
443
+
434
444
  # Should a button with "Share my work" show on the front page to users who are not logged in?
435
445
  attr_writer :display_share_button_when_not_logged_in
436
446
  def display_share_button_when_not_logged_in?
@@ -469,10 +479,14 @@ module Hyrax
469
479
  attr_writer :translate_uri_to_id
470
480
 
471
481
  def translate_uri_to_id
472
- @translate_uri_to_id ||= lambda do |uri|
473
- baseparts = 2 + [(::Noid::Rails.config.template.gsub(/\.[rsz]/, '').length.to_f / 2).ceil, 4].min
474
- uri.to_s.sub("#{ActiveFedora.fedora.host}#{ActiveFedora.fedora.base_path}", '').split('/', baseparts).last
475
- end
482
+ @translate_uri_to_id ||=
483
+ begin
484
+ baseparts = 2 + [(::Noid::Rails.config.template.gsub(/\.[rsz]/, '').length.to_f / 2).ceil, 4].min
485
+
486
+ lambda do |uri|
487
+ uri.to_s.split(ActiveFedora.fedora.base_path).last.split('/', baseparts).last
488
+ end
489
+ end
476
490
  end
477
491
 
478
492
  attr_writer :translate_id_to_uri
@@ -514,6 +528,11 @@ module Hyrax
514
528
  ->(id:, extent:) { Samvera::NestingIndexer.reindex_relationships(id: id, extent: extent) }
515
529
  end
516
530
 
531
+ attr_writer :identifier_registrars
532
+ def identifier_registrars
533
+ @identifier_registrars ||= {}
534
+ end
535
+
517
536
  private
518
537
 
519
538
  # @param [Symbol, #to_s] model_name - symbol representing the model