curation_concerns 1.7.0.beta1 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/concerns/curation_concerns/application_controller_behavior.rb +2 -8
- data/app/controllers/concerns/curation_concerns/collections_controller_behavior.rb +13 -13
- data/app/controllers/concerns/curation_concerns/curation_concern_controller.rb +40 -3
- data/app/controllers/concerns/curation_concerns/selects_collections.rb +2 -0
- data/app/controllers/concerns/curation_concerns/single_use_links_controller_behavior.rb +9 -7
- data/app/models/concerns/curation_concerns/solr_document_behavior.rb +8 -0
- data/app/models/concerns/curation_concerns/suppressible.rb +31 -0
- data/app/models/concerns/curation_concerns/work_behavior.rb +1 -1
- data/app/presenters/curation_concerns/inspect_work_presenter.rb +52 -0
- data/app/presenters/curation_concerns/work_show_presenter.rb +4 -0
- data/app/search_builders/curation_concerns/README.md +69 -0
- data/app/search_builders/curation_concerns/collection_search_builder.rb +35 -17
- data/app/search_builders/curation_concerns/filter_suppressed.rb +15 -0
- data/app/search_builders/curation_concerns/filter_suppressed_with_roles.rb +30 -0
- data/app/search_builders/curation_concerns/search_filters.rb +1 -0
- data/app/search_builders/curation_concerns/single_collection_search_builder.rb +5 -0
- data/app/search_builders/curation_concerns/work_search_builder.rb +1 -0
- data/app/services/curation_concerns/actors/actor_factory.rb +0 -1
- data/app/services/curation_concerns/embargo_service.rb +0 -13
- data/app/services/curation_concerns/workflow/action_taken_service.rb +25 -15
- data/app/services/curation_concerns/workflow/activate_object.rb +9 -2
- data/app/services/curation_concerns/workflow/deactivate_object.rb +9 -4
- data/app/services/curation_concerns/workflow/{remove_depositor_permissions.rb → grant_edit_to_depositor.rb} +4 -4
- data/app/services/curation_concerns/workflow/workflow_action_service.rb +1 -1
- data/app/services/curation_concerns/working_directory.rb +1 -1
- data/app/views/curation_concerns/base/inspect_work.html.erb +37 -0
- data/app/views/curation_concerns/base/unavailable.html.erb +10 -0
- data/app/views/curation_concerns/operations/index.html.erb +1 -1
- data/app/views/curation_concerns/operations/show.html.erb +1 -1
- data/config/locales/curation_concerns.en.yml +3 -0
- data/curation_concerns.gemspec +3 -3
- data/lib/curation_concerns/rails/routes.rb +1 -0
- data/lib/curation_concerns/version.rb +1 -1
- data/lib/curation_concerns/workflow_authorization_exception.rb +4 -0
- data/lib/generators/curation_concerns/templates/workflow.json.erb +1 -0
- data/spec/controllers/curation_concerns/generic_works_controller_spec.rb +78 -16
- data/spec/controllers/selects_collections_controller_spec.rb +2 -4
- data/spec/factories/generic_works.rb +6 -0
- data/spec/factories/workflows.rb +1 -1
- data/spec/features/add_file_spec.rb +3 -0
- data/spec/features/create_child_work_spec.rb +13 -7
- data/spec/features/update_file_spec.rb +3 -2
- data/spec/forms/curation_concerns/forms/workflow_action_form_spec.rb +2 -4
- data/spec/indexers/work_indexer_spec.rb +11 -7
- data/spec/jobs/characterize_job_spec.rb +2 -2
- data/spec/models/curation_concerns/work_behavior_spec.rb +1 -1
- data/spec/models/generic_work_spec.rb +16 -7
- data/spec/models/solr_document_spec.rb +13 -0
- data/spec/presenters/curation_concerns/inspect_work_presenter_spec.rb +58 -0
- data/spec/presenters/curation_concerns/work_show_presenter_spec.rb +9 -0
- data/spec/presenters/curation_concerns/workflow_presenter_spec.rb +29 -15
- data/spec/routing/route_spec.rb +4 -0
- data/spec/services/curation_concerns/workflow/action_taken_service_spec.rb +5 -6
- data/spec/services/curation_concerns/workflow/activate_object_spec.rb +13 -12
- data/spec/services/curation_concerns/workflow/deactivate_object_spec.rb +14 -13
- data/spec/services/curation_concerns/workflow/grant_edit_to_depositor_spec.rb +20 -0
- data/spec/services/curation_concerns/workflow/permission_query_spec.rb +3 -3
- data/spec/services/curation_concerns/workflow/status_list_service_spec.rb +4 -1
- data/spec/services/curation_concerns/workflow/workflow_importer_spec.rb +2 -3
- data/spec/services/curation_concerns/working_directory_spec.rb +12 -0
- data/spec/views/curation_concerns/base/unavailable.html.erb_spec.rb +40 -0
- metadata +34 -20
- data/app/actors/curation_concerns/actors/grant_edit_to_depositor_actor.rb +0 -19
- data/app/models/concerns/curation_concerns/publishable.rb +0 -25
- data/app/models/curation_concerns/state_workflow.rb +0 -13
- data/app/views/curation_concerns/file_sets/_rights_modal.html.erb +0 -41
- data/app/views/records/_rights_modal.html.erb +0 -1
- data/spec/actors/curation_concerns/grant_edit_to_depositor_actor_spec.rb +0 -32
- data/spec/services/curation_concerns/workflow/remove_depositor_permissions_spec.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fce83d5072e8e270e130b70cbbcd172c4a67f8b
|
4
|
+
data.tar.gz: 810425e450dc9b3c74b34f8e2e5b5d792caad21c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 464f2c154c361745c3fcba8eaac523c4ebee3d7a625163980c5754ac5c9f1f476fd8ccb813d3c7d39f42ab26fe96c5dfc72be5113ee0233f7397e73faaea1191
|
7
|
+
data.tar.gz: f477c89852669354e20fd1243788c7dec5263e12c0636e9869478317b82422bb4ecdcd7138c5ab74cfeb8ccf5d6978ff7cb91bc206cd964dfbaf28b359fbf5c0
|
@@ -6,14 +6,8 @@ module CurationConcerns
|
|
6
6
|
|
7
7
|
included do
|
8
8
|
helper CurationConcerns::MainAppHelpers
|
9
|
-
|
10
|
-
rescue_from
|
11
|
-
not_found_response(exception)
|
12
|
-
end
|
13
|
-
|
14
|
-
rescue_from Blacklight::Exceptions::InvalidSolrID do |exception|
|
15
|
-
not_found_response(exception)
|
16
|
-
end
|
9
|
+
rescue_from ActiveFedora::ObjectNotFoundError, with: :not_found_response
|
10
|
+
rescue_from Blacklight::Exceptions::InvalidSolrID, with: :not_found_response
|
17
11
|
end
|
18
12
|
|
19
13
|
def render_404
|
@@ -15,16 +15,7 @@ module CurationConcerns
|
|
15
15
|
copy_blacklight_config_from(::CatalogController)
|
16
16
|
|
17
17
|
# Catch permission errors
|
18
|
-
rescue_from Hydra::AccessDenied, CanCan::AccessDenied
|
19
|
-
if exception.action == :edit
|
20
|
-
redirect_to(url_for(action: 'show'), alert: 'You do not have sufficient privileges to edit this document')
|
21
|
-
elsif current_user && current_user.persisted?
|
22
|
-
redirect_to root_url, alert: exception.message
|
23
|
-
else
|
24
|
-
session['user_return_to'] = request.url
|
25
|
-
redirect_to new_user_session_url, alert: exception.message
|
26
|
-
end
|
27
|
-
end
|
18
|
+
rescue_from Hydra::AccessDenied, CanCan::AccessDenied, with: :deny_collection_access
|
28
19
|
|
29
20
|
# actions: audit, index, create, new, edit, show, update, destroy, permissions, citation
|
30
21
|
before_action :authenticate_user!, except: [:show, :index]
|
@@ -51,11 +42,22 @@ module CurationConcerns
|
|
51
42
|
# To build a query to find a list of collections
|
52
43
|
self.list_search_builder_class = CurationConcerns::CollectionSearchBuilder
|
53
44
|
# The search builder to find the collection
|
54
|
-
self.single_item_search_builder_class = CurationConcerns::
|
45
|
+
self.single_item_search_builder_class = CurationConcerns::SingleCollectionSearchBuilder
|
55
46
|
# The search builder to find the collections' members
|
56
47
|
self.member_search_builder_class = CurationConcerns::CollectionMemberSearchBuilder
|
57
48
|
end
|
58
49
|
|
50
|
+
def deny_collection_access(exception)
|
51
|
+
if exception.action == :edit
|
52
|
+
redirect_to(url_for(action: 'show'), alert: 'You do not have sufficient privileges to edit this document')
|
53
|
+
elsif current_user && current_user.persisted?
|
54
|
+
redirect_to root_url, alert: exception.message
|
55
|
+
else
|
56
|
+
session['user_return_to'] = request.url
|
57
|
+
redirect_to new_user_session_url, alert: exception.message
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
59
61
|
def index
|
60
62
|
# run the solr query to find the collections
|
61
63
|
query = list_search_builder.with(params).query
|
@@ -90,7 +92,6 @@ module CurationConcerns
|
|
90
92
|
|
91
93
|
def after_create_error
|
92
94
|
form
|
93
|
-
|
94
95
|
respond_to do |format|
|
95
96
|
format.html { render action: 'new' }
|
96
97
|
format.json { render json: @collection.errors, status: :unprocessable_entity }
|
@@ -120,7 +121,6 @@ module CurationConcerns
|
|
120
121
|
def after_update_error
|
121
122
|
form
|
122
123
|
query_collection_members
|
123
|
-
|
124
124
|
respond_to do |format|
|
125
125
|
format.html { render action: 'edit' }
|
126
126
|
format.json { render json: @collection.errors, status: :unprocessable_entity }
|
@@ -15,11 +15,13 @@ module CurationConcerns
|
|
15
15
|
self.work_form_service = WorkFormService
|
16
16
|
attr_accessor :curation_concern
|
17
17
|
helper_method :curation_concern, :contextual_path
|
18
|
+
|
19
|
+
rescue_from WorkflowAuthorizationException, with: :render_unavailable
|
18
20
|
end
|
19
21
|
|
20
22
|
module ClassMethods
|
21
23
|
def curation_concern_type=(curation_concern_type)
|
22
|
-
load_and_authorize_resource class: curation_concern_type, instance_name: :curation_concern, except: [:show, :file_manager]
|
24
|
+
load_and_authorize_resource class: curation_concern_type, instance_name: :curation_concern, except: [:show, :file_manager, :inspect_work]
|
23
25
|
self._curation_concern_type = curation_concern_type
|
24
26
|
end
|
25
27
|
|
@@ -105,6 +107,11 @@ module CurationConcerns
|
|
105
107
|
presenter
|
106
108
|
end
|
107
109
|
|
110
|
+
def inspect_work
|
111
|
+
raise Hydra::AccessDenied unless current_ability.admin?
|
112
|
+
presenter
|
113
|
+
end
|
114
|
+
|
108
115
|
attr_writer :actor
|
109
116
|
|
110
117
|
protected
|
@@ -193,10 +200,40 @@ module CurationConcerns
|
|
193
200
|
search_result_document(params)
|
194
201
|
end
|
195
202
|
|
203
|
+
# Only returns unsuppressed documents the user has read access to
|
196
204
|
def search_result_document(search_params)
|
197
205
|
_, document_list = search_results(search_params)
|
198
|
-
|
199
|
-
|
206
|
+
return document_list.first unless document_list.empty?
|
207
|
+
document_not_found!
|
208
|
+
end
|
209
|
+
|
210
|
+
def document_not_found!
|
211
|
+
doc = SolrDocument.find(params[:id])
|
212
|
+
raise WorkflowAuthorizationException if doc.suppressed?
|
213
|
+
raise CanCan::AccessDenied.new(nil, :show)
|
214
|
+
end
|
215
|
+
|
216
|
+
def render_unavailable
|
217
|
+
message = I18n.t("curation_concerns.workflow.unauthorized")
|
218
|
+
respond_to do |wants|
|
219
|
+
wants.html do
|
220
|
+
flash[:notice] = message
|
221
|
+
render 'unavailable', status: :unauthorized
|
222
|
+
end
|
223
|
+
wants.json do
|
224
|
+
render plain: message, status: :unauthorized
|
225
|
+
end
|
226
|
+
additional_response_formats(wants)
|
227
|
+
wants.ttl do
|
228
|
+
render plain: message, status: :unauthorized
|
229
|
+
end
|
230
|
+
wants.jsonld do
|
231
|
+
render plain: message, status: :unauthorized
|
232
|
+
end
|
233
|
+
wants.nt do
|
234
|
+
render plain: message, status: :unauthorized
|
235
|
+
end
|
236
|
+
end
|
200
237
|
end
|
201
238
|
end
|
202
239
|
end
|
@@ -9,6 +9,8 @@ module CurationConcerns::SelectsCollections
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
# @return [Hash{Symbol => Array[Symbol]}] bottom-up map of "what you need" to "what qualifies"
|
13
|
+
# @note i.e., requiring :read access is satisfied by either :read or :edit access
|
12
14
|
def access_levels
|
13
15
|
{ read: [:read, :edit], edit: [:edit] }
|
14
16
|
end
|
@@ -8,13 +8,15 @@ module CurationConcerns
|
|
8
8
|
before_action :authenticate_user!
|
9
9
|
before_action :authorize_user!
|
10
10
|
# Catch permission errors
|
11
|
-
rescue_from Hydra::AccessDenied, CanCan::AccessDenied
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
rescue_from Hydra::AccessDenied, CanCan::AccessDenied, with: :deny_link_access
|
12
|
+
end
|
13
|
+
|
14
|
+
def deny_link_access(exception)
|
15
|
+
if current_user && current_user.persisted?
|
16
|
+
redirect_to main_app.root_url, alert: "You do not have sufficient privileges to create links to this document"
|
17
|
+
else
|
18
|
+
session["user_return_to"] = request.url
|
19
|
+
redirect_to new_user_session_url, alert: exception.message
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
@@ -56,6 +56,10 @@ module CurationConcerns
|
|
56
56
|
hydra_model == ::Collection
|
57
57
|
end
|
58
58
|
|
59
|
+
def suppressed?
|
60
|
+
first(Solrizer.solr_name('suppressed', stored_boolean_field))
|
61
|
+
end
|
62
|
+
|
59
63
|
# Method to return the ActiveFedora model
|
60
64
|
def hydra_model
|
61
65
|
first(Solrizer.solr_name('has_model', :symbol)).constantize
|
@@ -181,5 +185,9 @@ module CurationConcerns
|
|
181
185
|
Rails.logger.info "Unable to parse date: #{field.first.inspect} for #{self['id']}"
|
182
186
|
end
|
183
187
|
end
|
188
|
+
|
189
|
+
def stored_boolean_field
|
190
|
+
Solrizer::Descriptor.new(:boolean, :stored, :indexed)
|
191
|
+
end
|
184
192
|
end
|
185
193
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module CurationConcerns
|
2
|
+
# A work should be able to be filtered out of search results if it's inactive
|
3
|
+
module Suppressible
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# This holds the workflow state
|
8
|
+
property :state, predicate: Vocab::FedoraResourceStatus.objState, multiple: false
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Used to restrict visibility on search results for a work that is inactive. If the state is not set, the
|
13
|
+
# default behavior is to consider the work not to be suppressed.
|
14
|
+
#
|
15
|
+
# Override this method if you have some criteria by which records should not display in the search results.
|
16
|
+
def suppressed?
|
17
|
+
return false if state.nil?
|
18
|
+
# This is a clumsy check only needed under RDF < 2.0 where there
|
19
|
+
# is a bug with `AT::Resource#==`
|
20
|
+
if RDF::VERSION.to_s < '2.0'
|
21
|
+
return state.rdf_subject == Vocab::FedoraResourceStatus.inactive
|
22
|
+
end
|
23
|
+
state == Vocab::FedoraResourceStatus.inactive
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_sipity_entity
|
27
|
+
raise "Can't create an entity until the model has been persisted" unless persisted?
|
28
|
+
@sipity_entity ||= Sipity::Entity.find_by(proxy_for_global_id: to_global_id.to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -16,7 +16,7 @@ module CurationConcerns::WorkBehavior
|
|
16
16
|
include Hydra::AccessControls::Embargoable
|
17
17
|
include GlobalID::Identification
|
18
18
|
include CurationConcerns::NestedWorks
|
19
|
-
include CurationConcerns::
|
19
|
+
include CurationConcerns::Suppressible
|
20
20
|
|
21
21
|
included do
|
22
22
|
property :owner, predicate: RDF::URI.new('http://opaquenamespace.org/ns/hydra/owner'), multiple: false
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module CurationConcerns
|
2
|
+
class InspectWorkPresenter
|
3
|
+
def initialize(solr_document, current_ability)
|
4
|
+
@solr_document = solr_document
|
5
|
+
@current_ability = current_ability
|
6
|
+
end
|
7
|
+
attr_reader :solr_document, :current_ability
|
8
|
+
|
9
|
+
def workflow
|
10
|
+
return { comments: [], roles: [] } unless sipity_entity
|
11
|
+
{
|
12
|
+
entity_id: sipity_entity.id,
|
13
|
+
proxy_for: sipity_entity.proxy_for_global_id,
|
14
|
+
workflow_id: sipity_entity.workflow_id,
|
15
|
+
workflow_name: sipity_entity.workflow_name,
|
16
|
+
state_id: sipity_entity.workflow_state_id,
|
17
|
+
state_name: sipity_entity.workflow_state_name,
|
18
|
+
comments: workflow_comments,
|
19
|
+
roles: sipity_entity_roles
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def solr
|
24
|
+
@solr_document.inspect
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def sipity_entity
|
30
|
+
@sipity_entity ||= PowerConverter.convert(solr_document, to: :sipity_entity)
|
31
|
+
end
|
32
|
+
|
33
|
+
def sipity_entity_roles
|
34
|
+
roles = CurationConcerns::Workflow::PermissionQuery.scope_roles_associated_with_the_given_entity(entity: solr_document)
|
35
|
+
roles.map do |role|
|
36
|
+
{ id: role.id, name: role.name, description: role.description, users: sipity_entity_role_users(role) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def sipity_entity_role_users(role)
|
41
|
+
users = CurationConcerns::Workflow::PermissionQuery.scope_users_for_entity_and_roles(entity: sipity_entity, roles: role)
|
42
|
+
users.map(&:user_key)
|
43
|
+
end
|
44
|
+
|
45
|
+
def workflow_comments
|
46
|
+
return [] unless sipity_entity && sipity_entity.comments.count > 0
|
47
|
+
sipity_entity.comments.map do |comment|
|
48
|
+
{ comment: comment.comment, created_at: comment.created_at }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -50,6 +50,10 @@ module CurationConcerns
|
|
50
50
|
@workflow ||= WorkflowPresenter.new(solr_document, current_ability)
|
51
51
|
end
|
52
52
|
|
53
|
+
def inspect_work
|
54
|
+
@inspect_workflow ||= InspectWorkPresenter.new(solr_document, current_ability)
|
55
|
+
end
|
56
|
+
|
53
57
|
# @return FileSetPresenter presenter for the representative FileSets
|
54
58
|
def representative_presenter
|
55
59
|
return nil if representative_id.blank?
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Search Builders
|
2
|
+
|
3
|
+
Building searches is core to any Blacklight app, and CurationConcerns is no exception.
|
4
|
+
This directory contains our Search Builders, so named because the design followed a builder pattern, meaning
|
5
|
+
that when invoked to set values, methods return the object itself, so that invocations can be chained, like:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
builder = Blacklight::SearchBuilder.new(processor_chain, scope)
|
9
|
+
.rows(20)
|
10
|
+
.page(3)
|
11
|
+
.with(q: 'Abraham Lincoln')
|
12
|
+
```
|
13
|
+
|
14
|
+
However, at this level, many if not most of the additional methods do not follow this pattern.
|
15
|
+
Refer to the `Blacklight::SearchBuilder` class if you want to be certain. That leads to the next topic...
|
16
|
+
|
17
|
+
## Ancestry
|
18
|
+
|
19
|
+
Most of the SearchBuilders have `::SearchBuilder` as a parent or ancestor. `::SearchBuilder` does not exist in any repo: it is generated
|
20
|
+
by Blacklight and modified by CurationConcerns. Others descend from `Blacklight::SearchBuilder`, or various other relatives.
|
21
|
+
|
22
|
+
### ::SearchBuilder
|
23
|
+
|
24
|
+
The generated parent class `SearchBuilder` descends from `Blacklight::SearchBuilder`.
|
25
|
+
As modified by CurationConcerns' installer, it includes additional modules and overrides. So if your SearchBuilder has `::SearchBuilder` as a parent class, you are getting:
|
26
|
+
- [Blacklight::SearchBuilder](https://github.com/projectblacklight/blacklight/blob/master/lib/blacklight/search_builder.rb) grandparent class
|
27
|
+
- [Blacklight::Solr::SearchBuilderBehavior](https://github.com/projectblacklight/blacklight/blob/master/lib/blacklight/solr/search_builder_behavior.rb) associated methods
|
28
|
+
- [Hydra::AccessControlsEnforcement](https://github.com/projecthydra/hydra-head/blob/master/hydra-access-controls/lib/hydra/access_controls_enforcement.rb) module
|
29
|
+
- [Blacklight::AccessControls::Enforcement](https://github.com/projectblacklight/blacklight-access_controls/blob/master/lib/blacklight/access_controls/enforcement.rb) ancestor of `Hydra::AccessControlsEnforcement`
|
30
|
+
- [CurationConcerns::SearchFilters](https://github.com/projecthydra/curation_concerns/blob/master/app/search_builders/curation_concerns/search_filters.rb) module that itself includes:
|
31
|
+
- [BlacklightAdvancedSearch::AdvancedSearchBuilder](https://github.com/projectblacklight/blacklight_advanced_search/blob/master/lib/blacklight_advanced_search/advanced_search_builder.rb) more magic for compound Boolean queries
|
32
|
+
- [CurationConcerns::FilterByType](https://github.com/projecthydra/curation_concerns/blob/master/app/search_builders/curation_concerns/filter_by_type.rb) Collection vs. Work filtering, specifically the `filter_models` method
|
33
|
+
|
34
|
+
This is not a comprehensive list, but it is sufficient to trace some of the complexity of interaction between various layers.
|
35
|
+
|
36
|
+
## Development: AKA Doing Something Useful
|
37
|
+
|
38
|
+
Note, the `default_processor_chain` defined by `Blacklight::Solr::SearchBuilderBehavior` provides a way to extend functionality, but also many possible points of override (namely method names). When you need to do something novel and additional, adding to the chain is completely reasonable. For example:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
module MySearchBuilder
|
42
|
+
extend ActiveSupport::Concern
|
43
|
+
|
44
|
+
included do
|
45
|
+
self.default_processor_chain += [:special_filter]
|
46
|
+
end
|
47
|
+
|
48
|
+
def special_filter(solr_parameters)
|
49
|
+
solr_parameters[:fq] << "{!field f=some_field_ssim}#{...}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
But to the extent that you are overriding (or undoing) something already done, `CurationConcerns::FileSetSearchBuilder` is a better example:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
module CurationConcerns
|
58
|
+
class FileSetSearchBuilder < ::SearchBuilder
|
59
|
+
include CurationConcerns::SingleResult
|
60
|
+
|
61
|
+
# This overrides the models in FilterByType
|
62
|
+
def models
|
63
|
+
[::FileSet]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
There is no point having the other `filter_models` methods apply `:fq`s that we then try to undo or overwrite. In general, directly overwriting the whole `default_processor_chain` or solr parameters like `:fq` is less flexible than appending constraints sufficient for your use case. In particular, you might find that you have overwritten components that implement access controls, thereby making your SearchBuilder less useful and less secure. When in doubt, examine the actual solr queries produced.
|
@@ -1,35 +1,53 @@
|
|
1
1
|
module CurationConcerns
|
2
|
+
# Our parent class is the generated SearchBuilder descending from Blacklight::SearchBuilder
|
3
|
+
# It includes Blacklight::Solr::SearchBuilderBehavior, Hydra::AccessControlsEnforcement, CurationConcerns::SearchFilters
|
4
|
+
# @see https://github.com/projectblacklight/blacklight/blob/master/lib/blacklight/search_builder.rb Blacklight::SearchBuilder parent
|
5
|
+
# @see https://github.com/projectblacklight/blacklight/blob/master/lib/blacklight/solr/search_builder_behavior.rb Blacklight::Solr::SearchBuilderBehavior
|
6
|
+
# @see https://github.com/projecthydra/curation_concerns/blob/master/app/search_builders/curation_concerns/README.md SearchBuilders README
|
7
|
+
# @note the default_processor_chain defined by Blacklight::Solr::SearchBuilderBehavior provides many possible points of override
|
8
|
+
#
|
2
9
|
class CollectionSearchBuilder < ::SearchBuilder
|
3
10
|
include FilterByType
|
4
11
|
# Defines which search_params_logic should be used when searching for Collections
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def some_rows(solr_parameters)
|
10
|
-
solr_parameters[:rows] = '100'
|
12
|
+
def initialize(context)
|
13
|
+
@rows = 100
|
14
|
+
super(context)
|
11
15
|
end
|
12
16
|
|
13
|
-
#
|
14
|
-
def
|
15
|
-
|
17
|
+
# @return [String] Solr field name indicating default sort order
|
18
|
+
def sort_field
|
19
|
+
Solrizer.solr_name('title', :sortable)
|
16
20
|
end
|
17
21
|
|
18
|
-
#
|
19
|
-
#
|
20
|
-
def
|
21
|
-
|
22
|
-
solr_parameters[:sort] ||= "#{sort_field} asc"
|
22
|
+
# @return [Hash{Symbol => Array[Symbol]}] bottom-up map of "what you need" to "what qualifies"
|
23
|
+
# @note i.e., requiring :read access is satisfied by either :read or :edit access
|
24
|
+
def access_levels
|
25
|
+
{ read: [:read, :edit], edit: [:edit] }
|
23
26
|
end
|
24
27
|
|
25
|
-
attr_writer :discovery_perms
|
28
|
+
attr_writer :discovery_perms # TODO: remove this line
|
29
|
+
## Overrides
|
26
30
|
|
31
|
+
# unprotect lib/blacklight/access_controls/enforcement.rb methods
|
32
|
+
# Remove these when https://github.com/projectblacklight/blacklight-access_controls/pull/23 is merged/released/required
|
27
33
|
def discovery_permissions
|
28
34
|
@discovery_perms || super
|
29
35
|
end
|
30
36
|
|
31
|
-
def
|
32
|
-
|
37
|
+
def discovery_permissions=(*args)
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
# This overrides the models in FilterByType
|
42
|
+
def models
|
43
|
+
collection_classes
|
44
|
+
end
|
45
|
+
|
46
|
+
# Sort results by title if no query was supplied.
|
47
|
+
# This overrides the default 'relevance' sort.
|
48
|
+
def add_sorting_to_solr(solr_parameters)
|
49
|
+
return if solr_parameters[:q]
|
50
|
+
solr_parameters[:sort] ||= "#{sort_field} asc"
|
33
51
|
end
|
34
52
|
end
|
35
53
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CurationConcerns
|
2
|
+
# Injects a search builder filter to hide documents marked as suppressed
|
3
|
+
module FilterSuppressed
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
self.default_processor_chain += [:only_active_works]
|
8
|
+
end
|
9
|
+
|
10
|
+
def only_active_works(solr_parameters)
|
11
|
+
solr_parameters[:fq] ||= []
|
12
|
+
solr_parameters[:fq] << '-suppressed_bsi:true'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module CurationConcerns
|
2
|
+
# Overrides FilterSuppressed filter to hide documents marked as
|
3
|
+
# suppressed when the current user is permitted to take no workflow
|
4
|
+
# actions for the work's current state
|
5
|
+
#
|
6
|
+
# Assumes presence of `blacklight_params[:id]` and a SolrDocument
|
7
|
+
# corresponding to that `:id` value
|
8
|
+
module FilterSuppressedWithRoles
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
include CurationConcerns::FilterSuppressed
|
11
|
+
|
12
|
+
# Skip the filter if the current user is permitted to take
|
13
|
+
# workflow actions on the work corresponding to the SolrDocument
|
14
|
+
# with id = `blacklight_params[:id]`
|
15
|
+
def only_active_works(solr_parameters)
|
16
|
+
return if user_has_active_workflow_role?
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def current_work
|
23
|
+
SolrDocument.find(blacklight_params[:id])
|
24
|
+
end
|
25
|
+
|
26
|
+
def user_has_active_workflow_role?
|
27
|
+
CurationConcerns::Workflow::PermissionQuery.scope_permitted_workflow_actions_available_for_current_state(user: current_ability.current_user, entity: current_work).any?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module CurationConcerns::SearchFilters
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
include CurationConcerns::FilterByType
|
4
|
+
include CurationConcerns::FilterSuppressed
|
4
5
|
|
5
6
|
# Override Hydra::AccessControlsEnforcement (or Hydra::PolicyAwareAccessControlsEnforcement)
|
6
7
|
# Allows admin users to see everything (don't apply any gated_discovery_filters for those users)
|
@@ -30,19 +30,6 @@ module CurationConcerns
|
|
30
30
|
def presenter_class
|
31
31
|
CurationConcerns::EmbargoPresenter
|
32
32
|
end
|
33
|
-
|
34
|
-
def presenters(builder)
|
35
|
-
response = repository.search(builder)
|
36
|
-
response.documents.map { |d| presenter_class.new(d) }
|
37
|
-
end
|
38
|
-
|
39
|
-
def repository
|
40
|
-
config.repository
|
41
|
-
end
|
42
|
-
|
43
|
-
def config
|
44
|
-
@config ||= ::CatalogController.new
|
45
|
-
end
|
46
33
|
end
|
47
34
|
end
|
48
35
|
end
|
@@ -2,46 +2,56 @@ module CurationConcerns
|
|
2
2
|
module Workflow
|
3
3
|
# Responsible for performing additional functions when the given criteria is met.
|
4
4
|
class ActionTakenService
|
5
|
-
# For the given
|
5
|
+
# For the given target and :action
|
6
6
|
# - Find the appropriate "function" to call
|
7
|
-
# - Then call that function. If the function returns a truthy value, then save the
|
8
|
-
def self.handle_action_taken(
|
9
|
-
new(
|
7
|
+
# - Then call that function. If the function returns a truthy value, then save the target
|
8
|
+
def self.handle_action_taken(target:, action:, comment:, user:)
|
9
|
+
new(target: target,
|
10
10
|
action: action,
|
11
11
|
comment: comment,
|
12
12
|
user: user).call
|
13
13
|
end
|
14
14
|
|
15
|
-
def initialize(
|
16
|
-
@
|
15
|
+
def initialize(target:, action:, comment:, user:)
|
16
|
+
@target = target
|
17
17
|
@action = action
|
18
18
|
@comment = comment
|
19
19
|
@user = user
|
20
20
|
end
|
21
21
|
|
22
|
-
attr_reader :action, :
|
22
|
+
attr_reader :action, :target, :comment, :user
|
23
23
|
|
24
|
+
# Calls all the workflow methods for this action. Stops calling methods if any return falsy
|
25
|
+
# @return [Boolean] true if all methods returned a truthy result
|
24
26
|
def call
|
25
27
|
return unless action.triggered_methods.any?
|
26
28
|
success = action.triggered_methods.order(:weight).all? do |method|
|
27
|
-
process_action(method.service_name)
|
29
|
+
status = process_action(method.service_name)
|
30
|
+
Rails.logger.debug("Result of #{method.service_name} is #{status}")
|
31
|
+
status
|
28
32
|
end
|
29
33
|
|
30
|
-
return
|
31
|
-
Rails.logger.error "Not all workflow methods were successful, so not saving (#{
|
34
|
+
return target.save if success
|
35
|
+
Rails.logger.error "Not all workflow methods were successful, so not saving (#{target.id})"
|
32
36
|
false
|
33
37
|
end
|
34
38
|
|
39
|
+
# @param service_name [String] the fully qualified class name to run the `call` method on
|
40
|
+
# @yieldparam status the result of calling the method
|
41
|
+
# @return the result of calling the method
|
35
42
|
def process_action(service_name)
|
36
43
|
service = resolve_service(service_name)
|
37
44
|
return unless service
|
38
|
-
service.call(
|
39
|
-
|
40
|
-
|
45
|
+
result = service.call(target: target,
|
46
|
+
comment: comment,
|
47
|
+
user: user)
|
48
|
+
yield(result) if block_given?
|
49
|
+
result
|
41
50
|
end
|
42
51
|
|
43
|
-
|
44
|
-
|
52
|
+
# @param class_name [String] the fully qualified class name to run
|
53
|
+
# @return [Class, NilClass] return nil if unable to locate the class
|
54
|
+
def resolve_service(class_name)
|
45
55
|
klass = begin
|
46
56
|
class_name.constantize
|
47
57
|
rescue NameError
|
@@ -1,8 +1,15 @@
|
|
1
1
|
module CurationConcerns
|
2
2
|
module Workflow
|
3
3
|
class ActivateObject
|
4
|
-
|
5
|
-
|
4
|
+
##
|
5
|
+
# This is a built in function for workflow, setting the `#state`
|
6
|
+
# of the target to the Fedora 'active' status URI
|
7
|
+
#
|
8
|
+
# @param target [#state] an instance of a model that includes `CurationConcerns::Suppressible`
|
9
|
+
#
|
10
|
+
# @return [RDF::Vocabulary::Term] the Fedora Resource Status 'active' term
|
11
|
+
def self.call(target:, **)
|
12
|
+
target.state = Vocab::FedoraResourceStatus.active
|
6
13
|
end
|
7
14
|
end
|
8
15
|
end
|