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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 140c7caa34751f7a525eda269abcee6331a9e7d200863e2cbee29d315966de65
4
- data.tar.gz: 7085c394edd0aa1e90baef7d13f90245d8fb0fb65659e54549cedda0487445e9
3
+ metadata.gz: '0148443e7ca6987d77b7ccbad46c89c895ae60e226565819b095293884c040cc'
4
+ data.tar.gz: 5a2cfda462e5415dc6c736dcbaaf4bb7b7a202fa0afe54c2819026f4559d7942
5
5
  SHA512:
6
- metadata.gz: 691b84f363281552cbd84f85b767bb5b460ba749e0449aed0498594143767a6cd4dae187a5dd9c88bf3b7bd06a568375da70367b3b8faa674a59f39deaf4df06
7
- data.tar.gz: e19605afaa51b569ea79e7e99d65fd0576b172cd6dfeb38f815c4dd3a7ac18678bb6b3ff4ac4a5af2b6358bf55c459baba0c4a98b393d20f7d64388f576c894f
6
+ metadata.gz: faaee31b6dec44292d47981fe77d22bc9f8f40865670b9f2b1a470aca00b10193cb01931c1084a9622cb3a4e6fca5803c1b6a8a77965dca75619cc59f5da1d67
7
+ data.tar.gz: b3232036171e55e8166da5d4886d52b91fe6ce3f0c05018508deee6b594491df87b0d7b925b477e4d8a6a5134c0233026433d4df47d9902c28e074614dd3e18d
data/.circleci/config.yml CHANGED
@@ -12,7 +12,7 @@ jobs:
12
12
  default: 1.17.3
13
13
  rails_version:
14
14
  type: string
15
- default: '5.2.4.3'
15
+ default: '5.2.6'
16
16
  executor:
17
17
  name: 'samvera/ruby'
18
18
  ruby_version: << parameters.ruby_version >>
@@ -57,7 +57,7 @@ jobs:
57
57
  default: 1.17.3
58
58
  rails_version:
59
59
  type: string
60
- default: '5.2.4.3'
60
+ default: '5.2.6'
61
61
  executor:
62
62
  name: 'samvera/ruby'
63
63
  ruby_version: << parameters.ruby_version >>
@@ -136,10 +136,10 @@ workflows:
136
136
  jobs:
137
137
  - bundle:
138
138
  ruby_version: "2.5.8"
139
- rails_version: "5.2.4.3"
139
+ rails_version: "5.2.6"
140
140
  - build:
141
141
  ruby_version: "2.5.8"
142
- rails_version: "5.2.4.3"
142
+ rails_version: "5.2.6"
143
143
  requires:
144
144
  - bundle
145
145
  - test:
@@ -151,10 +151,10 @@ workflows:
151
151
  jobs:
152
152
  - bundle:
153
153
  ruby_version: "2.6.6"
154
- rails_version: "5.2.4.3"
154
+ rails_version: "5.2.6"
155
155
  - build:
156
156
  ruby_version: "2.6.6"
157
- rails_version: "5.2.4.3"
157
+ rails_version: "5.2.6"
158
158
  requires:
159
159
  - bundle
160
160
  - test:
@@ -166,11 +166,11 @@ workflows:
166
166
  jobs:
167
167
  - bundle:
168
168
  ruby_version: "2.7.1"
169
- rails_version: "5.2.4.3"
169
+ rails_version: "5.2.6"
170
170
  bundler_version: "2.1.2"
171
171
  - build:
172
172
  ruby_version: "2.7.1"
173
- rails_version: "5.2.4.3"
173
+ rails_version: "5.2.6"
174
174
  bundler_version: "2.1.2"
175
175
  requires:
176
176
  - bundle
data/.gitignore CHANGED
@@ -78,3 +78,4 @@ _yardoc
78
78
  lib/bundler/man
79
79
  spec/reports
80
80
  /spec/examples.txt
81
+ node_modules
data/.regen CHANGED
@@ -1 +1 @@
1
- 3
1
+ 3.http_method
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.8.0/template.rb
161
+ rails _5.2.6_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.9.5/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:
@@ -104,6 +104,7 @@
104
104
  //= require hyrax/tabbed_form
105
105
  //= require hyrax/turbolinks_events
106
106
  //= require hyrax/i18n_helper
