hyrax 3.4.1 → 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +26 -17
  3. data/.dassie/.env +1 -1
  4. data/.dassie/Gemfile +1 -1
  5. data/.dassie/app/forms/collection_resource_form.rb +8 -0
  6. data/.dassie/app/indexers/collection_resource_indexer.rb +8 -0
  7. data/.dassie/app/models/collection_resource.rb +35 -0
  8. data/.dassie/config/initializers/file_services.rb +4 -0
  9. data/.dassie/config/initializers/hyrax.rb +2 -1
  10. data/.dassie/config/metadata/collection_resource.yaml +23 -0
  11. data/.dassie/db/seeds.rb +2 -0
  12. data/.dassie/spec/forms/collection_resource_form_spec.rb +13 -0
  13. data/.dassie/spec/indexers/collection_resource_indexer_spec.rb +14 -0
  14. data/.dassie/spec/models/collection_resource_spec.rb +13 -0
  15. data/.regen +1 -1
  16. data/.rubocop.yml +1 -1
  17. data/.rubocop_fixme.yml +19 -2
  18. data/CONTAINERS.md +18 -13
  19. data/Dockerfile +2 -2
  20. data/app/assets/javascripts/hyrax/collections_v2.es6 +13 -0
  21. data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +1 -3
  22. data/app/controllers/hyrax/dashboard/collections_controller.rb +159 -75
  23. data/app/controllers/hyrax/single_use_links_viewer_controller.rb +1 -1
  24. data/app/forms/hyrax/forms/collection_form.rb +1 -1
  25. data/app/forms/hyrax/forms/pcdm_collection_form.rb +29 -2
  26. data/app/forms/hyrax/forms/resource_form.rb +15 -1
  27. data/app/forms/hyrax/forms/widgets/admin_set_visibility.rb +1 -1
  28. data/app/indexers/hyrax/pcdm_collection_indexer.rb +0 -1
  29. data/app/jobs/characterize_job.rb +5 -1
  30. data/app/jobs/import_url_job.rb +4 -6
  31. data/app/jobs/valkyrie_ingest_job.rb +15 -77
  32. data/app/models/admin_set.rb +8 -0
  33. data/app/models/concerns/hyrax/collection_behavior.rb +1 -1
  34. data/app/models/concerns/hyrax/user.rb +11 -0
  35. data/app/models/concerns/hyrax/work_behavior.rb +1 -1
  36. data/app/models/featured_work_list.rb +0 -1
  37. data/app/models/hyrax/file_metadata.rb +32 -2
  38. data/app/models/hyrax/file_set.rb +1 -3
  39. data/app/models/hyrax/group.rb +19 -0
  40. data/app/models/hyrax/pcdm_collection.rb +0 -1
  41. data/app/models/job_io_wrapper.rb +1 -1
  42. data/app/presenters/hyrax/member_presenter_factory.rb +2 -4
  43. data/app/presenters/hyrax/work_show_presenter.rb +3 -3
  44. data/app/services/hyrax/access_control_list.rb +7 -6
  45. data/app/services/hyrax/adapters/nesting_index_adapter.rb +3 -3
  46. data/app/services/hyrax/characterization/valkyrie_characterization_service.rb +3 -5
  47. data/app/services/hyrax/collections/collection_member_service.rb +3 -5
  48. data/app/services/hyrax/listeners/file_metadata_listener.rb +11 -0
  49. data/app/services/hyrax/listeners/member_cleanup_listener.rb +14 -18
  50. data/app/services/hyrax/multiple_membership_checker.rb +2 -0
  51. data/app/services/hyrax/valkyrie_persist_derivatives.rb +50 -0
  52. data/app/services/hyrax/valkyrie_upload.rb +94 -0
  53. data/app/services/hyrax/workflow/workflow_importer.rb +7 -9
  54. data/app/services/hyrax/workflow/workflow_schema.rb +3 -5
  55. data/app/strategies/hyrax/strategies/yaml_strategy.rb +4 -6
  56. data/app/uploaders/hyrax/uploaded_file_uploader.rb +4 -4
  57. data/app/validators/hyrax/collection_membership_validator.rb +16 -15
  58. data/app/views/catalog/_index_header_list_default.html.erb +8 -1
  59. data/app/views/catalog/_thumbnail_list_default.html.erb +8 -3
  60. data/app/views/collections/edit_fields/_based_near.html.erb +7 -7
  61. data/app/views/hyrax/dashboard/collections/_form.html.erb +3 -2
  62. data/app/views/hyrax/dashboard/collections/_form_branding.html.erb +1 -0
  63. data/app/views/hyrax/dashboard/sidebar/_activity.html.erb +1 -1
  64. data/app/views/hyrax/my/works/_tabs.html.erb +6 -1
  65. data/chart/hyrax/Chart.yaml +10 -6
  66. data/chart/hyrax/templates/_helpers.tpl +4 -0
  67. data/chart/hyrax/templates/cron-embargo.yaml +5 -0
  68. data/chart/hyrax/templates/cron-lease.yaml +5 -0
  69. data/chart/hyrax/templates/deployment-worker.yaml +11 -0
  70. data/chart/hyrax/templates/ingress.yaml +7 -6
  71. data/chart/hyrax/values.yaml +152 -0
  72. data/config/features.rb +48 -50
  73. data/config/initializers/{valkryrie_storage.rb → storage_adapter_initializer.rb} +5 -0
  74. data/config/locales/hyrax.de.yml +12 -12
  75. data/docker-compose.yml +1 -0
  76. data/documentation/developing-your-hyrax-based-app.md +1 -1
  77. data/documentation/legacyREADME.md +1 -1
  78. data/hyrax.gemspec +5 -3
  79. data/lib/generators/hyrax/collection_resource/USAGE +20 -0
  80. data/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +133 -0
  81. data/lib/generators/hyrax/collection_resource/templates/collection.rb.erb +34 -0
  82. data/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +7 -0
  83. data/lib/generators/hyrax/collection_resource/templates/collection_form_spec.rb.erb +13 -0
  84. data/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +7 -0
  85. data/lib/generators/hyrax/collection_resource/templates/collection_indexer_spec.rb.erb +13 -0
  86. data/lib/generators/hyrax/collection_resource/templates/collection_metadata.yaml +22 -0
  87. data/lib/generators/hyrax/collection_resource/templates/collection_spec.rb.erb +12 -0
  88. data/lib/generators/hyrax/install_generator.rb +9 -0
  89. data/lib/hyrax/configuration.rb +12 -0
  90. data/lib/hyrax/publisher.rb +4 -0
  91. data/lib/hyrax/specs/shared_specs/hydra_works.rb +0 -1
  92. data/lib/hyrax/transactions/collection_update.rb +2 -0
  93. data/lib/hyrax/transactions/container.rb +10 -0
  94. data/lib/hyrax/transactions/steps/save_collection_banner.rb +59 -0
  95. data/lib/hyrax/transactions/steps/save_collection_logo.rb +109 -0
  96. data/lib/hyrax/version.rb +1 -1
  97. data/lib/wings/active_fedora_converter/file_metadata_node.rb +48 -0
  98. data/lib/wings/active_fedora_converter/instance_builder.rb +68 -0
  99. data/lib/wings/active_fedora_converter.rb +3 -3
  100. data/lib/wings/services/custom_queries/find_file_metadata.rb +19 -8
  101. data/lib/wings/valkyrie/query_service.rb +4 -6
  102. data/template.rb +1 -1
  103. metadata +63 -13
  104. data/app/views/catalog/_index_header_list_hyrax_pcdm_collection.html.erb +0 -4
