hyrax 3.4.1 → 3.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +26 -17
- data/.dassie/.env +1 -1
- data/.dassie/Gemfile +1 -1
- data/.dassie/app/forms/collection_resource_form.rb +8 -0
- data/.dassie/app/indexers/collection_resource_indexer.rb +8 -0
- data/.dassie/app/models/collection_resource.rb +35 -0
- data/.dassie/config/initializers/file_services.rb +4 -0
- data/.dassie/config/initializers/hyrax.rb +2 -1
- data/.dassie/config/metadata/collection_resource.yaml +23 -0
- data/.dassie/db/seeds.rb +2 -0
- data/.dassie/spec/forms/collection_resource_form_spec.rb +13 -0
- data/.dassie/spec/indexers/collection_resource_indexer_spec.rb +14 -0
- data/.dassie/spec/models/collection_resource_spec.rb +13 -0
- data/.regen +1 -1
- data/.rubocop.yml +1 -1
- data/.rubocop_fixme.yml +19 -2
- data/CONTAINERS.md +18 -13
- data/Dockerfile +2 -2
- data/app/assets/javascripts/hyrax/collections_v2.es6 +13 -0
- data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +1 -3
- data/app/controllers/hyrax/dashboard/collections_controller.rb +159 -75
- data/app/controllers/hyrax/single_use_links_viewer_controller.rb +1 -1
- data/app/forms/hyrax/forms/collection_form.rb +1 -1
- data/app/forms/hyrax/forms/pcdm_collection_form.rb +29 -2
- data/app/forms/hyrax/forms/resource_form.rb +15 -1
- data/app/forms/hyrax/forms/widgets/admin_set_visibility.rb +1 -1
- data/app/indexers/hyrax/pcdm_collection_indexer.rb +0 -1
- data/app/jobs/characterize_job.rb +5 -1
- data/app/jobs/import_url_job.rb +4 -6
- data/app/jobs/valkyrie_ingest_job.rb +15 -77
- data/app/models/admin_set.rb +8 -0
- data/app/models/concerns/hyrax/collection_behavior.rb +1 -1
- data/app/models/concerns/hyrax/user.rb +11 -0
- data/app/models/concerns/hyrax/work_behavior.rb +1 -1
- data/app/models/featured_work_list.rb +0 -1
- data/app/models/hyrax/file_metadata.rb +32 -2
- data/app/models/hyrax/file_set.rb +1 -3
- data/app/models/hyrax/group.rb +19 -0
- data/app/models/hyrax/pcdm_collection.rb +0 -1
- data/app/models/job_io_wrapper.rb +1 -1
- data/app/presenters/hyrax/member_presenter_factory.rb +2 -4
- data/app/presenters/hyrax/work_show_presenter.rb +3 -3
- data/app/services/hyrax/access_control_list.rb +7 -6
- data/app/services/hyrax/adapters/nesting_index_adapter.rb +3 -3
- data/app/services/hyrax/characterization/valkyrie_characterization_service.rb +3 -5
- data/app/services/hyrax/collections/collection_member_service.rb +3 -5
- data/app/services/hyrax/listeners/file_metadata_listener.rb +11 -0
- data/app/services/hyrax/listeners/member_cleanup_listener.rb +14 -18
- data/app/services/hyrax/multiple_membership_checker.rb +2 -0
- data/app/services/hyrax/valkyrie_persist_derivatives.rb +50 -0
- data/app/services/hyrax/valkyrie_upload.rb +94 -0
- data/app/services/hyrax/workflow/workflow_importer.rb +7 -9
- data/app/services/hyrax/workflow/workflow_schema.rb +3 -5
- data/app/strategies/hyrax/strategies/yaml_strategy.rb +4 -6
- data/app/uploaders/hyrax/uploaded_file_uploader.rb +4 -4
- data/app/validators/hyrax/collection_membership_validator.rb +16 -15
- data/app/views/catalog/_index_header_list_default.html.erb +8 -1
- data/app/views/catalog/_thumbnail_list_default.html.erb +8 -3
- data/app/views/collections/edit_fields/_based_near.html.erb +7 -7
- data/app/views/hyrax/dashboard/collections/_form.html.erb +3 -2
- data/app/views/hyrax/dashboard/collections/_form_branding.html.erb +1 -0
- data/app/views/hyrax/dashboard/sidebar/_activity.html.erb +1 -1
- data/app/views/hyrax/my/works/_tabs.html.erb +6 -1
- data/chart/hyrax/Chart.yaml +10 -6
- data/chart/hyrax/templates/_helpers.tpl +4 -0
- data/chart/hyrax/templates/cron-embargo.yaml +5 -0
- data/chart/hyrax/templates/cron-lease.yaml +5 -0
- data/chart/hyrax/templates/deployment-worker.yaml +11 -0
- data/chart/hyrax/templates/ingress.yaml +7 -6
- data/chart/hyrax/values.yaml +152 -0
- data/config/features.rb +48 -50
- data/config/initializers/{valkryrie_storage.rb → storage_adapter_initializer.rb} +5 -0
- data/config/locales/hyrax.de.yml +12 -12
- data/docker-compose.yml +1 -0
- data/documentation/developing-your-hyrax-based-app.md +1 -1
- data/documentation/legacyREADME.md +1 -1
- data/hyrax.gemspec +5 -3
- data/lib/generators/hyrax/collection_resource/USAGE +20 -0
- data/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +133 -0
- data/lib/generators/hyrax/collection_resource/templates/collection.rb.erb +34 -0
- data/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +7 -0
- data/lib/generators/hyrax/collection_resource/templates/collection_form_spec.rb.erb +13 -0
- data/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +7 -0
- data/lib/generators/hyrax/collection_resource/templates/collection_indexer_spec.rb.erb +13 -0
- data/lib/generators/hyrax/collection_resource/templates/collection_metadata.yaml +22 -0
- data/lib/generators/hyrax/collection_resource/templates/collection_spec.rb.erb +12 -0
- data/lib/generators/hyrax/install_generator.rb +9 -0
- data/lib/hyrax/configuration.rb +12 -0
- data/lib/hyrax/publisher.rb +4 -0
- data/lib/hyrax/specs/shared_specs/hydra_works.rb +0 -1
- data/lib/hyrax/transactions/collection_update.rb +2 -0
- data/lib/hyrax/transactions/container.rb +10 -0
- data/lib/hyrax/transactions/steps/save_collection_banner.rb +59 -0
- data/lib/hyrax/transactions/steps/save_collection_logo.rb +109 -0
- data/lib/hyrax/version.rb +1 -1
- data/lib/wings/active_fedora_converter/file_metadata_node.rb +48 -0
- data/lib/wings/active_fedora_converter/instance_builder.rb +68 -0
- data/lib/wings/active_fedora_converter.rb +3 -3
- data/lib/wings/services/custom_queries/find_file_metadata.rb +19 -8
- data/lib/wings/valkyrie/query_service.rb +4 -6
- data/template.rb +1 -1
- metadata +63 -13
- 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
|
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
|
-
|
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 ||=
|
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
|
data/app/models/hyrax/group.rb
CHANGED
@@ -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? #
|
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 ||=
|
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
|
-
|
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
|
158
|
-
grouped.select! { |obj| obj.
|
159
|
-
grouped.except
|
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
|
-
|
205
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
|
@@ -34,12 +34,10 @@ module Hyrax::Strategies
|
|
34
34
|
|
35
35
|
def yaml_file
|
36
36
|
@yaml_file ||=
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
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
|
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
|
-
|
3
|
+
##
|
4
|
+
# Validates that the record passes the multiple membership requirements for collections.
|
4
5
|
class CollectionMembershipValidator < ActiveModel::Validator
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
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
|
-
|
19
|
+
errors = Array(checker.check(collection_ids: ids))
|
20
|
+
record.errors[:member_of_collection_ids].concat(errors)
|
19
21
|
end
|
20
22
|
|
21
|
-
|
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
|
-
|
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
|
-
<
|
3
|
-
<%= render_thumbnail_tag document %>
|
4
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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) %>
|