107
+ //= require hyrax/skip_to_content
107
108
 
108
109
  // this needs to be after batch_select so that the form ids get setup correctly
109
110
  //= require hyrax/batch_edit
@@ -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
@@ -0,0 +1,15 @@
1
+ // This code is to implement skip_to_content
2
+
3
+ Blacklight.onLoad(function () {
4
+ $(".skip-to-content").click(function(event) {
5
+ event.preventDefault();
6
+ // element to focus on
7
+ var skipTo = '#' + $(this)[0].firstElementChild.hash.split('#')[1];
8
+
9
+ // Setting 'tabindex' to -1 takes an element out of normal
10
+ // tab flow but allows it to be focused via javascript
11
+ $(skipTo).attr('tabindex', -1).on('blur focusout', function () {
12
+ $(this).removeAttr('tabindex');
13
+ }).focus();
14
+ });
15
+ });
@@ -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: manifest_builder.to_h }
132
- wants.html { render json: manifest_builder.to_h }
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.base_url
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
@@ -85,13 +85,18 @@ module Hyrax
85
85
  actor.revert_content(params[:revision])
86
86
  elsif params.key?(:file_set)
87
87
  if params[:file_set].key?(:files)
88
- actor.update_content(params[:file_set][:files].first)
88
+ actor.update_content(uploaded_file_from_path)
89
89
  else
90
90
  update_metadata
91
91
  end
92
92
  end
93
93
  end
94
94
 
95
+ def uploaded_file_from_path
96
+ uploaded_file = CarrierWave::SanitizedFile.new(params[:file_set][:files].first)
97
+ Hyrax::UploadedFile.create(user_id: current_user.id, file: uploaded_file)
98
+ end
99
+
95
100
  def after_update_response
96
101
  respond_to do |wants|
97
102
  wants.html do
@@ -41,7 +41,7 @@ module Hyrax
41
41
 
42
42
  def find_user
43
43
  @user = ::User.from_url_component(params[:id])
44
- redirect_to root_path, alert: "User '#{params[:id]}' does not exist" if @user.nil?
44
+ redirect_to root_path, alert: "User does not exist" unless @user
45
45
  end
46
46
 
47
47
  def sort_value
@@ -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,15 @@
1
+ # frozen_string_literal: true
2
+ class EmbargoExpiryJob < Hyrax::ApplicationJob
3
+ def perform
4
+ records_with_expired_embargos.each do |id|
5
+ work = ActiveFedora::Base.find(id)
6
+ Hyrax::Actors::EmbargoActor.new(work).destroy
7
+ end
8
+ end
9
+
10
+ ##
11
+ # @return [Enumerator<String>] ids for all the objects that have expired active embargoes
12
+ def records_with_expired_embargos
13
+ Hyrax::EmbargoService.assets_with_expired_embargoes.map(&:id)
14
+ end
15
+ 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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ class LeaseExpiryJob < Hyrax::ApplicationJob
3
+ def perform
4
+ records_with_expired_leases.each do |id|
5
+ work = ActiveFedora::Base.find(id)
6
+ Hyrax::Actors::LeaseActor.new(work).destroy
7
+ end
8
+ end
9
+
10
+ ##
11
+ # @return [Enumerator<String>] ids for all the objects that have expired active leases
12
+ def records_with_expired_leases
13
+ Hyrax::LeaseService.assets_with_expired_leases.map(&:id)
14
+ end
15
+ end
@@ -73,7 +73,7 @@ module Hyrax
73
73
  ids = PermissionTemplateAccess.for_user(ability: self,
74
74
  access: ['deposit', 'manage'])
75
75
  .joins(:permission_template)
76
- .pluck('DISTINCT source_id')
76
+ .pluck(Arel.sql('DISTINCT source_id'))
77
77
  query = "_query_:\"{!raw f=has_model_ssim}AdminSet\" AND {!terms f=id}#{ids.join(',')}"
78
78
  ActiveFedora::SolrService.count(query).positive?
79
79
  end
@@ -67,7 +67,7 @@ module Hyrax
67
67
  end
68
68
 
69
69
  def file_size
70
- self[Solrizer.solr_name("file_size")]
70
+ self["file_size_lts"]
71
71
  end
72
72
 
73
73
  def filename
@@ -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