@@ -1,6 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hyrax
4
+ ##
5
+ # Casts a resource to an associated FileMetadata
6
+ #
7
+ # @param [Valkyrie::StorageAdapter::File] file
8
+ #
9
+ # @return [Hyrax::FileMetadata]
10
+ # @raise [ArgumentError]
11
+ def self.FileMetadata(file)
12
+ raise(ArgumentError, "Expected a Valkyrie::StorageAdapter::File; got #{file.class}: #{file}") if
13
+ file.is_a?(Valkyrie::Resource)
14
+
15
+ Hyrax.custom_queries.find_file_metadata_by(id: file.id)
16
+ rescue Hyrax::ObjectNotFoundError, Ldp::BadRequest
17
+ Hyrax.logger.debug('Could not find an existing metadata node for file ' \
18
+ "with id #{file.id}. Initializing a new one")
19
+
20
+ FileMetadata.new(file_identifier: file.id, alternative_ids: [file.id])
21
+ end
22
+
4
23
  class FileMetadata < Valkyrie::Resource
5
24
  # Include mime-types for Hydra Derivatives mime-type checking. We may want
6
25
  # to move this logic someday.
@@ -39,7 +58,7 @@ module Hyrax
39
58
  end
40
59
 
41
60
  attribute :file_identifier, Valkyrie::Types::ID # id of the file stored by the storage adapter
