hyrax 3.4.1 → 3.5.0
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/actors/hyrax/actors/collections_membership_actor.rb +1 -1
- data/app/actors/hyrax/actors/embargo_actor.rb +11 -4
- data/app/actors/hyrax/actors/lease_actor.rb +11 -4
- data/app/assets/javascripts/hyrax/app.js.erb +1 -1
- data/app/assets/javascripts/hyrax/collections_v2.es6 +13 -0
- data/app/assets/javascripts/hyrax/permissions/control.es6 +8 -1
- data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +1 -3
- data/app/controllers/concerns/hyrax/embargoes_controller_behavior.rb +11 -2
- data/app/controllers/concerns/hyrax/leases_controller_behavior.rb +11 -2
- data/app/controllers/concerns/hyrax/manages_embargoes.rb +13 -1
- data/app/controllers/hyrax/dashboard/collections_controller.rb +159 -76
- data/app/controllers/hyrax/downloads_controller.rb +16 -1
- data/app/controllers/hyrax/file_sets_controller.rb +10 -1
- data/app/controllers/hyrax/permissions_controller.rb +1 -1
- data/app/controllers/hyrax/single_use_links_viewer_controller.rb +1 -1
- data/app/controllers/hyrax/transfers_controller.rb +0 -2
- data/app/controllers/hyrax/workflow_actions_controller.rb +3 -2
- data/app/forms/hyrax/forms/collection_form.rb +1 -1
- data/app/forms/hyrax/forms/dashboard/nest_collection_form.rb +2 -0
- data/app/forms/hyrax/forms/embargo.rb +13 -0
- data/app/forms/hyrax/forms/file_set_edit_form.rb +1 -1
- data/app/forms/hyrax/forms/file_set_form.rb +8 -35
- data/app/forms/hyrax/forms/lease.rb +13 -0
- data/app/forms/hyrax/forms/pcdm_collection_form.rb +29 -2
- data/app/forms/hyrax/forms/pcdm_object_form.rb +46 -0
- data/app/forms/hyrax/forms/resource_form.rb +39 -21
- data/app/forms/hyrax/forms/widgets/admin_set_visibility.rb +1 -1
- data/app/forms/hyrax/forms/work_embargo_form.rb +35 -0
- data/app/forms/hyrax/forms/work_lease_form.rb +35 -0
- data/app/helpers/hyrax/embargo_helper.rb +11 -0
- data/app/helpers/hyrax/lease_helper.rb +11 -0
- data/app/indexers/hyrax/pcdm_collection_indexer.rb +1 -1
- data/app/indexers/hyrax/valkyrie_file_set_indexer.rb +2 -8
- data/app/jobs/characterize_job.rb +5 -1
- data/app/jobs/content_event_job.rb +1 -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 +3 -2
- data/app/models/concerns/hyrax/collection_nesting.rb +10 -1
- data/app/models/concerns/hyrax/file_set_behavior.rb +1 -0
- data/app/models/concerns/hyrax/user.rb +11 -0
- data/app/models/concerns/hyrax/work_behavior.rb +3 -2
- data/app/models/featured_work_list.rb +0 -1
- data/app/models/hyrax/embargo.rb +1 -1
- data/app/models/hyrax/file_metadata.rb +32 -2
- data/app/models/hyrax/file_set.rb +4 -6
- data/app/models/hyrax/group.rb +19 -0
- data/app/models/hyrax/lease.rb +1 -1
- data/app/models/hyrax/pcdm_collection.rb +0 -1
- data/app/models/job_io_wrapper.rb +1 -1
- data/app/models/proxy_deposit_request.rb +1 -1
- data/app/presenters/hyrax/member_presenter_factory.rb +2 -4
- data/app/presenters/hyrax/permission_badge.rb +3 -2
- data/app/presenters/hyrax/version_list_presenter.rb +6 -1
- data/app/presenters/hyrax/work_show_presenter.rb +3 -3
- data/app/search_builders/hyrax/dashboard/nested_collections_search_builder.rb +13 -5
- 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/collections/nested_collection_query_service.rb +1 -1
- data/app/services/hyrax/edit_permissions_service.rb +21 -3
- data/app/services/hyrax/embargo_manager.rb +9 -0
- data/app/services/hyrax/file_set_file_service.rb +55 -0
- data/app/services/hyrax/lease_manager.rb +9 -0
- 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/user_stat_importer.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/versioning_service.rb +77 -9
- data/app/services/hyrax/visibility_propagator.rb +5 -5
- data/app/services/hyrax/work_resource_query_service.rb +45 -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/base/_form_progress.html.erb +1 -1
- data/app/views/hyrax/base/_form_visibility_component.html.erb +5 -1
- 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/embargoes/edit.html.erb +3 -3
- data/app/views/hyrax/file_sets/_permission.html.erb +1 -1
- data/app/views/hyrax/file_sets/_permission_form.html.erb +1 -6
- data/app/views/hyrax/file_sets/edit.html.erb +2 -2
- data/app/views/hyrax/leases/edit.html.erb +3 -3
- data/app/views/hyrax/my/works/_tabs.html.erb +6 -1
- data/app/views/hyrax/transfers/new.html.erb +1 -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 +14 -13
- data/config/locales/hyrax.en.yml +3 -0
- data/config/locales/hyrax.es.yml +1 -0
- data/config/locales/hyrax.fr.yml +2 -1
- data/config/locales/hyrax.it.yml +1 -0
- data/config/locales/hyrax.pt-BR.yml +1 -0
- data/config/locales/hyrax.zh.yml +1 -0
- data/config/metadata/file_set_metadata.yaml +130 -0
- data/docker-compose.yml +1 -0
- data/documentation/developing-your-hyrax-based-app.md +2 -2
- data/documentation/legacyREADME.md +3 -3
- data/hyrax.gemspec +7 -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/generators/hyrax/templates/config/locales/hyrax.de.yml +1 -1
- data/lib/generators/hyrax/templates/config/locales/hyrax.en.yml +1 -1
- data/lib/generators/hyrax/templates/config/locales/hyrax.es.yml +1 -1
- data/lib/generators/hyrax/templates/config/locales/hyrax.fr.yml +1 -1
- data/lib/generators/hyrax/templates/config/locales/hyrax.it.yml +1 -1
- data/lib/generators/hyrax/templates/config/locales/hyrax.zh.yml +1 -1
- data/lib/hyrax/active_fedora_dummy_model.rb +13 -0
- data/lib/hyrax/configuration.rb +21 -2
- data/lib/hyrax/errors.rb +2 -0
- data/lib/hyrax/publisher.rb +4 -0
- data/lib/hyrax/specs/shared_specs/factories/strategies/valkyrie_resource.rb +6 -0
- data/lib/hyrax/specs/shared_specs/hydra_works.rb +0 -1
- data/lib/hyrax/specs/shared_specs/indexers.rb +5 -0
- 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/lib/wings/valkyrie/storage.rb +6 -2
- data/template.rb +1 -1
- metadata +99 -13
- data/app/views/catalog/_index_header_list_hyrax_pcdm_collection.html.erb +0 -4
@@ -31,12 +31,10 @@ module Hyrax
|
|
31
31
|
# @see https://wiki.duraspace.org/display/samvera/Hydra%3A%3AWorks+Shared+Modeling
|
32
32
|
class FileSet < Hyrax::Resource
|
33
33
|
include Hyrax::Schema(:core_metadata)
|
34
|
-
include Hyrax::Schema(:
|
34
|
+
include Hyrax::Schema(:file_set_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
|
@@ -44,8 +42,8 @@ module Hyrax
|
|
44
42
|
|
45
43
|
attribute :file_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID) # id for FileMetadata resources
|
46
44
|
attribute :thumbnail_id, Valkyrie::Types::ID.optional # id for FileMetadata resource
|
47
|
-
attribute :original_file_id, Valkyrie::Types::ID # id for FileMetadata resource
|
48
|
-
attribute :extracted_text_id, Valkyrie::Types::ID # id for FileMetadata resource
|
45
|
+
attribute :original_file_id, Valkyrie::Types::ID.optional # id for FileMetadata resource
|
46
|
+
attribute :extracted_text_id, Valkyrie::Types::ID.optional # id for FileMetadata resource
|
49
47
|
|
50
48
|
##
|
51
49
|
# @return [Valkyrie::ID]
|
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
|
data/app/models/hyrax/lease.rb
CHANGED
@@ -15,7 +15,7 @@ module Hyrax
|
|
15
15
|
attribute :lease_history, Valkyrie::Types::Array
|
16
16
|
|
17
17
|
def active?
|
18
|
-
(lease_expiration_date.present? &&
|
18
|
+
(lease_expiration_date.present? && Hyrax::TimeService.time_in_utc < lease_expiration_date)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
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
|
|
@@ -7,7 +7,7 @@ class ProxyDepositRequest < ActiveRecord::Base
|
|
7
7
|
include ActionView::Helpers::UrlHelper
|
8
8
|
|
9
9
|
class_attribute :work_query_service_class
|
10
|
-
self.work_query_service_class = Hyrax::WorkQueryService
|
10
|
+
self.work_query_service_class = Hyrax.config.use_valkyrie? ? Hyrax::WorkResourceQueryService : Hyrax::WorkQueryService
|
11
11
|
|
12
12
|
delegate :deleted_work?, :work, :to_s, to: :work_query_service
|
13
13
|
|
@@ -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
|
@@ -24,14 +24,15 @@ module Hyrax
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def dom_label_class
|
27
|
-
VISIBILITY_LABEL_CLASS.fetch(@visibility
|
27
|
+
VISIBILITY_LABEL_CLASS.fetch(@visibility&.to_sym, 'label-info')
|
28
28
|
end
|
29
29
|
|
30
30
|
def text
|
31
31
|
if registered?
|
32
32
|
Institution.name
|
33
33
|
else
|
34
|
-
|
34
|
+
visibility_key = @visibility || 'unknown'
|
35
|
+
I18n.t("hyrax.visibility.#{visibility_key}.text")
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
@@ -19,7 +19,12 @@ module Hyrax
|
|
19
19
|
#
|
20
20
|
# @raise [ArgumentError] if we can't build an enu
|
21
21
|
def self.for(file_set:)
|
22
|
-
|
22
|
+
original_file = if file_set.respond_to?(:original_file)
|
23
|
+
file_set.original_file
|
24
|
+
else
|
25
|
+
Hyrax::FileSetFileService.new(file_set: file_set).original_file
|
26
|
+
end
|
27
|
+
new(Hyrax::VersioningService.new(resource: original_file).versions)
|
23
28
|
rescue NoMethodError
|
24
29
|
raise ArgumentError
|
25
30
|
end
|
@@ -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
|
|
@@ -26,11 +26,19 @@ module Hyrax
|
|
26
26
|
|
27
27
|
def show_only_other_collections_of_the_same_collection_type(solr_parameters)
|
28
28
|
solr_parameters[:fq] ||= []
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
if Hyrax.config.use_solr_graph_for_collection_nesting
|
30
|
+
solr_parameters[:fq] += [
|
31
|
+
Hyrax::SolrQueryBuilderService.construct_query(Hyrax.config.collection_type_index_field => @collection.collection_type_gid),
|
32
|
+
"-{!graph from=id to=member_of_collection_ids_ssim#{' maxDepth=1' if @nest_direction == :as_parent}}id:#{@collection.id}",
|
33
|
+
"-{!graph to=id from=member_of_collection_ids_ssim#{' maxDepth=1' if @nest_direction == :as_child}}id:#{@collection.id}"
|
34
|
+
]
|
35
|
+
else
|
36
|
+
solr_parameters[:fq] += [
|
37
|
+
"-" + Hyrax::SolrQueryBuilderService.construct_query_for_ids([limit_ids]),
|
38
|
+
Hyrax::SolrQueryBuilderService.construct_query(Hyrax.config.collection_type_index_field => @collection.collection_type_gid)
|
39
|
+
]
|
40
|
+
solr_parameters[:fq] += limit_clause if limit_clause # add limits to prevent illegal nesting arrangements
|
41
|
+
end
|
34
42
|
end
|
35
43
|
|
36
44
|
private
|
@@ -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
|
@@ -86,7 +86,7 @@ module Hyrax
|
|
86
86
|
# id is in the response. Useful for validation.
|
87
87
|
# @param nest_direction [Symbol] :as_child or :as_parent
|
88
88
|
def self.query_solr(collection:, access:, scope:, limit_to_id:, nest_direction:)
|
89
|
-
nesting_attributes = NestingAttributes.new(id: collection.id.to_s, scope: scope)
|
89
|
+
nesting_attributes = (Hyrax.config.use_solr_graph_for_collection_nesting ? nil : NestingAttributes.new(id: collection.id.to_s, scope: scope))
|
90
90
|
query_builder = Hyrax::Dashboard::NestedCollectionsSearchBuilder.new(
|
91
91
|
access: access,
|
92
92
|
collection: collection,
|
@@ -20,17 +20,35 @@ module Hyrax
|
|
20
20
|
# @note
|
21
21
|
# +form object.class = SimpleForm::FormBuilder+
|
22
22
|
# For works (i.e. GenericWork):
|
23
|
-
# *
|
24
|
-
# *
|
23
|
+
# * form_object.object = Hyrax::GenericWorkForm
|
24
|
+
# * form_object.object.model = GenericWork
|
25
25
|
# * use the work itself
|
26
26
|
# For file_sets:
|
27
|
-
# *
|
27
|
+
# * form_object.object.class = FileSet
|
28
|
+
# * use work the file_set is in
|
29
|
+
# For file set forms:
|
30
|
+
# * form_object.object.class = Hyrax::Forms::FileSetForm OR
|
31
|
+
# Hyrax::Forms::FileSetEditForm
|
32
|
+
# * form_object.object.model = FileSet
|
28
33
|
# * use work the file_set is in
|
29
34
|
# No other object types are supported by this view.
|
30
35
|
def self.build_service_object_from(form:, ability:)
|
31
36
|
if form.object.respond_to?(:model) && form.object.model.work?
|
37
|
+
# The provided form object is a work form.
|
32
38
|
new(object: form.object, ability: ability)
|
39
|
+
elsif form.object.respond_to?(:model) && form.object.model.file_set?
|
40
|
+
# The provided form object is a FileSet form. For Valkyrie forms
|
41
|
+
# (+Hyrax::Forms::FileSetForm+), +:in_works_ids+ is prepopulated onto
|
42
|
+
# the form object itself. For +Hyrax::Forms::FileSetEditForm+, the
|
43
|
+
# +:in_works+ method is present on the wrapped +:model+.
|
44
|
+
if form.object.is_a?(Hyrax::Forms::FileSetForm)
|
45
|
+
object_id = form.object.in_works_ids.first
|
46
|
+
new(object: Hyrax.query_service.find_by(id: object_id), ability: ability)
|
47
|
+
else
|
48
|
+
new(object: form.object.model.in_works.first, ability: ability)
|
49
|
+
end
|
33
50
|
elsif form.object.file_set?
|
51
|
+
# The provided form object is a FileSet.
|
34
52
|
new(object: form.object.in_works.first, ability: ability)
|
35
53
|
end
|
36
54
|
end
|
@@ -161,6 +161,15 @@ module Hyrax
|
|
161
161
|
resource.embargo || Embargo.new
|
162
162
|
end
|
163
163
|
|
164
|
+
##
|
165
|
+
# Drop the embargo by setting its release date to `nil`.
|
166
|
+
#
|
167
|
+
# @return [void]
|
168
|
+
def nullify
|
169
|
+
return unless under_embargo?
|
170
|
+
embargo.embargo_release_date = nil
|
171
|
+
end
|
172
|
+
|
164
173
|
##
|
165
174
|
# Sets the visibility of the resource to the embargo's visibility condition.
|
166
175
|
# no-op if the embargo period is current.
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hyrax
|
4
|
+
##
|
5
|
+
# A service for accessing specific Hyrax::FileMetadata objects referenced by a
|
6
|
+
# Hyrax::FileSet.
|
7
|
+
class FileSetFileService
|
8
|
+
##
|
9
|
+
# @!attribute [r] file_set
|
10
|
+
# @return [Hyrax::FileSet]
|
11
|
+
attr_reader :file_set
|
12
|
+
|
13
|
+
##
|
14
|
+
# @!attribute [r] query_service
|
15
|
+
# @return [#find_by]
|
16
|
+
attr_reader :query_service
|
17
|
+
|
18
|
+
##
|
19
|
+
# @param resource [Hyrax::FileSet]
|
20
|
+
def initialize(file_set:, query_service: Hyrax.query_service)
|
21
|
+
@query_service = query_service
|
22
|
+
@file_set = file_set
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Return the Hyrax::FileMetadata which should be considered “original” for
|
27
|
+
# indexing and version‐tracking.
|
28
|
+
#
|
29
|
+
# If +file_set.original_file_id+ is defined, it will be used; otherwise,
|
30
|
+
# this requires a custom query. The ultimate fallback, if no
|
31
|
+
# pcdm:OriginalFile is associated with the :file_set, is to just use the
|
32
|
+
# first file in its :file_ids.
|
33
|
+
#
|
34
|
+
# @return [Hyrax::FileMetadata]
|
35
|
+
def original_file
|
36
|
+
if file_set.original_file_id
|
37
|
+
# Always just use original_file_id if it is defined.
|
38
|
+
#
|
39
|
+
# NOTE: This needs to use :find_file_metadata_by, not :find_by, because
|
40
|
+
# at time of writing the latter does not work in Wings.
|
41
|
+
query_service.custom_queries.find_file_metadata_by(id: file_set.original_file_id)
|
42
|
+
else
|
43
|
+
# Cache the fallback to avoid needing to do this query twice.
|
44
|
+
#
|
45
|
+
# See NOTE above regarding use of :find_file_metadata_by.
|
46
|
+
@original_file ||= begin
|
47
|
+
query_service.custom_queries.find_original_file(file_set: file_set)
|
48
|
+
rescue Valkyrie::Persistence::ObjectNotFoundError
|
49
|
+
fallback_id = file_set.file_ids.first
|
50
|
+
query_service.custom_queries.find_file_metadata_by(id: fallback_id) if fallback_id
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -89,6 +89,15 @@ module Hyrax
|
|
89
89
|
resource.lease || Lease.new
|
90
90
|
end
|
91
91
|
|
92
|
+
##
|
93
|
+
# Drop the lease by setting its release date to `nil`.
|
94
|
+
#
|
95
|
+
# @return [void]
|
96
|
+
def nullify
|
97
|
+
return unless under_lease?
|
98
|
+
lease.lease_expiration_date = nil
|
99
|
+
end
|
100
|
+
|
92
101
|
##
|
93
102
|
# @return [Boolean]
|
94
103
|
def release
|
@@ -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
|