hyrax 2.8.0 → 2.9.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +1 -1
- data/app/assets/javascripts/hyrax/autocomplete.es6 +29 -0
- data/app/assets/javascripts/hyrax/editor.es6 +9 -10
- data/app/controllers/concerns/hyrax/works_controller_behavior.rb +18 -7
- data/app/helpers/hyrax/hyrax_helper_behavior.rb +1 -0
- data/app/helpers/hyrax/work_form_helper.rb +48 -0
- data/app/jobs/iiif_manifest_cache_prewarm_job.rb +16 -0
- data/app/models/concerns/hyrax/solr_document/metadata.rb +1 -0
- data/app/models/concerns/hyrax/solr_document/ordered_members.rb +46 -0
- data/app/models/concerns/hyrax/solr_document_behavior.rb +10 -0
- data/app/presenters/hyrax/displays_image.rb +25 -21
- data/app/presenters/hyrax/iiif_manifest_presenter.rb +232 -0
- data/app/presenters/hyrax/member_presenter_factory.rb +1 -7
- data/app/services/hyrax/caching_iiif_manifest_builder.rb +53 -0
- data/app/services/hyrax/identifier/builder.rb +45 -0
- data/app/services/hyrax/identifier/dispatcher.rb +61 -0
- data/app/services/hyrax/identifier/registrar.rb +41 -0
- data/app/services/hyrax/manifest_builder_service.rb +88 -0
- data/app/services/hyrax/versioning_service.rb +9 -0
- data/app/views/hyrax/base/_form.html.erb +1 -1
- data/app/views/hyrax/base/_form_progress.html.erb +4 -0
- data/app/views/hyrax/base/_guts4form.html.erb +7 -1
- data/app/views/hyrax/batch_uploads/_form.html.erb +1 -1
- data/app/views/hyrax/dashboard/_sidebar.html.erb +1 -1
- data/config/features.rb +4 -0
- data/hyrax.gemspec +1 -0
- data/lib/generators/hyrax/templates/config/initializers/hyrax.rb +5 -0
- data/lib/hyrax.rb +1 -0
- data/lib/hyrax/configuration.rb +15 -0
- data/lib/hyrax/engine.rb +1 -0
- data/lib/hyrax/specs/shared_specs.rb +1 -0
- data/lib/hyrax/specs/shared_specs/identifiers.rb +27 -0
- data/lib/hyrax/version.rb +1 -1
- data/template.rb +1 -1
- metadata +26 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c050894909dcdbe63b34640d24f9f665e3818850cf2f4c5a0d92af23ae51cf62
|
4
|
+
data.tar.gz: 42a5a185ee2d26c9ab54d544a8261fc2bd24c01b99903092e5d54a9c5dcee054
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0fab1e2979598561c1f4afd61e2434c0af3529005c7f6394f9605d5c30e4e95df45a7c23cf665ac6ee647360a27ef286870a7456b8b57a0ec17e905f8d474af
|
7
|
+
data.tar.gz: 55d6ffdace586396f41b327dceca10da11eeedbcee3d0be0abeafa3635574425e79fa6b8dd0ba831870b9f6d464e0067da889d46e5318051d63f00a502cff892
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -158,7 +158,7 @@ NOTE: The steps need to be done in order to create a new Hyrax based app.
|
|
158
158
|
Generate a new Rails application using the template.
|
159
159
|
|
160
160
|
```
|
161
|
-
rails _5.2.4.3_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.
|
161
|
+
rails _5.2.4.3_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.9.0/template.rb
|
162
162
|
```
|
163
163
|
|
164
164
|
Generating a new Rails application using Hyrax's template above takes cares of a number of steps for you, including:
|
@@ -10,6 +10,34 @@ export default class Autocomplete {
|
|
10
10
|
* @param {string} url - The url for the autocompete search endpoint
|
11
11
|
*/
|
12
12
|
setup (element, fieldName, url) {
|
13
|
+
if(element.data('autocomplete-type') && element.data('autocomplete-type').length > 0) {
|
14
|
+
this.byDataAttribute(element, url)
|
15
|
+
} else {
|
16
|
+
this.byFieldName(element, fieldName, url)
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
byDataAttribute(element, url) {
|
21
|
+
let type = element.data('autocomplete-type')
|
22
|
+
let exlude = element.data('exclude-work')
|
23
|
+
if(type === 'resource' && exclude.length > 0) {
|
24
|
+
new Resource(
|
25
|
+
element,
|
26
|
+
url,
|
27
|
+
{ excluding: exclude }
|
28
|
+
)
|
29
|
+
} else if(type === 'resource' ) {
|
30
|
+
new Resource(
|
31
|
+
element,
|
32
|
+
url)
|
33
|
+
} else if(type === 'linked') {
|
34
|
+
new LinkedData(element, url)
|
35
|
+
} else {
|
36
|
+
new Default(element, url)
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
byFieldName(element, fieldName, url) {
|
13
41
|
switch (fieldName) {
|
14
42
|
case 'work':
|
15
43
|
new Resource(
|
@@ -30,4 +58,5 @@ export default class Autocomplete {
|
|
30
58
|
break
|
31
59
|
}
|
32
60
|
}
|
61
|
+
|
33
62
|
}
|
@@ -53,17 +53,16 @@ export default class {
|
|
53
53
|
$('[data-autocomplete]').each((function() {
|
54
54
|
var elem = $(this)
|
55
55
|
autocomplete.setup(elem, elem.data('autocomplete'), elem.data('autocompleteUrl'))
|
56
|
+
elem.parents('.multi_value.form-group').manage_fields({
|
57
|
+
add: function(e, element) {
|
58
|
+
var elem = $(element)
|
59
|
+
// Don't mark an added element as readonly even if previous element was
|
60
|
+
// Enable before initializing, as otherwise LinkedData fields remain disabled
|
61
|
+
elem.attr('readonly', false)
|
62
|
+
autocomplete.setup(elem, elem.data('autocomplete'), elem.data('autocompleteUrl'))
|
63
|
+
}
|
64
|
+
})
|
56
65
|
}))
|
57
|
-
|
58
|
-
$('.multi_value.form-group').manage_fields({
|
59
|
-
add: function(e, element) {
|
60
|
-
var elem = $(element)
|
61
|
-
// Don't mark an added element as readonly even if previous element was
|
62
|
-
// Enable before initializing, as otherwise LinkedData fields remain disabled
|
63
|
-
elem.attr('readonly', false)
|
64
|
-
autocomplete.setup(elem, elem.data('autocomplete'), elem.data('autocompleteUrl'))
|
65
|
-
}
|
66
|
-
})
|
67
66
|
}
|
68
67
|
|
69
68
|
// initialize any controlled vocabulary widgets
|
@@ -10,10 +10,11 @@ module Hyrax
|
|
10
10
|
with_themed_layout :decide_layout
|
11
11
|
copy_blacklight_config_from(::CatalogController)
|
12
12
|
|
13
|
-
class_attribute :_curation_concern_type, :show_presenter, :work_form_service, :search_builder_class
|
13
|
+
class_attribute :_curation_concern_type, :show_presenter, :work_form_service, :search_builder_class, :iiif_manifest_builder
|
14
14
|
self.show_presenter = Hyrax::WorkShowPresenter
|
15
15
|
self.work_form_service = Hyrax::WorkFormService
|
16
16
|
self.search_builder_class = WorkSearchBuilder
|
17
|
+
self.iiif_manifest_builder = (Flipflop.cache_work_iiif_manifest? ? Hyrax::CachingIiifManifestBuilder.new : Hyrax::ManifestBuilderService.new)
|
17
18
|
attr_accessor :curation_concern
|
18
19
|
helper_method :curation_concern, :contextual_path
|
19
20
|
|
@@ -127,14 +128,28 @@ module Hyrax
|
|
127
128
|
|
128
129
|
def manifest
|
129
130
|
headers['Access-Control-Allow-Origin'] = '*'
|
131
|
+
|
132
|
+
json = iiif_manifest_builder.manifest_for(presenter: iiif_manifest_presenter)
|
133
|
+
|
130
134
|
respond_to do |wants|
|
131
|
-
wants.json { render json:
|
132
|
-
wants.html { render json:
|
135
|
+
wants.json { render json: json }
|
136
|
+
wants.html { render json: json }
|
133
137
|
end
|
134
138
|
end
|
135
139
|
|
136
140
|
private
|
137
141
|
|
142
|
+
def iiif_manifest_builder
|
143
|
+
self.class.iiif_manifest_builder
|
144
|
+
end
|
145
|
+
|
146
|
+
def iiif_manifest_presenter
|
147
|
+
IiifManifestPresenter.new(curation_concern_from_search_results).tap do |p|
|
148
|
+
p.hostname = request.hostname
|
149
|
+
p.ability = current_ability
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
138
153
|
def user_collections
|
139
154
|
collections_service.search_results(:deposit)
|
140
155
|
end
|
@@ -157,10 +172,6 @@ module Hyrax
|
|
157
172
|
@form = work_form_service.build(curation_concern, current_ability, self)
|
158
173
|
end
|
159
174
|
|
160
|
-
def manifest_builder
|
161
|
-
::IIIFManifest::ManifestFactory.new(presenter)
|
162
|
-
end
|
163
|
-
|
164
175
|
def actor
|
165
176
|
@actor ||= Hyrax::CurationConcern.actor
|
166
177
|
end
|
@@ -12,6 +12,7 @@ module Hyrax
|
|
12
12
|
include Hyrax::ChartsHelper
|
13
13
|
include Hyrax::DashboardHelperBehavior
|
14
14
|
include Hyrax::IiifHelper
|
15
|
+
include Hyrax::WorkFormHelper
|
15
16
|
|
16
17
|
# Which translations are available for the user to select
|
17
18
|
# @return [Hash<String,String>] locale abbreviations as keys and flags as values
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module WorkFormHelper
|
4
|
+
##
|
5
|
+
# This helper allows downstream applications and engines to add/remove/reorder the tabs to be
|
6
|
+
# rendered on the work form.
|
7
|
+
#
|
8
|
+
# @example with additional tabs
|
9
|
+
# Override this helper and ensure that it loads after Hyrax's helpers.
|
10
|
+
# module WorksHelper
|
11
|
+
# def form_tabs_for(form:)
|
12
|
+
# super + ["my_new_tab"]
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
# Add the new section partial at app/views/hyrax/base/_form_my_new_tab.html.erb
|
16
|
+
#
|
17
|
+
# @todo The share tab isn't included because it wasn't in guts4form. guts4form should be
|
18
|
+
# cleaned up so share is treated the same as other tabs and can be included below.
|
19
|
+
# @param form [Hyrax::Forms::WorkForm]
|
20
|
+
# @return [Array<String>] the list of names of tabs to be rendered in the form
|
21
|
+
def form_tabs_for(form:)
|
22
|
+
if form.instance_of? Hyrax::Forms::BatchUploadForm
|
23
|
+
%w[files metadata relationships]
|
24
|
+
else
|
25
|
+
%w[metadata files relationships]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# This helper allows downstream applications and engines to add additional sections to be
|
31
|
+
# rendered after the visibility section in the Save Work panel on the work form.
|
32
|
+
#
|
33
|
+
# @example with additional sections
|
34
|
+
# Override this helper and ensure that it loads after Hyrax's helpers.
|
35
|
+
# module WorksHelper
|
36
|
+
# def form_progress_sections_for(*)
|
37
|
+
# super + ["my_new_section"]
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
# Add the new section partial at app/views/hyrax/base/_form_progress_my_new_section.html.erb
|
41
|
+
#
|
42
|
+
# @param form [Hyrax::Forms::WorkForm]
|
43
|
+
# @return [Array<String>] the list of names of sections to be rendered in the form_progress panel
|
44
|
+
def form_progress_sections_for(*)
|
45
|
+
[]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class IiifManifestCachePrewarmJob < Hyrax::ApplicationJob
|
4
|
+
##
|
5
|
+
# @param work [ActiveFedora::Base]
|
6
|
+
def perform(work)
|
7
|
+
presenter = Hyrax::IiifManifestPresenter.new(work)
|
8
|
+
manifest_builder.manifest_for(presenter: presenter)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def manifest_builder
|
14
|
+
Hyrax::CachingIiifManifestBuilder.new
|
15
|
+
end
|
16
|
+
end
|
@@ -54,6 +54,7 @@ module Hyrax
|
|
54
54
|
attribute :read_groups, Solr::Array, ::Ability.read_group_field
|
55
55
|
attribute :collection_ids, Solr::Array, 'collection_ids_tesim'
|
56
56
|
attribute :admin_set, Solr::Array, solr_name('admin_set')
|
57
|
+
attribute :member_ids, Solr::Array, "member_ids_ssim"
|
57
58
|
attribute :member_of_collection_ids, Solr::Array, solr_name('member_of_collection_ids', :symbol)
|
58
59
|
attribute :description, Solr::Array, solr_name('description')
|
59
60
|
attribute :title, Solr::Array, solr_name('title')
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module SolrDocument
|
4
|
+
##
|
5
|
+
# Decorates an object responding to `#id` with an `#ordered_member_ids` method.
|
6
|
+
#
|
7
|
+
# @note this decorator is intended for use with data representations other
|
8
|
+
# than the core model objects, as an alternative to a direct query of the
|
9
|
+
# canonical database. for example, it can be used with `SolrDocument` to
|
10
|
+
# quickly retrieve member order in a way that is compatible with the
|
11
|
+
# fast access required in Blacklight's search contexts.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# base_document = SolrDocument.new(my_work.to_solr)
|
15
|
+
# solr_document = Hyrax::SolrDocument::OrderedMembers.decorate(base_document)
|
16
|
+
#
|
17
|
+
# solr_document.ordered_member_ids # => ['abc', '123']
|
18
|
+
#
|
19
|
+
class OrderedMembers < Draper::Decorator
|
20
|
+
delegate_all
|
21
|
+
|
22
|
+
##
|
23
|
+
# @note the purpose of this method is to provide fast access to member
|
24
|
+
# order. currently this is achieved by accessing indexed list proxies
|
25
|
+
# from Solr. however, this strategy may change in the future.
|
26
|
+
#
|
27
|
+
# @return [Enumerable<String>] ids in the order of their membership,
|
28
|
+
# only includes ids of ordered members.
|
29
|
+
def ordered_member_ids
|
30
|
+
return [] if id.blank?
|
31
|
+
@ordered_member_ids ||= query_for_ordered_ids
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def query_for_ordered_ids(limit: 10_000,
|
37
|
+
proxy_field: 'proxy_in_ssi',
|
38
|
+
target_field: 'ordered_targets_ssim')
|
39
|
+
ActiveFedora::SolrService
|
40
|
+
.query("#{proxy_field}:#{id}", rows: limit, fl: target_field)
|
41
|
+
.flat_map { |x| x.fetch(target_field, nil) }
|
42
|
+
.compact
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -61,10 +61,20 @@ module Hyrax
|
|
61
61
|
@model ||= ModelWrapper.new(hydra_model, id)
|
62
62
|
end
|
63
63
|
|
64
|
+
##
|
65
|
+
# @return [Boolean]
|
64
66
|
def collection?
|
65
67
|
hydra_model == ::Collection
|
66
68
|
end
|
67
69
|
|
70
|
+
##
|
71
|
+
# @return [Boolean]
|
72
|
+
def file_set?
|
73
|
+
hydra_model == ::FileSet
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# @return [Boolean]
|
68
78
|
def admin_set?
|
69
79
|
hydra_model == ::AdminSet
|
70
80
|
end
|
@@ -11,20 +11,11 @@ module Hyrax
|
|
11
11
|
# @return [IIIFManifest::DisplayImage] the display image required by the manifest builder.
|
12
12
|
def display_image
|
13
13
|
return nil unless solr_document.image? && current_ability.can?(:read, solr_document)
|
14
|
-
|
15
|
-
latest_file_id = lookup_original_file_id
|
16
|
-
|
17
14
|
return nil unless latest_file_id
|
18
15
|
|
19
|
-
url = Hyrax.config.iiif_image_url_builder.call(
|
20
|
-
latest_file_id,
|
21
|
-
request.base_url,
|
22
|
-
Hyrax.config.iiif_image_size_default
|
23
|
-
)
|
24
|
-
|
25
16
|
# @see https://github.com/samvera-labs/iiif_manifest
|
26
|
-
IIIFManifest::DisplayImage.new(
|
27
|
-
format: image_format(
|
17
|
+
IIIFManifest::DisplayImage.new(display_image_url(request.base_url),
|
18
|
+
format: image_format(alpha_channels),
|
28
19
|
width: width,
|
29
20
|
height: height,
|
30
21
|
iiif_endpoint: iiif_endpoint(latest_file_id))
|
@@ -32,16 +23,24 @@ module Hyrax
|
|
32
23
|
|
33
24
|
private
|
34
25
|
|
35
|
-
def
|
26
|
+
def display_image_url(base_url)
|
27
|
+
Hyrax.config.iiif_image_url_builder.call(
|
28
|
+
latest_file_id,
|
29
|
+
base_url,
|
30
|
+
Hyrax.config.iiif_image_size_default
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def iiif_endpoint(file_id, base_url: request.base_url)
|
36
35
|
return unless Hyrax.config.iiif_image_server?
|
37
36
|
IIIFManifest::IIIFEndpoint.new(
|
38
|
-
Hyrax.config.iiif_info_url_builder.call(file_id,
|
37
|
+
Hyrax.config.iiif_info_url_builder.call(file_id, base_url),
|
39
38
|
profile: Hyrax.config.iiif_image_compliance_level_uri
|
40
39
|
)
|
41
40
|
end
|
42
41
|
|
43
42
|
def image_format(channels)
|
44
|
-
channels
|
43
|
+
channels&.find { |c| c.include?('rgba') }.nil? ? 'jpg' : 'png'
|
45
44
|
end
|
46
45
|
|
47
46
|
def unindexed_current_file_version
|
@@ -49,13 +48,18 @@ module Hyrax
|
|
49
48
|
ActiveFedora::File.uri_to_id(::FileSet.find(id).current_content_version_uri)
|
50
49
|
end
|
51
50
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
def latest_file_id
|
52
|
+
@latest_file_id ||=
|
53
|
+
begin
|
54
|
+
result = original_file_id
|
55
|
+
|
56
|
+
if result.blank?
|
57
|
+
Rails.logger.warn "original_file_id for #{id} not found, falling back to Fedora."
|
58
|
+
result = Hyrax::VersioningService.versioned_file_id ::FileSet.find(id).original_file
|
59
|
+
end
|
60
|
+
|
61
|
+
result
|
62
|
+
end
|
59
63
|
end
|
60
64
|
end
|
61
65
|
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hyrax
|
4
|
+
##
|
5
|
+
# This presenter wraps objects in the interface required by `IIIFManifiest`.
|
6
|
+
# It will accept either a Work-like resource or a SolrDocument.
|
7
|
+
#
|
8
|
+
# @example with a work
|
9
|
+
#
|
10
|
+
# monograph = Monograph.new
|
11
|
+
# presenter = IiifManifestPresenter.new(monograph)
|
12
|
+
# presenter.title # => []
|
13
|
+
#
|
14
|
+
# monograph.title = ['Comet in Moominland']
|
15
|
+
# presenter.title # => ['Comet in Moominland']
|
16
|
+
#
|
17
|
+
# @see https://www.rubydoc.info/gems/iiif_manifest
|
18
|
+
class IiifManifestPresenter < Draper::Decorator
|
19
|
+
delegate_all
|
20
|
+
|
21
|
+
##
|
22
|
+
# @!attribute [w] ability
|
23
|
+
# @return [Ability]
|
24
|
+
# @!attribute [w] hostname
|
25
|
+
# @return [String]
|
26
|
+
attr_writer :ability, :hostname
|
27
|
+
|
28
|
+
class << self
|
29
|
+
##
|
30
|
+
# @param [Hyrax::Resource, SolrDocument]
|
31
|
+
def for(model)
|
32
|
+
klass = model.file_set? ? DisplayImagePresenter : IiifManifestPresenter
|
33
|
+
|
34
|
+
klass.new(model)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# @return [#can?]
|
40
|
+
def ability
|
41
|
+
@ability ||= NullAbility.new
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# @return [String]
|
46
|
+
def description
|
47
|
+
Array(super).first || ''
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# @return [Boolean]
|
52
|
+
def file_set?
|
53
|
+
model.try(:file_set?) || Array(model[:has_model_ssim]).include?('FileSet')
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# @return [Array<DisplayImagePresenter>]
|
58
|
+
def file_set_presenters
|
59
|
+
member_presenters.select(&:file_set?)
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# IIIF metadata for inclusion in the manifest
|
64
|
+
# Called by the `iiif_manifest` gem to add metadata
|
65
|
+
#
|
66
|
+
# @todo should this use the simple_form i18n keys?! maybe the manifest
|
67
|
+
# needs its own?
|
68
|
+
#
|
69
|
+
# @return [Array<Hash{String => String}>] array of metadata hashes
|
70
|
+
def manifest_metadata
|
71
|
+
metadata_fields.map do |field_name|
|
72
|
+
{
|
73
|
+
'label' => I18n.t("simple_form.labels.defaults.#{field_name}"),
|
74
|
+
'value' => Array(self[field_name]).map { |value| scrub(value.to_s) }
|
75
|
+
}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# @return [String] the URL where the manifest can be found
|
81
|
+
def manifest_url
|
82
|
+
return '' if id.blank?
|
83
|
+
|
84
|
+
Rails.application.routes.url_helpers.polymorphic_url([:manifest, model], host: hostname)
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# @return [Array<#to_s>]
|
89
|
+
def member_ids
|
90
|
+
Hyrax::SolrDocument::OrderedMembers.decorate(model).ordered_member_ids
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# @note cache member presenters to avoid querying repeatedly; we expect this
|
95
|
+
# presenter to live only as long as the request.
|
96
|
+
#
|
97
|
+
# @note skips presenters for objects the current `@ability` cannot read.
|
98
|
+
# the default ability has all permissions.
|
99
|
+
#
|
100
|
+
# @return [Array<IiifManifestPresenter>]
|
101
|
+
def member_presenters
|
102
|
+
@member_presenters_cache ||= Factory.build_for(ids: member_ids, presenter_class: self.class).map do |presenter|
|
103
|
+
next unless ability.can?(:read, presenter.model)
|
104
|
+
|
105
|
+
presenter.hostname = hostname
|
106
|
+
presenter.ability = ability
|
107
|
+
presenter
|
108
|
+
end.compact
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# @return [Array<Hash{String => String}>]
|
113
|
+
def sequence_rendering
|
114
|
+
Array(try(:rendering_ids)).map do |file_set_id|
|
115
|
+
rendering = file_set_presenters.find { |p| p.id == file_set_id }
|
116
|
+
next unless rendering
|
117
|
+
|
118
|
+
{ '@id' => Hyrax::Engine.routes.url_helpers.download_url(rendering.id, host: hostname),
|
119
|
+
'format' => rendering.mime_type.present? ? rendering.mime_type : I18n.t("hyrax.manifest.unknown_mime_text"),
|
120
|
+
'label' => I18n.t("hyrax.manifest.download_text") + (rendering.label || '') }
|
121
|
+
end.flatten
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# @return [Boolean]
|
126
|
+
def work?
|
127
|
+
object.try(:work?) || !file_set?
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# @return [Array<IiifManifestPresenter>]
|
132
|
+
def work_presenters
|
133
|
+
member_presenters.select(&:work?)
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# @note ideally, this value will be cheap to retrieve, and will reliably
|
138
|
+
# change any time the manifest JSON will change. the current implementation
|
139
|
+
# is more blunt than this, changing only when the work itself changes.
|
140
|
+
#
|
141
|
+
# @return [String] a string tag suitable for cache keys for this manifiest
|
142
|
+
def version
|
143
|
+
object.try(:modified_date)&.to_s || ''
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# An Ability-like object that gives `true` for all `can?` requests
|
148
|
+
class NullAbility
|
149
|
+
##
|
150
|
+
# @return [Boolean] true
|
151
|
+
def can?(*)
|
152
|
+
true
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class Factory < PresenterFactory
|
157
|
+
##
|
158
|
+
# @return [Array]
|
159
|
+
def build
|
160
|
+
ids.map do |id|
|
161
|
+
solr_doc = load_docs.find { |doc| doc.id == id }
|
162
|
+
presenter_class.for(solr_doc) if solr_doc
|
163
|
+
end.compact
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
##
|
169
|
+
# cache the docs in this method, rather than #build;
|
170
|
+
# this can probably be pushed up to the parent class
|
171
|
+
def load_docs
|
172
|
+
@cached_docs ||= super
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# a Presenter for producing `IIIFManifest::DisplayImage` objects
|
178
|
+
#
|
179
|
+
class DisplayImagePresenter < Draper::Decorator
|
180
|
+
delegate_all
|
181
|
+
|
182
|
+
include Hyrax::DisplaysImage
|
183
|
+
|
184
|
+
##
|
185
|
+
# @!attribute [w] ability
|
186
|
+
# @return [Ability]
|
187
|
+
# @!attribute [w] hostname
|
188
|
+
# @return [String]
|
189
|
+
attr_writer :ability, :hostname
|
190
|
+
|
191
|
+
##
|
192
|
+
# Creates a display image only where #model is an image.
|
193
|
+
#
|
194
|
+
# @return [IIIFManifest::DisplayImage] the display image required by the manifest builder.
|
195
|
+
def display_image
|
196
|
+
return nil unless model.image?
|
197
|
+
return nil unless latest_file_id
|
198
|
+
|
199
|
+
IIIFManifest::DisplayImage
|
200
|
+
.new(display_image_url(hostname),
|
201
|
+
format: image_format(alpha_channels),
|
202
|
+
width: width,
|
203
|
+
height: height,
|
204
|
+
iiif_endpoint: iiif_endpoint(latest_file_id, base_url: hostname))
|
205
|
+
end
|
206
|
+
|
207
|
+
def hostname
|
208
|
+
@hostname || 'localhost'
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# @return [Boolean] false
|
213
|
+
def work?
|
214
|
+
false
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
def hostname
|
221
|
+
@hostname || 'localhost'
|
222
|
+
end
|
223
|
+
|
224
|
+
def metadata_fields
|
225
|
+
Hyrax.config.iiif_metadata_fields
|
226
|
+
end
|
227
|
+
|
228
|
+
def scrub(value)
|
229
|
+
Loofah.fragment(value).scrub!(:whitewash).to_s
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -36,14 +36,8 @@ module Hyrax
|
|
36
36
|
@work_presenters ||= member_presenters(ordered_ids - file_set_ids, work_presenter_class)
|
37
37
|
end
|
38
38
|
|
39
|
-
# TODO: Extract this to ActiveFedora::Aggregations::ListSource
|
40
39
|
def ordered_ids
|
41
|
-
@ordered_ids ||=
|
42
|
-
ActiveFedora::SolrService.query("proxy_in_ssi:#{id}",
|
43
|
-
rows: 10_000,
|
44
|
-
fl: "ordered_targets_ssim")
|
45
|
-
.flat_map { |x| x.fetch("ordered_targets_ssim", []) }
|
46
|
-
end
|
40
|
+
@ordered_ids ||= Hyrax::SolrDocument::OrderedMembers.decorate(@work).ordered_member_ids
|
47
41
|
end
|
48
42
|
|
49
43
|
private
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hyrax
|
4
|
+
##
|
5
|
+
# constructs IIIF Manifests and holds them in the Rails cache,
|
6
|
+
# this approach avoids long manifest build times for some kinds of requests,
|
7
|
+
# at the cost of introducing cache invalidation issues.
|
8
|
+
class CachingIiifManifestBuilder < ManifestBuilderService
|
9
|
+
KEY_PREFIX = 'iiif-cache-v1'
|
10
|
+
|
11
|
+
attr_accessor :expires_in
|
12
|
+
|
13
|
+
##
|
14
|
+
# @api public
|
15
|
+
#
|
16
|
+
# @param iiif_manifest_factory [Class] a class that initializes with presenter
|
17
|
+
# object and returns an object that responds to `#to_h`
|
18
|
+
# @param expires_in [Integer] the number of seconds until the cache expires
|
19
|
+
# @see Hyrax::Configuration#iiif_manifest_cache_duration
|
20
|
+
def initialize(iiif_manifest_factory: ::IIIFManifest::ManifestFactory, expires_in: Hyrax.config.iiif_manifest_cache_duration)
|
21
|
+
self.expires_in = expires_in
|
22
|
+
|
23
|
+
super(iiif_manifest_factory: iiif_manifest_factory)
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# @see ManifestBuilderService#as_json
|
28
|
+
def manifest_for(presenter:)
|
29
|
+
Rails.cache.fetch(manifest_cache_key(presenter: presenter), expires_in: expires_in) do
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
##
|
37
|
+
# @note adding a version_for suffix helps us manage cache expiration,
|
38
|
+
# reducing false cache hits
|
39
|
+
#
|
40
|
+
# @param presenter [Hyrax::IiifManifestPresenter]
|
41
|
+
#
|
42
|
+
# @return [String]
|
43
|
+
def manifest_cache_key(presenter:)
|
44
|
+
"#{KEY_PREFIX}_#{presenter.id}/#{version_for(presenter)}"
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# @return [String]
|
49
|
+
def version_for(presenter)
|
50
|
+
presenter.version
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -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">
|
@@ -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,5 +1,11 @@
|
|
1
1
|
<% # we will yield to content_for for each tab, e.g. :files_tab %>
|
2
|
-
|
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">
|
@@ -10,7 +10,7 @@
|
|
10
10
|
<%= link_to t("hyrax.batch_uploads.files.button_label"), [main_app, :new, Hyrax.primary_work_type.model_name.singular_route_key] %>
|
11
11
|
</p>
|
12
12
|
<% end %>
|
13
|
-
<%= render 'hyrax/base/guts4form', f: f, tabs:
|
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
|
|
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'
|
@@ -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"
|
data/lib/hyrax.rb
CHANGED
data/lib/hyrax/configuration.rb
CHANGED
@@ -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?
|
@@ -514,6 +524,11 @@ module Hyrax
|
|
514
524
|
->(id:, extent:) { Samvera::NestingIndexer.reindex_relationships(id: id, extent: extent) }
|
515
525
|
end
|
516
526
|
|
527
|
+
attr_writer :identifier_registrars
|
528
|
+
def identifier_registrars
|
529
|
+
@identifier_registrars ||= {}
|
530
|
+
end
|
531
|
+
|
517
532
|
private
|
518
533
|
|
519
534
|
# @param [Symbol, #to_s] model_name - symbol representing the model
|
data/lib/hyrax/engine.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_examples 'a Hyrax::Identifier::Builder' do
|
4
|
+
subject(:builder) { described_class.new }
|
5
|
+
|
6
|
+
describe '#build' do
|
7
|
+
it 'returns an identifier string' do
|
8
|
+
expect(builder.build(hint: 'moomin'))
|
9
|
+
.to respond_to :to_str
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec.shared_examples 'a Hyrax::Identifier::Registrar' do
|
15
|
+
subject(:registrar) { described_class.new(builder: builder) }
|
16
|
+
let(:builder) { instance_double(Hyrax::Identifier::Builder, build: 'moomin') }
|
17
|
+
let(:object) { instance_double(GenericWork, id: 'moomin_id') }
|
18
|
+
|
19
|
+
it { is_expected.to have_attributes(builder: builder) }
|
20
|
+
|
21
|
+
describe '#register!' do
|
22
|
+
it 'creates an identifier record' do
|
23
|
+
expect(registrar.register!(object: object).identifier)
|
24
|
+
.to respond_to :to_str
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/hyrax/version.rb
CHANGED
data/template.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hyrax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2020-
|
17
|
+
date: 2020-07-28 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: rails
|
@@ -162,6 +162,20 @@ dependencies:
|
|
162
162
|
- - "~>"
|
163
163
|
- !ruby/object:Gem::Version
|
164
164
|
version: '1.5'
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
name: draper
|
167
|
+
requirement: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - "~>"
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '4.0'
|
172
|
+
type: :runtime
|
173
|
+
prerelease: false
|
174
|
+
version_requirements: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - "~>"
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '4.0'
|
165
179
|
- !ruby/object:Gem::Dependency
|
166
180
|
name: dry-equalizer
|
167
181
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1460,6 +1474,7 @@ files:
|
|
1460
1474
|
- app/helpers/hyrax/title_helper.rb
|
1461
1475
|
- app/helpers/hyrax/trophy_helper.rb
|
1462
1476
|
- app/helpers/hyrax/url_helper.rb
|
1477
|
+
- app/helpers/hyrax/work_form_helper.rb
|
1463
1478
|
- app/indexers/concerns/hyrax/indexes_basic_metadata.rb
|
1464
1479
|
- app/indexers/concerns/hyrax/indexes_linked_metadata.rb
|
1465
1480
|
- app/indexers/hyrax/admin_set_indexer.rb
|
@@ -1497,6 +1512,7 @@ files:
|
|
1497
1512
|
- app/jobs/hyrax/grant_read_to_members_job.rb
|
1498
1513
|
- app/jobs/hyrax/revoke_edit_from_members_job.rb
|
1499
1514
|
- app/jobs/hyrax/revoke_edit_job.rb
|
1515
|
+
- app/jobs/iiif_manifest_cache_prewarm_job.rb
|
1500
1516
|
- app/jobs/import_export_job.rb
|
1501
1517
|
- app/jobs/import_url_job.rb
|
1502
1518
|
- app/jobs/ingest_job.rb
|
@@ -1541,6 +1557,7 @@ files:
|
|
1541
1557
|
- app/models/concerns/hyrax/solr_document/characterization.rb
|
1542
1558
|
- app/models/concerns/hyrax/solr_document/export.rb
|
1543
1559
|
- app/models/concerns/hyrax/solr_document/metadata.rb
|
1560
|
+
- app/models/concerns/hyrax/solr_document/ordered_members.rb
|
1544
1561
|
- app/models/concerns/hyrax/solr_document_behavior.rb
|
1545
1562
|
- app/models/concerns/hyrax/suppressible.rb
|
1546
1563
|
- app/models/concerns/hyrax/user.rb
|
@@ -1619,6 +1636,7 @@ files:
|
|
1619
1636
|
- app/presenters/hyrax/file_usage.rb
|
1620
1637
|
- app/presenters/hyrax/fixity_status_presenter.rb
|
1621
1638
|
- app/presenters/hyrax/homepage_presenter.rb
|
1639
|
+
- app/presenters/hyrax/iiif_manifest_presenter.rb
|
1622
1640
|
- app/presenters/hyrax/inspect_work_presenter.rb
|
1623
1641
|
- app/presenters/hyrax/lease_presenter.rb
|
1624
1642
|
- app/presenters/hyrax/member_presenter_factory.rb
|
@@ -1705,6 +1723,7 @@ files:
|
|
1705
1723
|
- app/services/hyrax/analytics.rb
|
1706
1724
|
- app/services/hyrax/batch_create_failure_service.rb
|
1707
1725
|
- app/services/hyrax/batch_create_success_service.rb
|
1726
|
+
- app/services/hyrax/caching_iiif_manifest_builder.rb
|
1708
1727
|
- app/services/hyrax/change_content_depositor_service.rb
|
1709
1728
|
- app/services/hyrax/collection_member_service.rb
|
1710
1729
|
- app/services/hyrax/collection_size_service.rb
|
@@ -1733,6 +1752,9 @@ files:
|
|
1733
1752
|
- app/services/hyrax/fixity_check_failure_service.rb
|
1734
1753
|
- app/services/hyrax/form_metadata_service.rb
|
1735
1754
|
- app/services/hyrax/graph_exporter.rb
|
1755
|
+
- app/services/hyrax/identifier/builder.rb
|
1756
|
+
- app/services/hyrax/identifier/dispatcher.rb
|
1757
|
+
- app/services/hyrax/identifier/registrar.rb
|
1736
1758
|
- app/services/hyrax/iiif_authorization_service.rb
|
1737
1759
|
- app/services/hyrax/import_url_failure_service.rb
|
1738
1760
|
- app/services/hyrax/indexes_thumbnails.rb
|
@@ -1743,6 +1765,7 @@ files:
|
|
1743
1765
|
- app/services/hyrax/local_file_service.rb
|
1744
1766
|
- app/services/hyrax/lock_manager.rb
|
1745
1767
|
- app/services/hyrax/lockable.rb
|
1768
|
+
- app/services/hyrax/manifest_builder_service.rb
|
1746
1769
|
- app/services/hyrax/messenger_service.rb
|
1747
1770
|
- app/services/hyrax/microdata.rb
|
1748
1771
|
- app/services/hyrax/multiple_membership_checker.rb
|
@@ -2371,6 +2394,7 @@ files:
|
|
2371
2394
|
- lib/hyrax/search_state.rb
|
2372
2395
|
- lib/hyrax/specs/shared_specs.rb
|
2373
2396
|
- lib/hyrax/specs/shared_specs/derivative_service.rb
|
2397
|
+
- lib/hyrax/specs/shared_specs/identifiers.rb
|
2374
2398
|
- lib/hyrax/specs/shared_specs/workflow_method.rb
|
2375
2399
|
- lib/hyrax/transactions.rb
|
2376
2400
|
- lib/hyrax/transactions/container.rb
|