42
- attribute :alternate_ids, Valkyrie::Types::Set.of(Valkyrie::Types::ID) # id of the Hydra::PCDM::File which holds metadata and the file in ActiveFedora
61
+ attribute :alternate_ids, Valkyrie::Types::Set.of(Valkyrie::Types::ID) # id of the file, populated for queryability
43
62
  attribute :file_set_id, ::Valkyrie::Types::ID # id of parent file set resource
44
63
 
45
64
  # all remaining attributes are on AF::File metadata_node unless otherwise noted
@@ -107,7 +126,9 @@ module Hyrax
107
126
  attribute :aspect_ratio, ::Valkyrie::Types::Set
108
127
 
109
128
  # @param [ActionDispatch::Http::UploadedFile] file
129
+ # @deprecated Use #new instead; for removal in 4.0.0
110
130
  def self.for(file:)
131
+ Deprecation.warn "#{self.class}##{__method__} is deprecated; use #new instead."
111
132
  new(label: file.original_filename,
112
133
  original_filename: file.original_filename,
113
134
  mime_type: file.content_type)
@@ -155,8 +176,17 @@ module Hyrax
155
176
  ''
156
177
  end
157
178
 
179
+ ##
180
+ # @return [Valkyrie::StorageAdapter::File]
181
+ #
182
+ # @raise [Valkyrie::StorageAdapter::AdapterNotFoundError] if no adapter
183
+ # could be found matching the file_identifier's scheme
184
+ # @raise [Valkyrie::StorageAdapter::FileNotFound] when the file can't
185
+ # be found in the registered adapter
158
186
  def file
159
- Hyrax.storage_adapter.find_by(id: file_identifier)
187
+ Valkyrie::StorageAdapter
188
+ .adapter_for(id: file_identifier)
189
+ .find_by(id: file_identifier)
160
190
  end
161
191
  end
162
192
  end
@@ -34,9 +34,7 @@ module Hyrax
34
34
  include Hyrax::Schema(:basic_metadata)
35
35
 
36
36
  def self.model_name(name_class: Hyrax::Name)
37
- @_model_name ||= begin
38
- name_class.new(self, nil, 'FileSet')
39
- end
37
+ @_model_name ||= name_class.new(self, nil, 'FileSet')
40
38
  end
41
39
 
42
40
  class_attribute :characterization_proxy
@@ -7,12 +7,31 @@ module Hyrax
7
7
  DEFAULT_NAME_PREFIX
8
8
  end
9
9
 
10
+ ##
11
+ # @return [Hyrax::Group]
12
+ def self.from_agent_key(key)
13
+ new(key.delete_prefix(name_prefix))
14
+ end
15
+
10
16
  def initialize(name)
11
17
  @name = name
12
18
  end
13
19
 
14
20
  attr_reader :name
15
21
 
22
+ ##
23
+ # @return [Boolean]
24
+ def ==(other)
25
+ other.class == self.class && other.name == name
26
+ end
27
+
28
+ ##
29
+ # @return [String] a local identifier for this group; for use (e.g.) in ACL
30
+ # data
31
+ def agent_key
32
+ self.class.name_prefix + name
33
+ end
34
+
16
35
  def to_sipity_agent
17
36
  sipity_agent || create_sipity_agent!
18
37
  end
@@ -41,7 +41,6 @@ module Hyrax
41
41
  #
42
42
  class PcdmCollection < Hyrax::Resource
43
43
  include Hyrax::Schema(:core_metadata)
44
- include Hyrax::Schema(:basic_metadata)
45
44
 
46
45
  attribute :collection_type_gid, Valkyrie::Types::String
47
46
  attribute :member_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID).meta(ordered: true)
@@ -94,7 +94,7 @@ class JobIoWrapper < ApplicationRecord
94
94
 
95
95
  def extracted_original_name
96
96
  eon = uploaded_file.uploader.filename if uploaded_file
97
- eon ||= File.basename(path) if path.present? # note: uploader.filename is `nil` with uncached remote files (e.g. AWSFile)
97
+ eon ||= File.basename(path) if path.present? # NOTE: uploader.filename is `nil` with uncached remote files (e.g. AWSFile)
98
98
  eon
99
99
  end
100
100
 
@@ -47,13 +47,11 @@ module Hyrax
47
47
  # in order.
48
48
  # Arbitrarily maxed at 10 thousand; had to specify rows due to solr's default of 10
