hyrax 3.0.2 → 3.1.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 +22 -0
- data/.dassie/Gemfile +10 -5
- data/.dassie/config/initializers/hyrax.rb +5 -0
- data/.dockerignore +3 -0
- data/.env +0 -1
- data/.rubocop.yml +4 -0
- data/CONTAINERS.md +1 -1
- data/Dockerfile +12 -6
- data/Gemfile +21 -27
- data/app/actors/hyrax/actors/base_actor.rb +1 -1
- data/app/actors/hyrax/actors/create_with_remote_files_actor.rb +85 -63
- data/app/actors/hyrax/actors/create_with_remote_files_ordered_members_actor.rb +7 -42
- data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +20 -8
- data/app/controllers/concerns/hyrax/embargoes_controller_behavior.rb +21 -9
- data/app/controllers/concerns/hyrax/leases_controller_behavior.rb +14 -5
- data/app/controllers/concerns/hyrax/works_controller_behavior.rb +22 -3
- data/app/controllers/hyrax/admin/workflows_controller.rb +8 -2
- data/app/controllers/hyrax/dashboard/collection_members_controller.rb +13 -9
- data/app/controllers/hyrax/dashboard/collections_controller.rb +12 -10
- data/app/controllers/hyrax/file_sets_controller.rb +49 -13
- data/app/controllers/hyrax/permissions_controller.rb +3 -4
- data/app/controllers/hyrax/workflow_actions_controller.rb +3 -1
- data/app/forms/hyrax/forms/collection_form.rb +7 -3
- data/app/forms/hyrax/forms/dashboard/nest_collection_form.rb +24 -2
- data/app/forms/hyrax/forms/file_set_form.rb +46 -0
- data/app/forms/hyrax/forms/permission.rb +23 -0
- data/app/forms/hyrax/forms/permission_template_form.rb +8 -2
- data/app/forms/hyrax/forms/resource_form.rb +10 -17
- data/app/forms/hyrax/forms/work_form.rb +5 -2
- data/app/helpers/hyrax/batch_edits_helper.rb +3 -1
- data/app/helpers/hyrax/collections_helper.rb +88 -2
- data/app/helpers/hyrax/dashboard_helper_behavior.rb +3 -7
- data/app/helpers/hyrax/file_set_helper.rb +25 -6
- data/app/helpers/hyrax/work_form_helper.rb +53 -0
- data/app/indexers/hyrax/administrative_set_indexer.rb +18 -0
- data/app/indexers/hyrax/valkyrie_indexer.rb +3 -3
- data/app/inputs/controlled_vocabulary_input.rb +2 -5
- data/app/jobs/attach_files_to_work_job.rb +19 -10
- data/app/jobs/attach_files_to_work_with_ordered_members_job.rb +6 -5
- data/app/jobs/inherit_permissions_job.rb +9 -5
- data/app/models/admin_set.rb +6 -25
- data/app/models/concerns/hyrax/ability.rb +3 -1
- data/app/models/concerns/hyrax/collection_behavior.rb +17 -44
- data/app/models/concerns/hyrax/file_set/characterization.rb +18 -12
- data/app/models/concerns/hyrax/solr_document_behavior.rb +9 -52
- data/app/models/concerns/hyrax/suppressible.rb +5 -0
- data/app/models/concerns/hyrax/user.rb +9 -3
- data/app/models/hyrax/file_set.rb +6 -0
- data/app/models/hyrax/pcdm_collection.rb +1 -0
- data/app/models/hyrax/permission_template.rb +98 -12
- data/app/models/hyrax/virus_scanner.rb +27 -18
- data/app/models/sipity/agent.rb +1 -0
- data/app/models/sipity/entity.rb +30 -8
- data/app/models/sipity/workflow.rb +1 -0
- data/app/models/sipity.rb +42 -0
- data/app/presenters/hyrax/admin_set_options_presenter.rb +2 -10
- data/app/presenters/hyrax/admin_set_presenter.rb +5 -1
- data/app/presenters/hyrax/admin_set_selection_presenter.rb +116 -0
- data/app/presenters/hyrax/collection_presenter.rb +31 -6
- data/app/presenters/hyrax/file_set_presenter.rb +6 -1
- data/app/presenters/hyrax/file_usage.rb +3 -2
- data/app/presenters/hyrax/stats_usage_presenter.rb +2 -1
- data/app/presenters/hyrax/trophy_presenter.rb +33 -4
- data/app/presenters/hyrax/user_profile_presenter.rb +11 -1
- data/app/presenters/hyrax/version_list_presenter.rb +19 -0
- data/app/presenters/hyrax/version_presenter.rb +3 -2
- data/app/presenters/hyrax/work_show_presenter.rb +25 -4
- data/app/presenters/hyrax/work_usage.rb +5 -3
- data/app/renderers/hyrax/renderers/attribute_renderer.rb +10 -2
- data/app/search_builders/hyrax/admin_set_search_builder.rb +1 -1
- data/app/search_builders/hyrax/my/collections_search_builder.rb +1 -1
- data/app/services/hyrax/admin_set_create_service.rb +3 -1
- data/app/services/hyrax/collections/collection_member_search_service.rb +72 -0
- data/app/services/hyrax/collections/collection_member_service.rb +112 -27
- data/app/services/hyrax/collections/migration_service.rb +4 -2
- data/app/services/hyrax/collections/nested_collection_persistence_service.rb +12 -13
- data/app/services/hyrax/collections/nested_collection_query_service.rb +2 -0
- data/app/services/hyrax/collections/permissions_create_service.rb +6 -4
- data/app/services/hyrax/contextual_path.rb +23 -0
- data/app/services/hyrax/custom_queries/find_file_metadata.rb +7 -5
- data/app/services/hyrax/custom_queries/navigators/parent_collections_navigator.rb +46 -0
- data/app/services/hyrax/edit_permissions_service.rb +27 -20
- data/app/services/hyrax/find_objects_via_solr_service.rb +11 -7
- data/app/services/hyrax/multiple_membership_checker.rb +51 -31
- data/app/services/hyrax/resource_status.rb +7 -0
- data/app/services/hyrax/search_service.rb +4 -2
- data/app/services/hyrax/solr_query_builder_service.rb +29 -6
- data/app/services/hyrax/solr_query_service.rb +224 -0
- data/app/services/hyrax/solr_service.rb +8 -1
- data/app/services/hyrax/statistics/depositors/summary.rb +2 -1
- data/app/services/hyrax/work_uploads_handler.rb +17 -2
- data/app/services/hyrax/workflow/actionable_objects.rb +70 -0
- data/app/services/hyrax/workflow/object_in_workflow_decorator.rb +31 -0
- data/app/services/hyrax/workflow/status_list_service.rb +43 -13
- data/app/views/hyrax/base/_form_relationships.html.erb +1 -2
- data/app/views/hyrax/base/_form_rendering.html.erb +1 -1
- data/app/views/hyrax/base/_form_representative.html.erb +1 -1
- data/app/views/hyrax/base/_form_thumbnail.html.erb +1 -1
- data/app/views/hyrax/base/_guts4form.html.erb +2 -2
- data/app/views/hyrax/base/_representative_media.html.erb +1 -1
- data/app/views/hyrax/base/_show_actions.html.erb +1 -1
- data/app/views/hyrax/dashboard/collections/_form.html.erb +3 -3
- data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +1 -1
- data/app/views/hyrax/dashboard/collections/edit.html.erb +4 -2
- data/app/views/hyrax/dashboard/collections/new.html.erb +4 -2
- data/app/views/hyrax/dashboard/collections/show.html.erb +1 -1
- data/app/views/hyrax/file_sets/edit.html.erb +1 -1
- data/app/views/hyrax/file_sets/media_display/_audio.html.erb +1 -1
- data/app/views/hyrax/file_sets/media_display/_default.html.erb +1 -1
- data/app/views/hyrax/file_sets/media_display/_image.html.erb +1 -1
- data/app/views/hyrax/file_sets/media_display/_office_document.html.erb +1 -1
- data/app/views/hyrax/file_sets/media_display/_pdf.html.erb +1 -1
- data/app/views/hyrax/file_sets/media_display/_video.html.erb +1 -1
- data/app/views/hyrax/file_sets/show.html.erb +1 -1
- data/app/views/hyrax/my/_admin_set_action_menu.html.erb +0 -11
- data/app/views/hyrax/my/_collection_action_menu.html.erb +1 -2
- data/app/views/hyrax/my/collections/_list_collections.html.erb +1 -1
- data/app/views/hyrax/my/collections/_modal_add_subcollection.html.erb +3 -5
- data/bin/solrcloud-assign-configset.sh +8 -5
- data/bin/solrcloud-upload-configset.sh +4 -2
- data/chart/hyrax/Chart.yaml +3 -3
- data/chart/hyrax/README.md +47 -1
- data/chart/hyrax/templates/_helpers.tpl +1 -1
- data/chart/hyrax/templates/configmap-env.yaml +1 -3
- data/chart/hyrax/templates/deployment-worker.yaml +6 -3
- data/chart/hyrax/templates/deployment.yaml +8 -3
- data/chart/hyrax/values.yaml +12 -0
- data/config/brakeman.ignore +2 -2
- data/config/locales/hyrax.de.yml +1 -1
- data/config/locales/hyrax.en.yml +1 -1
- data/config/locales/hyrax.es.yml +1 -1
- data/config/locales/hyrax.fr.yml +1 -1
- data/config/locales/hyrax.it.yml +1 -1
- data/config/locales/hyrax.pt-BR.yml +1 -1
- data/config/locales/hyrax.zh.yml +1 -1
- data/docker-compose.yml +1 -0
- data/documentation/developing-your-hyrax-based-app.md +1 -1
- data/documentation/legacyREADME.md +1 -1
- data/lib/generators/hyrax/templates/config/initializers/hyrax.rb +5 -0
- data/lib/hyrax/active_fedora_dummy_model.rb +62 -0
- data/lib/hyrax/configuration.rb +8 -0
- data/lib/hyrax/engine.rb +1 -0
- data/lib/hyrax/errors.rb +2 -0
- data/lib/hyrax/specs/capybara.rb +3 -1
- data/lib/hyrax/specs/shared_specs/valkyrie_storage_versions.rb +9 -0
- data/lib/hyrax/transactions/container.rb +21 -0
- data/lib/hyrax/transactions/file_set_destroy.rb +21 -0
- data/lib/hyrax/transactions/steps/add_file_sets.rb +3 -2
- data/lib/hyrax/transactions/steps/add_to_parent.rb +36 -0
- data/lib/hyrax/transactions/steps/remove_file_set_from_work.rb +47 -0
- data/lib/hyrax/transactions/work_create.rb +2 -1
- data/lib/hyrax/valkyrie_can_can_adapter.rb +1 -0
- data/lib/hyrax/version.rb +1 -1
- data/lib/hyrax.rb +9 -0
- data/lib/tasks/collection_type_global_id.rake +1 -1
- data/lib/tasks/regenerate_derivatives.rake +12 -0
- data/lib/wings/orm_converter.rb +18 -2
- data/lib/wings/setup.rb +1 -0
- data/lib/wings/valkyrie/storage.rb +56 -1
- data/template.rb +1 -1
- metadata +17 -2
@@ -10,6 +10,11 @@ module Hyrax
|
|
10
10
|
end
|
11
11
|
|
12
12
|
##
|
13
|
+
# @deprecated use `Hyrax::ResourceStatus` instead. in most cases,
|
14
|
+
# {#suppressed?} is being called on a {SolrDocumentBehavior}. we continue
|
15
|
+
# to index `suppressed_bsi` and expose its value as an attribute on solr
|
16
|
+
# document objects.
|
17
|
+
#
|
13
18
|
# Used to restrict visibility on search results for a work that is inactive. If the state is not set, the
|
14
19
|
# default behavior is to consider the work not to be suppressed.
|
15
20
|
#
|
@@ -31,7 +31,7 @@ module Hyrax::User
|
|
31
31
|
|
32
32
|
scope :guests, ->() { where(guest: true) }
|
33
33
|
scope :registered, ->() { where(guest: false) }
|
34
|
-
scope :without_system_accounts, -> { where("#{::User.user_key_field} not in (?)", [::User.batch_user_key, ::User.audit_user_key]) }
|
34
|
+
scope :without_system_accounts, -> { where("#{::User.user_key_field} not in (?)", [::User.batch_user_key, ::User.audit_user_key, ::User.system_user_key]) }
|
35
35
|
|
36
36
|
# Validate and normalize ORCIDs
|
37
37
|
validates_with OrcidValidator
|
@@ -145,7 +145,14 @@ module Hyrax::User
|
|
145
145
|
end
|
146
146
|
|
147
147
|
module ClassMethods
|
148
|
-
|
148
|
+
def system_user
|
149
|
+
find_or_create_system_user(system_user_key)
|
150
|
+
end
|
151
|
+
|
152
|
+
def system_user_key
|
153
|
+
Hyrax.config.system_user_key
|
154
|
+
end
|
155
|
+
|
149
156
|
def audit_user
|
150
157
|
find_or_create_system_user(audit_user_key)
|
151
158
|
end
|
@@ -158,7 +165,6 @@ module Hyrax::User
|
|
158
165
|
Hydra.config.user_key_field
|
159
166
|
end
|
160
167
|
|
161
|
-
# Override this method if you aren't using email/password
|
162
168
|
def batch_user
|
163
169
|
find_or_create_system_user(batch_user_key)
|
164
170
|
end
|
@@ -9,6 +9,12 @@ module Hyrax
|
|
9
9
|
include Hyrax::Schema(:core_metadata)
|
10
10
|
include Hyrax::Schema(:basic_metadata)
|
11
11
|
|
12
|
+
def self.model_name(name_class: Hyrax::Name)
|
13
|
+
@_model_name ||= begin
|
14
|
+
name_class.new(self, nil, 'FileSet')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
12
18
|
attribute :file_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID) # id for FileMetadata resources
|
13
19
|
attribute :original_file_id, Valkyrie::Types::ID # id for FileMetadata resource
|
14
20
|
attribute :thumbnail_id, Valkyrie::Types::ID # id for FileMetadata resource
|
@@ -11,6 +11,7 @@ module Hyrax
|
|
11
11
|
|
12
12
|
attribute :collection_type_gid, Valkyrie::Types::String
|
13
13
|
attribute :member_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID).meta(ordered: true)
|
14
|
+
attribute :member_of_collection_ids, Valkyrie::Types::Set.of(Valkyrie::Types::ID)
|
14
15
|
|
15
16
|
##
|
16
17
|
# @api private
|
@@ -1,20 +1,61 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Hyrax
|
3
3
|
##
|
4
|
-
#
|
4
|
+
# Holds policy data about the workflow and permissions applied objects when
|
5
|
+
# they are deposited through an Administrative Set or a Collection. Each
|
6
|
+
# template record has a {#source} (through {#source_id}); the template's
|
7
|
+
# rules inform the behavior of objects deposited through that {#source_model}.
|
5
8
|
#
|
6
|
-
#
|
7
|
-
# * calculate embargo/lease release dates
|
9
|
+
# The {PermissionTemplate} specifies:
|
8
10
|
#
|
9
|
-
#
|
11
|
+
# - an {#active_workflow} that the object will enter and be processed through.
|
12
|
+
# - {#access_grants} that can be applied to each object (especially at deposit
|
13
|
+
# time).
|
14
|
+
# - an embargo configuration ({#release_date} {#release_period}) for default
|
15
|
+
# embargo behavior.
|
10
16
|
#
|
11
|
-
#
|
12
|
-
|
17
|
+
# Additionally, the {PermissionTemplate} grants authority to perform actions
|
18
|
+
# that relate to the Administrative Set/Collection itself. Rules for who can
|
19
|
+
# deposit to, view(?!), or manage the admin set are governed by related
|
20
|
+
# {PermissionTemplateAccess} records. Administrat Sets should have a manager
|
21
|
+
# granted by some such record.
|
22
|
+
#
|
23
|
+
# @todo write up what "default embargo behavior", when it is applied, and how
|
24
|
+
# it interacts with embargoes specified by user input.
|
25
|
+
#
|
26
|
+
# @example cerating a permission template and manager for an admin set
|
27
|
+
# admin_set = Hyrax::AdministrativeSet.new(title: 'My Admin Set')
|
28
|
+
# admin_set = Hyrax.persister.save(resource: admin_set)
|
29
|
+
#
|
30
|
+
# template = PermissionTemplate.create!(source_id: admin_set.id.to_s)
|
31
|
+
# Hyrax::PermissionTemplateAccess.create!(permission_template: template,
|
32
|
+
# agent_type: Hyrax::PermissionTemplateAccess::USER,
|
33
|
+
# agent_id: user.user_key,
|
34
|
+
# access: Hyrax::PermissionTemplateAccess::MANAGE)
|
35
|
+
#
|
36
|
+
# @see Hyrax::AdministrativeSet
|
37
|
+
class PermissionTemplate < ActiveRecord::Base # rubocop:disable Metrics/ClassLength
|
13
38
|
self.table_name = 'permission_templates'
|
14
39
|
|
40
|
+
##
|
41
|
+
# @!attribute [rw] source_id
|
42
|
+
# @return [String] identifier for the {Collection} or {AdministrativeSet}
|
43
|
+
# to which this template applies.
|
44
|
+
# @!attribute [rw] access_grants
|
45
|
+
# @return [Hyrax::PermissionTemplateAccess]
|
46
|
+
# @!attribute [rw] active_workflow
|
47
|
+
# @return [Sipity::Workflow]
|
48
|
+
# @!attribute [rw] available_workflows
|
49
|
+
# @return [Enumerable<Sipity::Workflow>]
|
15
50
|
has_many :access_grants, class_name: 'Hyrax::PermissionTemplateAccess', dependent: :destroy
|
16
51
|
accepts_nested_attributes_for :access_grants, reject_if: :all_blank
|
17
52
|
|
53
|
+
# The list of workflows that could be activated; It includes the active workflow
|
54
|
+
has_many :available_workflows, class_name: 'Sipity::Workflow', dependent: :destroy
|
55
|
+
|
56
|
+
# In a perfect world, there would be a join table that enforced uniqueness on the ID.
|
57
|
+
has_one :active_workflow, -> { where(active: true) }, class_name: 'Sipity::Workflow', foreign_key: :permission_template_id
|
58
|
+
|
18
59
|
##
|
19
60
|
# @api public
|
20
61
|
#
|
@@ -28,12 +69,6 @@ module Hyrax
|
|
28
69
|
access_grants.where(agent_type: agent_type, access: access).pluck(:agent_id)
|
29
70
|
end
|
30
71
|
|
31
|
-
# The list of workflows that could be activated; It includes the active workflow
|
32
|
-
has_many :available_workflows, class_name: 'Sipity::Workflow', dependent: :destroy
|
33
|
-
|
34
|
-
# In a perfect world, there would be a join table that enforced uniqueness on the ID.
|
35
|
-
has_one :active_workflow, -> { where(active: true) }, class_name: 'Sipity::Workflow', foreign_key: :permission_template_id
|
36
|
-
|
37
72
|
##
|
38
73
|
# @note this is a convenience method for +Hyrax.query_service.find_by(id: template.source_id)+
|
39
74
|
#
|
@@ -153,6 +188,57 @@ module Hyrax
|
|
153
188
|
visibility == value
|
154
189
|
end
|
155
190
|
|
191
|
+
##
|
192
|
+
# @return [Array<String>]
|
193
|
+
def edit_users
|
194
|
+
agent_ids_for(access: 'manage', agent_type: 'user')
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# @return [Array<String>]
|
199
|
+
def edit_groups
|
200
|
+
agent_ids_for(access: 'manage', agent_type: 'group')
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# @return [Array<String>]
|
205
|
+
def read_users
|
206
|
+
(agent_ids_for(access: 'view', agent_type: 'user') +
|
207
|
+
agent_ids_for(access: 'deposit', agent_type: 'user')).uniq
|
208
|
+
end
|
209
|
+
|
210
|
+
##
|
211
|
+
# @return [Array<String>]
|
212
|
+
def read_groups
|
213
|
+
(agent_ids_for(access: 'view', agent_type: 'group') +
|
214
|
+
agent_ids_for(access: 'deposit', agent_type: 'group')).uniq -
|
215
|
+
[::Ability.registered_group_name, ::Ability.public_group_name]
|
216
|
+
end
|
217
|
+
|
218
|
+
##
|
219
|
+
# @return [Boolean]
|
220
|
+
def reset_access_controls(interpret_visibility: false)
|
221
|
+
reset_access_controls_for(collection: source_model,
|
222
|
+
interpret_visibility: interpret_visibility)
|
223
|
+
end
|
224
|
+
|
225
|
+
##
|
226
|
+
# @return [Boolean]
|
227
|
+
def reset_access_controls_for(collection:, interpret_visibility: false)
|
228
|
+
interpreted_read_groups = read_groups
|
229
|
+
|
230
|
+
if interpret_visibility
|
231
|
+
visibilities = Hyrax::VisibilityMap.instance
|
232
|
+
interpreted_read_groups -= visibilities.deletions_for(visibility: collection.visibility)
|
233
|
+
interpreted_read_groups += visibilities.additions_for(visibility: collection.visibility)
|
234
|
+
end
|
235
|
+
|
236
|
+
collection.update!(edit_users: edit_users,
|
237
|
+
edit_groups: edit_groups,
|
238
|
+
read_users: read_users,
|
239
|
+
read_groups: interpreted_read_groups.uniq)
|
240
|
+
end
|
241
|
+
|
156
242
|
private
|
157
243
|
|
158
244
|
# If template requires no delays, check if date is exactly today
|
@@ -1,23 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# If ClamAV is present, it will be used to check for the presence of a virus. If ClamAV is not
|
4
|
-
# installed or otherwise not available to your application, Hyrax::Works does no virus checking
|
5
|
-
# add assumes files have no viruses.
|
6
|
-
#
|
7
|
-
# @example to use a virus checker other than Hyrax::VirusScanner:
|
8
|
-
# class MyScanner < Hyrax::Works::VirusScanner
|
9
|
-
# def infected?
|
10
|
-
# my_result = Scanner.check_for_viruses(file)
|
11
|
-
# [return true or false]
|
12
|
-
# end
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# # Then set Hyrax::Works to use your scanner either in a config file or initializer:
|
16
|
-
# Hyrax.config.virus_scanner = MyScanner
|
2
|
+
|
17
3
|
module Hyrax
|
4
|
+
##
|
5
|
+
# The default virus scanner ported from +Hyrax::Works+.
|
6
|
+
#
|
7
|
+
# If ClamAV is present, it will be used to check for the presence of a virus.
|
8
|
+
# If ClamAV is not installed or otherwise not available to your application,
|
9
|
+
# +Hyrax::Works+ does no virus checking add assumes files have no viruses.
|
10
|
+
#
|
11
|
+
# @example to use a virus checker other than Hyrax::VirusScanner:
|
12
|
+
# class MyScanner < Hyrax::Works::VirusScanner
|
13
|
+
# def infected?
|
14
|
+
# my_result = Scanner.check_for_viruses(file)
|
15
|
+
# [return true or false]
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # Then set Hyrax::Works to use your scanner either in a config file or initializer:
|
20
|
+
# Hyrax.config.virus_scanner = MyScanner
|
21
|
+
#
|
18
22
|
class VirusScanner
|
19
23
|
attr_reader :file
|
20
24
|
|
25
|
+
##
|
21
26
|
# @api public
|
22
27
|
# @param file [String]
|
23
28
|
def self.infected?(file)
|
@@ -28,7 +33,9 @@ module Hyrax
|
|
28
33
|
@file = file
|
29
34
|
end
|
30
35
|
|
31
|
-
|
36
|
+
##
|
37
|
+
# @note Override this method to use your own virus checking software
|
38
|
+
#
|
32
39
|
# @return [Boolean]
|
33
40
|
def infected?
|
34
41
|
defined?(ClamAV) ? clam_av_scanner : null_scanner
|
@@ -41,8 +48,10 @@ module Hyrax
|
|
41
48
|
true
|
42
49
|
end
|
43
50
|
|
44
|
-
|
45
|
-
#
|
51
|
+
##
|
52
|
+
# Always return zero if there's nothing available to check for viruses.
|
53
|
+
# This means that we assume all files have no viruses because we can't
|
54
|
+
# conclusively say if they have or not.
|
46
55
|
def null_scanner
|
47
56
|
warning "Unable to check #{file} for viruses because no virus scanner is defined" unless
|
48
57
|
Rails.env.test?
|
data/app/models/sipity/agent.rb
CHANGED
data/app/models/sipity/entity.rb
CHANGED
@@ -1,19 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Sipity
|
3
|
-
|
3
|
+
##
|
4
|
+
# A proxy for the entity (e.g. a repository Object) that is being processed
|
5
|
+
# via workflows.
|
4
6
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
+
# Objects of this class (and their underlying database records) represent
|
8
|
+
# another object in the context of the workflow process. By using a proxy,
|
9
|
+
# we can avoid polluting the repository object's data and behavior with
|
10
|
+
# things related to workflow processing. This means we can move an object into
|
11
|
+
# and through a workflow without making changes independently from curatorial
|
12
|
+
# considerations (e.g. metadata changes).
|
13
|
+
#
|
14
|
+
# Keeping this object and interface separate also presents a clear seam for
|
15
|
+
# alternative solutions.
|
16
|
+
#
|
17
|
+
# The {Sipity::Entity} relates to repository objects via a +GlobalID+ URI via
|
18
|
+
# {#proxy_for_global_id}. Since the repository objects aren't assumed to be
|
19
|
+
# +ActiveRecord+ or +ActiveModel+ compatible, we use the URI-based system
|
20
|
+
# provided by +GlobalID+ to ensure that this relationship functions independent
|
21
|
+
# of the modelling system used for the respository objects. {#proxy_for} is
|
22
|
+
# provided as a convenience method for retrieving the underlying repository
|
23
|
+
# object.
|
24
|
+
#
|
25
|
+
# Each {Sipity::Entity} holds a relationship to a {Sipity::Workflow}, which is
|
26
|
+
# the active workflow on the object represented by the {Entity}. It also holds
|
27
|
+
# a reference to a {Sipity::WorkflowState}, which is the current state of the
|
28
|
+
# object within the workflow.
|
7
29
|
#
|
8
|
-
# The goal is to keep this behavior separate, so that we can possibly
|
9
|
-
# extract the information.
|
10
30
|
# @example To get the Sipity::Entity for a work
|
11
31
|
# work = GenericWork.first
|
12
|
-
#
|
13
|
-
# => "gid://whatever/GenericWork/3x816m604"
|
14
|
-
# Sipity::Entity.where(proxy_for_global_id: work_global_id).first
|
32
|
+
# Sipity::Entity(work)
|
15
33
|
# => #<Sipity::Entity id: 1, proxy_for_global_id: "gid://whatever/GenericWork/3x816m604",
|
16
34
|
# workflow_id: 8, workflow_state_id: 20, created_at: "2017-07-07 13:39:42", updated_at: "2017-07-07 13:39:42">
|
35
|
+
#
|
36
|
+
# @see https://github.com/rails/globalid Rails' GlobalID library
|
17
37
|
class Entity < ActiveRecord::Base
|
18
38
|
self.table_name = 'sipity_entities'
|
19
39
|
|
@@ -35,6 +55,8 @@ module Sipity
|
|
35
55
|
# Defines the method #workflow_name
|
36
56
|
delegate :name, to: :workflow, prefix: :workflow
|
37
57
|
|
58
|
+
##
|
59
|
+
# @return [Object] the thing this +Entity+ represents.
|
38
60
|
def proxy_for
|
39
61
|
@proxy_for ||= GlobalID::Locator.locate(proxy_for_global_id)
|
40
62
|
end
|
data/app/models/sipity.rb
CHANGED
@@ -1,6 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
##
|
4
|
+
# {Sipity} is a workflow/state engine.
|
5
|
+
#
|
6
|
+
# This module and the classes namespaced within it provide a domain model and
|
7
|
+
# implementation for managing the movement of repository objects through a
|
8
|
+
# defined workflow. The workflows themselves are configured using JSON documents
|
9
|
+
# and loaded into the database/domain model as {Sipity::Workflow}. Each workflow
|
10
|
+
# can be understood as finite sets of {Sipity::WorkflowState},
|
11
|
+
# {Sipity::WorkflowAction} (transitions from state to state), and {Sipity::Role}
|
12
|
+
# authorized to carry out each action.
|
13
|
+
#
|
14
|
+
# Any uniquely identifiable object can be managed by a {Sipity::Workflow}.
|
15
|
+
# Normally Hyrax uses workflows to handle the deposit process and maintenance
|
16
|
+
# lifecycle of repository objects at the level of the Work (within the Hydra
|
17
|
+
# Works model). Objects are represented within the Sipity engine's domain model
|
18
|
+
# by a {Sipity::Entity}. Each object has at most one {Sipity::Entity}, is
|
19
|
+
# governed by one {Sipity::Workflow}, and in one {Sipity::WorkflowState} at any
|
20
|
+
# given time.
|
21
|
+
#
|
22
|
+
# Some use cases for Sipity workflows include:
|
23
|
+
#
|
24
|
+
# * Simple unmediated deposit with on-deposit notifications and actions;
|
25
|
+
# * Mediated deposit with one or more review steps;
|
26
|
+
# * Publication workflows requiring multiple levels of editorial approval
|
27
|
+
# and/or peer review;
|
28
|
+
# * Preservation processes involving post-deposit selection of objects for
|
29
|
+
# replication to external preservation platforms and/or required action
|
30
|
+
# in case of failed fixity checks;
|
31
|
+
# * Electronic Thesis & Dissertation submission processes involving (e.g.)
|
32
|
+
# student deposit, committee and/or departmental approval, centralized/
|
33
|
+
# graduate school review, and a final graduation step.
|
34
|
+
#
|
3
35
|
module Sipity
|
36
|
+
##
|
37
|
+
# Cast a given input (e.g. a +::User+ or {Hyrax::Group} to a {Sipity::Agent}).
|
38
|
+
#
|
39
|
+
# @param input [Object]
|
40
|
+
#
|
41
|
+
# @return [Sipity::Agent]
|
4
42
|
def Agent(input, &block) # rubocop:disable Naming/MethodName
|
5
43
|
result = case input
|
6
44
|
when Sipity::Agent
|
@@ -13,6 +51,10 @@ module Sipity
|
|
13
51
|
|
14
52
|
##
|
15
53
|
# Cast an object to an Entity
|
54
|
+
#
|
55
|
+
# @param input [Object]
|
56
|
+
#
|
57
|
+
# @return [Sipity::Entity]
|
16
58
|
# rubocop:disable Naming/MethodName, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
17
59
|
def Entity(input, &block)
|
18
60
|
result = case input
|
@@ -59,16 +59,8 @@ module Hyrax
|
|
59
59
|
# > remove files from a work, and add new works to the set.
|
60
60
|
return true if @current_ability.can?(:manage, permission_template)
|
61
61
|
|
62
|
-
# Otherwise, we check if the workflow
|
63
|
-
|
64
|
-
wf = workflow(permission_template: permission_template)
|
65
|
-
return false unless wf
|
66
|
-
wf.allows_access_grant?
|
67
|
-
end
|
68
|
-
|
69
|
-
def workflow(permission_template:)
|
70
|
-
return unless permission_template.active_workflow
|
71
|
-
Sipity::Workflow.find_by!(id: permission_template.active_workflow.id)
|
62
|
+
# Otherwise, we check if the active workflow allows access grants
|
63
|
+
!!permission_template.active_workflow&.allows_access_grant?
|
72
64
|
end
|
73
65
|
end
|
74
66
|
end
|
@@ -12,7 +12,11 @@ module Hyrax
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def total_viewable_items
|
15
|
-
|
15
|
+
field_pairs = { "isPartOf_ssim" => id.to_s }
|
16
|
+
SolrQueryService.new
|
17
|
+
.with_field_pairs(field_pairs: field_pairs)
|
18
|
+
.accessible_by(ability: current_ability)
|
19
|
+
.count
|
16
20
|
end
|
17
21
|
|
18
22
|
# AdminSet cannot be deleted if default set or non-empty
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
##
|
4
|
+
# @api public
|
5
|
+
# @since 3.1.0
|
6
|
+
#
|
7
|
+
# Presents select options for admin sets.
|
8
|
+
#
|
9
|
+
# Each entry in the {#select_options} return value provides a label for
|
10
|
+
# display, an id to serve as the value, and a data hash which is used as HTML5
|
11
|
+
# data entries. The data entries can be used as hooks for Javascript
|
12
|
+
# to control input validation taking into account the Admin Set and
|
13
|
+
# `PermissionTemplate` rules (`visibility_component.es6` does this, for
|
14
|
+
# example).
|
15
|
+
#
|
16
|
+
# @note this supersedes the older +Hyrax::AdminSetOptionsPresenter+, which
|
17
|
+
# actied more like a "service" sending database queries to Solr and
|
18
|
+
# ActiveRecord. this version seeks only to present the input data and
|
19
|
+
# relies on its caller to pass in the right data.
|
20
|
+
class AdminSetSelectionPresenter
|
21
|
+
##
|
22
|
+
# @param [Array<#id>]
|
23
|
+
def initialize(admin_sets:)
|
24
|
+
@admin_sets = admin_sets
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# @return [Array<Array<String, String, Hash>>] an array suitable for a form
|
29
|
+
# input `collection:` parameter. it should contain a label, an id, and a
|
30
|
+
# hash of HTML5 data attributes.
|
31
|
+
def select_options
|
32
|
+
@admin_sets.map do |admin_set|
|
33
|
+
case admin_set
|
34
|
+
when OptionsEntry
|
35
|
+
admin_set.result
|
36
|
+
else
|
37
|
+
OptionsEntry.new(admin_set: admin_set).result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# @api public
|
44
|
+
class OptionsEntry
|
45
|
+
##
|
46
|
+
# @!attribute [rw] admin_set
|
47
|
+
# @return [AdministrativeSet, SolrDocument]
|
48
|
+
# @!attribute [rw] permission_template
|
49
|
+
# @return [PermissionTemplate]
|
50
|
+
# @!attribute [rw] permit_sharing
|
51
|
+
# @return [Boolean]
|
52
|
+
attr_accessor :admin_set, :permission_template, :permit_sharing
|
53
|
+
|
54
|
+
##
|
55
|
+
# @param [AdministrativeSet, SolrDocument] admin_set
|
56
|
+
# @param [PermissionTemplate] permission_template
|
57
|
+
# @param [Boolean] permit_sharing
|
58
|
+
def initialize(admin_set:, permission_template: nil, permit_sharing: false)
|
59
|
+
@admin_set = admin_set
|
60
|
+
@permission_template = permission_template
|
61
|
+
@permit_sharing = permit_sharing
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# @return [Array<String, String, Hash>]
|
66
|
+
def result
|
67
|
+
[label, id, data]
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# @return [String]
|
72
|
+
def label
|
73
|
+
Array(admin_set.title).first || admin_set.to_s
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# @return [String]
|
78
|
+
def id
|
79
|
+
admin_set.id.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# @return [Hash{String => Object}]
|
84
|
+
def data
|
85
|
+
{}.tap do |data|
|
86
|
+
data['data-sharing'] = permit_sharing
|
87
|
+
|
88
|
+
if permission_template
|
89
|
+
data.merge!(data_for(permission_template))
|
90
|
+
else
|
91
|
+
data['data-release-no-delay'] = true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
##
|
99
|
+
# @api private
|
100
|
+
def data_for(template)
|
101
|
+
{}.tap do |data|
|
102
|
+
if template.release_no_delay?
|
103
|
+
data['data-release-no-delay'] = true
|
104
|
+
elsif template.release_date.present?
|
105
|
+
data['data-release-date'] = template.release_date
|
106
|
+
end
|
107
|
+
|
108
|
+
data['data-release-before-date'] = true if
|
109
|
+
template.release_before_date?
|
110
|
+
data['data-visibility'] = template.visibility if
|
111
|
+
template.visibility.present?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|