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