49
49
  def file_set_ids
50
- @file_set_ids ||= begin
51
- Hyrax::SolrService.query("{!field f=has_model_ssim}FileSet",
50
+ @file_set_ids ||= Hyrax::SolrService.query("{!field f=has_model_ssim}FileSet",
52
51
  rows: 10_000,
53
52
  fl: Hyrax.config.id_field,
54
53
  fq: "{!join from=ordered_targets_ssim to=id}id:\"#{id}/list_source\"")
55
- .flat_map { |x| x.fetch(Hyrax.config.id_field, []) }
56
- end
54
+ .flat_map { |x| x.fetch(Hyrax.config.id_field, []) }
57
55
  end
58
56
 
59
57
  def presenter_factory_arguments
@@ -154,9 +154,9 @@ module Hyrax
154
154
  def grouped_presenters(filtered_by: nil, except: nil)
155
155
  # TODO: we probably need to retain collection_presenters (as parent_presenters)
156
156
  # and join this with member_of_collection_presenters
157
- grouped = member_of_collection_presenters.group_by(&:model_name).transform_keys { |key| key.to_s.underscore }
158
- grouped.select! { |obj| obj.downcase == filtered_by } unless filtered_by.nil?
159
- grouped.except!(*except) unless except.nil?
157
+ grouped = member_of_collection_presenters.group_by(&:model_name).transform_keys(&:human)
158
+ grouped.select! { |obj| obj.casecmp(filtered_by).zero? } unless filtered_by.nil?
159
+ grouped.reject! { |obj| except.map(&:downcase).include? obj.downcase } unless except.nil?
160
160
  grouped
161
161
  end
162
162
 
@@ -200,13 +200,14 @@ module Hyrax
200
200
 
201
201
  private
202
202
 
203
+ ##
204
+ # Returns the identifier used by ACLs to identify agents.
205
+ #
206
+ # This defaults to the `:agent_key`, but if that method doesn’t exist,
207
+ # `:user_key` will be used as a fallback.
203
208
  def id_for(agent:)
204
- case agent
205
- when Hyrax::Group
206
- "#{Hyrax::Group.name_prefix}#{agent.name}"
207
- else
208
- agent.user_key.to_s
209
- end
209
+ key = agent.try(:agent_key) || agent.user_key
210
+ key.to_s
210
211
  end
211
212
  end
212
213
 
@@ -60,7 +60,7 @@ module Hyrax
60
60
  object = ActiveFedora::Base.find(id)
61
61
  parent_ids = object.try(:member_of_collection_ids) || []
62
62
 
63
- # note: we do not yield when the object has parents. Calling the nested indexer for the
63
+ # NOTE: we do not yield when the object has parents. Calling the nested indexer for the
64
64
  # top id will reindex all descendants as well.
65
65
  if object.try(:use_nested_reindexing?)
66
66
  yield(id, parent_ids) if parent_ids.empty?
@@ -119,11 +119,11 @@ module Hyrax
119
119
  # @yield Samvera::NestingIndexer::Documents::IndexDocument
120
120
  #
121
121
  # @return [void]
122
- def self.each_child_document_of(document:, extent:, &block)
122
+ def self.each_child_document_of(document:, extent:, &block) # rubocop:disable Lint/UnusedMethodArgument
123
123
  raw_child_solr_documents_of(parent_document: document).each do |solr_document|
124
124
  child_document = coerce_solr_document_to_index_document(original_solr_document: solr_document, id: solr_document.fetch('id'))
125
125
  # during light reindexing, we want to reindex the child only if fields aren't already there
126
- block.call(child_document) if full_reindex?(extent: extent) || child_document.pathnames.empty?
126
+ yield(child_document) if full_reindex?(extent: extent) || child_document.pathnames.empty?
127
127
  end
128
128
  end
129
129
 
@@ -91,11 +91,9 @@ class Hyrax::Characterization::ValkyrieCharacterizationService
91
91
  h = {}
92
92
 
93
93
  doc.class.terminology.terms.each_pair do |key, _target|
94
- begin
95
- h[key] = doc.public_send(key)
96
- rescue NoMethodError
97
- next
98
- end
94
+ h[key] = doc.public_send(key)
95
+ rescue NoMethodError
96
+ next
99
97
  end
100
98
 
101
99
  h.compact
@@ -83,11 +83,9 @@ module Hyrax
83
83
  def add_members(collection_id:, new_members:, user:)
84
84
  messages = []
85
85
  new_members.map do |new_member|
86
- begin
87
- add_member(collection_id: collection_id, new_member: new_member, user: user)
88
- rescue Hyrax::SingleMembershipError => err
89
- messages += [err.message]
90
- end
86
+ add_member(collection_id: collection_id, new_member: new_member, user: user)
87
+ rescue Hyrax::SingleMembershipError => err
88
+ messages += [err.message]
91
89
  end
92
90
  raise Hyrax::SingleMembershipError, messages if messages.present?
93
91
  end
@@ -5,6 +5,17 @@ module Hyrax
5
5
  ##
6
6
  # Listens for events related to {Hyrax::FileMetadata}
7
7
  class FileMetadataListener
8
+ ##
9
+ # Called when 'file.characterized' event is published;
10
+ # allows post-characterization handling, like derivatives generation.
11
+ #
12
+ # @param [Dry::Events::Event] event
13
+ # @return [void]
14
+ def on_file_characterized(event)
15
+ CreateDerivativesJob
16
+ .perform_later(event[:file_set], event[:file_id], event[:path_hint])
17
+ end
18
+
8
19
  ##
9
20
  # Called when 'file.metadata.updated' event is published; reindexes a
10
21
  # {Hyrax::FileSet} when a file claiming to be its `pcdm_use:OriginalFile`
@@ -13,15 +13,13 @@ module Hyrax
13
13
  return if event[:object].is_a?(ActiveFedora::Base) # handled by legacy code
14
14
 
15
15
  Hyrax.custom_queries.find_child_file_sets(resource: event[:object]).each do |file_set|
16
- begin
17
- Hyrax.persister.delete(resource: file_set)
18
- Hyrax.publisher
19
- .publish('object.deleted', object: file_set, id: file_set.id, user: event[:user])
20
- rescue StandardError # we don't uncaught errors looping filesets
21
- Hyrax.logger.warn "Failed to delete #{file_set.class}:#{file_set.id} " \
22
- "during cleanup for resource: #{event[:object]}. " \
23
- 'This member may now be orphaned.'
24
- end
16
+ Hyrax.persister.delete(resource: file_set)
17
+ Hyrax.publisher
18
+ .publish('object.deleted', object: file_set, id: file_set.id, user: event[:user])
19
+ rescue StandardError # we don't uncaught errors looping filesets
20
+ Hyrax.logger.warn "Failed to delete #{file_set.class}:#{file_set.id} " \
21
+ "during cleanup for resource: #{event[:object]}. " \
22
+ 'This member may now be orphaned.'
25
23
  end
26
24
  end
27
25
 
@@ -33,15 +31,13 @@ module Hyrax
33
31
  return if event[:collection].is_a?(ActiveFedora::Base) # handled by legacy code
34
32
 
35
33
  Hyrax.custom_queries.find_members_of(collection: event[:collection]).each do |resource|
36
- begin
37
- resource.member_of_collection_ids -= [event[:collection].id]
38
- Hyrax.persister.save(resource: resource)
39
- Hyrax.publisher
40
- .publish('collection.membership.updated', collection: event[:collection], user: event[:user])
41
- rescue StandardError
42
- Hyrax.logger.warn "Failed to remove collection reference from #{work.class}:#{work.id} " \
43
- "during cleanup for collection: #{event[:collection]}. "
44
- end
34
+ resource.member_of_collection_ids -= [event[:collection].id]
35
+ Hyrax.persister.save(resource: resource)
36
+ Hyrax.publisher
37
+ .publish('collection.membership.updated', collection: event[:collection], user: event[:user])
38
+ rescue StandardError
39
+ Hyrax.logger.warn "Failed to remove collection reference from #{work.class}:#{work.id} " \
40
+ "during cleanup for collection: #{event[:collection]}. "
45
41
  end
46
42
  end
47
43
  end
@@ -21,7 +21,9 @@ module Hyrax
21
21
  # also belong to other collections of the same type.
22
22
  #
23
23
  # @return [True, String] true if no conflicts; otherwise, an error message string
24
+ # @deprecated Use #check instead; for removal in 4.0.0
24
25
  def validate
26
+ Deprecation.warn "#{self.class}##{__method__} is deprecated; use #check instead."
25
27
  return true if item.member_of_collection_ids.empty? || item.member_of_collection_ids.count <= 1
26
28
  return true unless single_membership_collection_types_exist?
27
29
 
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ class ValkyriePersistDerivatives < Hydra::Derivatives::PersistOutputFileService
4
+ # Persists a derivative using the defined Valkyrie storage adapter
5
+ #
6
+ # This Service conforms to the signature of `Hydra::Derivatives::PersistOutputFileService`.
7
+ # This service is a Valkyrized alternative to the default Hydra::Derivatives::PersistOutputFileService.
8
+ # This service will always update existing and does not do versioning of persisted files.
9
+ #
10
+ # to replace the default AF derivative pipeline, set
11
+ # ```
12
+ # Hydra::Derivatives.config.output_file_service = Hyrax::ValkyriePersistDerivatives
13
+ # Hydra::Derivatives.config.source_file_service = Hyrax::LocalFileService
14
+ # ```
15
+ #
16
+ # @param [#read] stream the derivative filestream
17
+ # @param [Hash] directives
18
+ # @option directives [String] :url a url to the file destination
19
+ def self.call(stream, directives)
20
+ filepath = URI(directives.fetch(:url)).path
21
+ fileset_id = fileset_id_from_path(filepath)
22
+ fileset = Hyrax.metadata_adapter.query_service.find_by(id: fileset_id)
23
+
24
+ # Valkyrie storage adapters will typically expect an IO-like object that
25
+ # responds to #path -- here we only have a StringIO, so some
26
+ # transformation is in order
27
+ tmpfile = Tempfile.new(fileset_id, encoding: 'ascii-8bit')
28
+ tmpfile.write stream.read
29
+
30
+ Rails.logger.debug "Uploading thumbnail for FileSet #{fileset_id} as #{filepath}"
31
+ Hyrax.config.derivatives_storage_adapter.upload(
32
+ file: tmpfile,
33
+ original_filename: filepath,
34
+ resource: fileset
35
+ )
36
+ end
37
+
38
+ # The filepath will look something like
39
+ # /app/samvera/hyrax-webapp/derivatives/95/93/tv/12/3-thumbnail.jpeg and
40
+ # we want to extract the FileSet id, which in this case would be 9593tv123
41
+ #
42
+ # @param [String] path
43
+ # @return [String]
44
+ def self.fileset_id_from_path(path)
45
+ path.sub(Hyrax.config.derivatives_path.to_s, "")
46
+ .sub(/-[^\/]+\..*$/, "")
47
+ .delete("/")
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax::ValkyrieUpload
4
+ # @param [IO] io
5
+ # @param [String] filename
6
+ # @param [Hyrax::FileSet] file_set
7
+ # @param [RDF::URI] use
8
+ # @param [User] user
9
+ #
10
+ # @see Hyrax::FileMetadata::Use
11
+ # @return [Hyrax::FileMetadata] the metadata representing the uploaded file
12
+ # rubocop:disable Metrics/MethodLength
13
+ # rubocop:disable Metrics/ParameterLists
14
+ def self.file(
15
+ filename:,
16
+ file_set:,
17
+ io:,
18
+ storage_adapter: Hyrax.storage_adapter,
19
+ use: Hyrax::FileMetadata::Use::ORIGINAL_FILE,
20
+ user: nil
21
+ )
22
+
23
+ streamfile = storage_adapter.upload(
24
+ file: io,
25
+ original_filename: filename,
26
+ resource: file_set,
27
+ use: use
28
+ )
29
+ io.close
30
+
31
+ file_metadata = Hyrax::FileMetadata(streamfile)
32
+ file_metadata.file_set_id = file_set.id
33
+
34
+ case use
35
+ when Hyrax::FileMetadata::Use::ORIGINAL_FILE
36
+ # Set file set label.
37
+ reset_title = file_set.title.first == file_set.label
38
+ # set title to label if that's how it was before this characterization
39
+ file_set.title = file_metadata.original_filename if reset_title
40
+ # always set the label to the original_name
41
+ file_set.label = file_metadata.original_filename
42
+ when Hyrax::FileMetadata::Use::THUMBNAIL
43
+ # TODO: the parent work's thumbnail_id remains incorrect (it's set to the
44
+ # FileSet ID, rather than the ID of this thumbnail FileMetadata; but
45
+ # trying to update the parent attributes here doesn't seem to stick
46
+ file_set.thumbnail_id = file_metadata.id
47
+ end
48
+
49
+ saved_metadata = Hyrax.persister.save(resource: file_metadata)
50
+ Hyrax.publisher.publish("object.file.uploaded", metadata: saved_metadata)
51
+
52
+ add_file_to_file_set(file_set: file_set,
53
+ file_metadata: saved_metadata,
54
+ user: user)
55
+
56
+ Hyrax.publisher.publish('file.metadata.updated', metadata: saved_metadata, user: user)
57
+
58
+ saved_metadata
59
+ end
60
+
61
+ # @param [Hyrax::FileSet] file_set the file set to add to
62
+ # @param [Hyrax::FileMetadata] file_metadata the metadata object representing
63
+ # the file to add
64
+ # @param [::User] user the user performing the add
65
+ #
66
+ # @return [Hyrax::FileSet] updated file set
67
+ def self.add_file_to_file_set(file_set:, file_metadata:, user:)
68
+ file_set.file_ids << file_metadata.id
69
+ set_file_use_ids(file_set, file_metadata)
70
+
71
+ Hyrax.persister.save(resource: file_set)
72
+ Hyrax.publisher.publish('object.membership.updated', object: file_set, user: user)
73
+ end
74
+
75
+ # @api private
76
+ # @param [Hyrax::FileSet] file_set the file set to add to
77
+ # @param [Hyrax::FileMetadata] file_metadata the metadata object representing
78
+ # the file to add
79
+ # @return [void]
80
+ def self.set_file_use_ids(file_set, file_metadata)
81
+ file_metadata.type.each do |type|
82
+ case type
83
+ when Hyrax::FileMetadata::Use::ORIGINAL_FILE
84
+ file_set.original_file_id = file_metadata.id
85
+ when Hyrax::FileMetadata::Use::THUMBNAIL
86
+ file_set.thumbnail_id = file_metadata.id
87
+ when Hyrax::FileMetadata::Use::EXTRACTED_TEXT
88
+ file_set.extracted_text_id = file_metadata.id
89
+ else
90
+ Rails.logger.warn "Unknown file use #{file_metadata.type} specified for #{file_metadata.file_identifier}"
91
+ end
92
+ end
93
+ end
94
+ end
@@ -128,16 +128,14 @@ module Hyrax
128
128
  def call
129
129
  self.errors = []
130
130
  Array.wrap(data.fetch(:workflows)).map do |configuration|
131
- begin
132
- find_or_create_from(configuration: configuration)
133
- rescue InvalidStateRemovalException => e
134
- e.states.each do |state|
135
- error = I18n.t('hyrax.workflow.load.state_error', workflow_name: state.workflow.name, state_name: state.name, entity_count: state.entities.count)
136
- Rails.logger.error(error)
137
- errors << error
138
- end
139
- Sipity::Workflow.find_by(name: configuration[:name])
131
+ find_or_create_from(configuration: configuration)
132
+ rescue InvalidStateRemovalException => e
133
+ e.states.each do |state|
134
+ error = I18n.t('hyrax.workflow.load.state_error', workflow_name: state.workflow.name, state_name: state.name, entity_count: state.entities.count)
135
+ Rails.logger.error(error)
136
+ errors << error
140
137
  end
138
+ Sipity::Workflow.find_by(name: configuration[:name])
141
139
  end
142
140
  end
143
141
 
@@ -20,11 +20,9 @@ module Hyrax
20
20
  include Dry::Types()
21
21
 
22
22
  Constant = Types::Class.constructor do |v|
23
- begin
24
- v.constantize
25
- rescue NameError => _err
26
- v
27
- end
23
+ v.constantize
24
+ rescue NameError => _err
25
+ v
28
26
  end
29
27
  end
30
28
 
@@ -34,12 +34,10 @@ module Hyrax::Strategies
34
34
 
35
35
  def yaml_file
36
36
  @yaml_file ||=
37
- begin
38
- if File.exist?(@config_file)
39
- YAML.load_file(@config_file)
40
- else
41
- {}
42
- end
37
+ if File.exist?(@config_file)
38
+ YAML.load_file(@config_file)
39
+ else
40
+ {}
43
41
  end
44
42
  end
45
43
  end
@@ -4,21 +4,21 @@ module Hyrax
4
4
  # Override the directory where uploaded files will be stored.
5
5
  # This is a sensible default for uploaders that are meant to be mounted:
6
6
  def store_dir
7
- configured_upload_path + "#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
7
+ (configured_upload_path / model.class.to_s.underscore / mounted_as.to_s / model.id.to_s).to_s
8
8
  end
9
9
 
10
10
  def cache_dir
11
- configured_cache_path + "#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
11
+ (configured_cache_path / model.class.to_s.underscore / mounted_as.to_s / model.id.to_s).to_s
12
12
  end
13
13
 
14
14
  private
15
15
 
16
16
  def configured_upload_path
17
- Hyrax.config.upload_path.call
17
+ Pathname.new(Hyrax.config.upload_path.call)
18
18
  end
19
19
 
20
20
  def configured_cache_path
21
- Hyrax.config.cache_path.call
21
+ Pathname.new(Hyrax.config.cache_path.call)
22
22
  end
23
23
  end
24
24
  end
@@ -1,30 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
  module Hyrax
3
- # Validates that the record passes the multiple membership checker
3
+ ##
4
+ # Validates that the record passes the multiple membership requirements for collections.
4
5
  class CollectionMembershipValidator < ActiveModel::Validator
5
- def validate(record)
6
- update_collections(record)
7
- validation = validate_multi_membership(record)
8
- return if validation == true
9
- record.errors[:member_of_collection_ids] << validation
6
+ ##
7
+ # @param multiple_membership_checker
8
+ def initialize(multiple_membership_checker: Hyrax::MultipleMembershipChecker, **options)
9
+ @multiple_membership_checker = multiple_membership_checker
10
+ super(options)
10
11
  end
11
12
 
12
- private
13
-
14
- def validate_multi_membership(record)
13
+ def validate(record)
15
14
  # collections-in-collections do not have multi-membership restrictions
16
15
  return true if record.is_a? Hyrax::Forms::PcdmCollectionForm
16
+ checker = @multiple_membership_checker.new(item: nil)
17
+ ids = collections_ids(record)
17
18
 
18
- Hyrax::MultipleMembershipChecker.new(item: record).validate
19
+ errors = Array(checker.check(collection_ids: ids))
20
+ record.errors[:member_of_collection_ids].concat(errors)
19
21
  end
20
22
 
21
- def update_collections(record)
22
- record.member_of_collection_ids = collections_ids(record)
23
- record.member_of_collection_ids.uniq!
24
- end
23
+ private
25
24
 
26
25
  def collections_ids(record)
27
- collection_ids = []
26
+ collection_ids = record.member_of_collection_ids.reject(&:blank?)
27
+
28
28
  if record.member_of_collections_attributes.present?
29
29
  record.member_of_collections_attributes
30
30
  .each do |_k, h|
@@ -32,6 +32,7 @@ module Hyrax
32
32
  collection_ids << Valkyrie::ID.new(h["id"])
33
33
  end
34
34
  end
35
+
35
36
  collection_ids
36
37
  end
37
38
  end
@@ -1,3 +1,10 @@
1
+ <% model = document.hydra_model %>
1
2
  <div class="search-results-title-row">
2
- <h3 class="search-result-title"><%= link_to document.title_or_label, document %></h3>
3
+ <% if model == Hyrax::PcdmCollection || model < Hyrax::PcdmCollection %>
4
+ <h3 class="search-result-title"><%= link_to document.title_or_label, [hyrax, document] %></h3>
5
+ <%= Hyrax::CollectionPresenter.new(document, current_ability).collection_type_badge %>
6
+ <% else %>
7
+ <h3 class="search-result-title"><%= link_to document.title_or_label, document %></h3>
8
+ <% end %>
3
9
  </div>
10
+
@@ -1,5 +1,10 @@
1
+ <% model = document.hydra_model %>
1
2
  <div class="col-md-2">
2
- <div class="list-thumbnail">
3
- <%= render_thumbnail_tag document %>
4
- </div>
3
+ <% if model == Hyrax::PcdmCollection || model < Hyrax::PcdmCollection %>
4
+ <%= render_thumbnail_tag document, {}, suppress_link: true %>
5
+ <% else %>
6
+ <div class="list-thumbnail">
7
+ <%= render_thumbnail_tag document %>
8
+ </div>
9
+ <% end %>
5
10
  </div>
@@ -1,8 +1,8 @@
1
1
  <%= f.input key,
2
- as: :multi_value,
3
- input_html: {
4
- class: 'form-control',
5
- data: { 'autocomplete-url' => "/authorities/search/geonames",
6
- 'autocomplete' => key }
7
- },
8
- required: f.object.required?(key) %>
2
+ as: :multi_value,
3
+ input_html: {
4
+ class: 'form-control',
5
+ data: { 'autocomplete-url' => "/authorities/search/geonames",
6
+ 'autocomplete' => key }
7
+ },
8
+ required: f.object.required?(key) %>