Skip to content

Commit

Permalink
Solidify abilities using permission services
Browse files Browse the repository at this point in the history
  • Loading branch information
elrayle committed Oct 8, 2017
1 parent 8b6beb6 commit 6129ffe
Show file tree
Hide file tree
Showing 23 changed files with 1,424 additions and 496 deletions.
2 changes: 1 addition & 1 deletion app/controllers/hyrax/admin/collection_types_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def new
def create
@collection_type = Hyrax::CollectionType.new(collection_type_params)
if @collection_type.save
Hyrax::CollectionTypes::PermissionsService.add_default_participants(@collection_type.id)
Hyrax::CollectionTypes::CreateService.add_default_participants(@collection_type.id)
redirect_to hyrax.edit_admin_collection_type_path(@collection_type), notice: t(:'hyrax.admin.collection_types.create.notification', name: @collection_type.title)
else
setup_form
Expand Down
57 changes: 10 additions & 47 deletions app/models/concerns/hyrax/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ module Ability
extend ActiveSupport::Concern

included do
include Hyrax::Ability::AdminSetAbility
include Hyrax::Ability::CollectionAbility
include Hyrax::Ability::CollectionTypeAbility
include Hyrax::Ability::PermissionTemplateAbility

class_attribute :admin_group_name, :registered_group_name
self.admin_group_name = 'admin'
self.registered_group_name = 'registered'
Expand All @@ -19,6 +24,9 @@ module Ability
:uploaded_file_abilities,
:feature_abilities,
:admin_set_abilities,
:collection_abilities,
:collection_type_abilities,
:permission_template_abilities,
:trophy_abilities]
end

Expand Down Expand Up @@ -46,7 +54,7 @@ def download_users(id)
def can_create_any_work?
Hyrax.config.curation_concerns.any? do |curation_concern_type|
can?(:create, curation_concern_type)
end && source_ids_for_deposit.any?
end && Hyrax::Collections::PermissionsService.admin_set_ids_for_user(user: current_user, access: ['deposit', 'manage'], ability: self).any?
end

# Override this method in your ability model if you use a different group
Expand All @@ -55,35 +63,6 @@ def admin?
user_groups.include? admin_group_name
end

# @return [Array<String>] a list of admin set ids for admin sets the user
# has deposit or manage permissions to.
def source_ids_for_deposit
source_ids_for_roles(['deposit', 'manage'])
end

# @return [Array<String>] a list of admin set ids for admin sets the user
# has manage permissions to.
def source_ids_for_management
source_ids_for_roles(['manage'])
end

# @param [Array<String>] roles the roles to be used when searching for admin
# sets for the user
# @return [Array<String>] a list of admin set ids for admin sets the user
# that match the roles
def source_ids_for_roles(roles)
PermissionTemplateAccess.joins(:permission_template)
.where(agent_type: 'user',
agent_id: current_user.user_key,
access: roles)
.or(
PermissionTemplateAccess.joins(:permission_template)
.where(agent_type: 'group',
agent_id: user_groups,
access: roles)
).pluck('DISTINCT source_id')
end

private

# This overrides hydra-head, (and restores the method from blacklight-access-controls)
Expand Down Expand Up @@ -162,23 +141,6 @@ def feature_abilities
can :manage, Hyrax::Feature if admin?
end

def admin_set_abilities
can :manage, [AdminSet, Hyrax::PermissionTemplate, Hyrax::PermissionTemplateAccess] if admin?
can :manage_any, AdminSet if admin? || source_ids_for_management.present?

can [:create, :edit, :update, :destroy], Hyrax::PermissionTemplate do |template|
test_edit(template.source_id)
end

can [:create, :edit, :update, :destroy], Hyrax::PermissionTemplateAccess do |access|
test_edit(access.permission_template.source_id)
end

can :review, :submissions do
can_review_submissions?
end
end

def operation_abilities
can :read, Hyrax::Operation, user_id: current_user.id
end
Expand Down Expand Up @@ -217,6 +179,7 @@ def admin_permissions
can :manage, :collection_types
end

# TODO: elr - How is this used? How does it fit with collection participants?
def add_to_collection
return unless registered_user?
alias_action :files, to: :read # members will be filtered separately
Expand Down
31 changes: 31 additions & 0 deletions app/models/concerns/hyrax/ability/admin_set_ability.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Hyrax
module Ability
module AdminSetAbility
def admin_set_abilities # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
can :manage, AdminSet if admin?
can :manage_any, AdminSet if admin? ||
Hyrax::Collections::PermissionsService.can_manage_any_admin_set?(ability: self)
can :create_any, AdminSet if admin? ||
Hyrax::CollectionTypes::PermissionsService.can_create_admin_set_collection_type?(ability: self)
can :view_admin_show_any, AdminSet if admin? ||
Hyrax::Collections::PermissionsService.can_view_admin_show_for_any_admin_set?(ability: self)
can [:edit, :update, :destroy], AdminSet do |admin_set|
test_edit(admin_set.id)
end
can :deposit, AdminSet do |admin_set|
Hyrax::Collections::PermissionsService.can_deposit_in_collection?(ability: self, collection: admin_set)
end
can :view_admin_show, AdminSet do |admin_set| # admin show page
Hyrax::Collections::PermissionsService.can_view_admin_show_for_collection?(ability: self, collection: admin_set)
end
can :read, AdminSet do |admin_set| # public show page
test_read(admin_set.id)
end

can :review, :submissions do
can_review_submissions?
end
end
end
end
end
27 changes: 27 additions & 0 deletions app/models/concerns/hyrax/ability/collection_ability.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Hyrax
module Ability
module CollectionAbility
def collection_abilities # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
can :manage, Collection if admin?
can :manage_any, Collection if admin? ||
Hyrax::Collections::PermissionsService.can_manage_any_collection?(ability: self)
can :create_any, Collection if admin? ||
Hyrax::CollectionTypes::PermissionsService.can_create_any_collection_type?(ability: self)
can :view_admin_show_any, Collection if admin? ||
Hyrax::Collections::PermissionsService.can_view_admin_show_for_any_collection?(ability: self)
can [:edit, :update, :destroy], Collection do |collection|
test_edit(collection.id)
end
can :deposit, Collection do |collection|
Hyrax::Collections::PermissionsService.can_deposit_in_collection?(user: current_user, collection: collection)
end
can :view_admin_show, Collection do |collection| # admin show page
Hyrax::Collections::PermissionsService.can_view_admin_show_for_collection?(user: current_user, collection: collection)
end
can :read, Collection do |collection| # public show page
test_read(collection.id)
end
end
end
end
end
12 changes: 12 additions & 0 deletions app/models/concerns/hyrax/ability/collection_type_ability.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Hyrax
module Ability
module CollectionTypeAbility
def collection_type_abilities
can :manage, CollectionType if admin?
can :create_collection_of_type, CollectionType do |collection_type|
Hyrax::CollectionTypes::PermissionsService.can_create_collection_of_type?(user: current_user, collection_type: collection_type)
end
end
end
end
end
16 changes: 16 additions & 0 deletions app/models/concerns/hyrax/ability/permission_template_ability.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Hyrax
module Ability
module PermissionTemplateAbility
def permission_template_abilities
can :manage, [Hyrax::PermissionTemplate, Hyrax::PermissionTemplateAccess] if admin?

can [:create, :edit, :update, :destroy], Hyrax::PermissionTemplate do |template|
test_edit(template.source_id)
end
can [:create, :edit, :update, :destroy], Hyrax::PermissionTemplateAccess do |access|
test_edit(access.permission_template.source_id)
end
end
end
end
end
9 changes: 6 additions & 3 deletions app/search_builders/hyrax/admin_set_search_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ def discovery_permissions
# @return [Array<String>] a list of filters to apply to the solr query
def gated_discovery_filters
return super if @access != :deposit
["{!terms f=id}#{source_ids_for_deposit.join(',')}"]
["{!terms f=id}#{admin_set_ids_for_deposit.join(',')}"]
end

delegate :source_ids_for_deposit, to: :current_ability
private :source_ids_for_deposit
private

def admin_set_ids_for_deposit
Hyrax::Collections::PermissionsService.admin_set_ids_for_deposit(ability: current_ability)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Dashboard
class CollectionsSearchBuilder < Hyrax::CollectionSearchBuilder
include Hyrax::Dashboard::ManagedSearchFilters

self.solr_access_filters_logic += [:apply_admin_set_deposit_permissions]
self.solr_access_filters_logic += [:apply_collection_deposit_permissions]
self.default_processor_chain += [:show_only_managed_collections_for_non_admins]

# This overrides the models in FilterByType
Expand All @@ -26,14 +26,17 @@ def show_only_managed_collections_for_non_admins(solr_parameters)

# Include all admin sets the user has deposit permission for.
# @return [Array{String}] values are lucence syntax term queries suitable for :fq
def apply_admin_set_deposit_permissions(_permission_types, _ability = current_ability)
collection_ids = source_ids_for_deposit
def apply_collection_deposit_permissions(_permission_types, _ability = current_ability)
collection_ids = collection_ids_for_deposit
return [] if collection_ids.empty?
["{!terms f=id}#{collection_ids.join(',')}"]
end

delegate :source_ids_for_deposit, to: :current_ability
private :source_ids_for_deposit
private

def collection_ids_for_deposit
Hyrax::Collections::PermissionsService.collection_ids_for_deposit(ability: current_ability)
end
end
end
end
57 changes: 54 additions & 3 deletions app/services/hyrax/collection_types/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,23 @@ class CreateService
{ agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, agent_id: ::Ability.registered_group_name, access: Hyrax::CollectionTypeParticipant::CREATE_ACCESS }]
}.freeze

# @api public
#
# Create a new collection type.
#
# @param machine_id [String]
# @param title [String]
# @param title [String] short tag identifying the collection type
# @param options [Hash] options to override DEFAULT_OPTIONS
# @return [Hyrax::CollectionType]
# @option options [String] :description a description to show the user when selecting the collection type
# @option options [True | False] :nestable if true, collections of this type can be nested
# @option options [True | False] :discoverable if true, collections of this type can be marked Public and found in search results
# @option options [True | False] :sharable if true, collections of this type can have participants added for :manage, :deposit, or :view access
# @option options [True | False] :allow_multiple_membership if true, works can be members of multiple collections of this type
# @option options [True | False] :require_membership if true, all works must belong to at least one collection of this type. When combined
# with allow_multiple_membership=false, works can belong to one and only one collection of this type.
# @option options [True | False] :assigns_workflow if true, collections of this type can be used to assign a workflow to a work
# @option options [True | False] :assigns_visibility if true, collections of this type can be used to assign initial visibility to a work
# @return [Hyrax::CollectionType] the newly created collection type instance
def self.create_collection_type(machine_id: DEFAULT_MACHINE_ID, title: DEFAULT_TITLE, options: {})
opts = DEFAULT_OPTIONS.merge(options)
ct = Hyrax::CollectionType.create!(machine_id: machine_id, title: title) do |c|
Expand All @@ -42,9 +55,47 @@ def self.create_collection_type(machine_id: DEFAULT_MACHINE_ID, title: DEFAULT_T
c.assigns_workflow = opts[:assigns_workflow]
c.assigns_visibility = opts[:assigns_visibility]
end
Hyrax::CollectionTypes::PermissionsService.add_participants(ct.id, opts[:participants])
add_participants(ct.id, opts[:participants])
ct
end

# @api public
#
# Add the default participants to a collection_type.
#
# @param collection_type_id [Integer] the id of the collection type
# @note Several checks get the user's groups from the user's ability. The same values can be retrieved directly from a passed in ability.
# If calling from Abilities, pass the ability. If you try to get the ability from the user, you end up in an infinit loop.
def self.add_default_participants(collection_type_id)
return unless collection_type_id
default_participants = [{ agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE,
agent_id: ::Ability.admin_group_name,
access: Hyrax::CollectionTypeParticipant::MANAGE_ACCESS },
{ agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE,
agent_id: ::Ability.registered_group_name,
access: Hyrax::CollectionTypeParticipant::CREATE_ACCESS }]
add_participants(collection_type_id, default_participants)
end

# @api public
#
# Add a participants to a collection_type.
#
# @param collection_type_id [Integer] the id of the collection type
# @param participants [Array<Hash>] each element holds agent_type, agent_id, and access for a participant to be added
def self.add_participants(collection_type_id, participants)
return unless collection_type_id && participants.count > 0
participants.each do |p|
begin
agent_type = p.fetch(:agent_type)
agent_id = p.fetch(:agent_id)
access = p.fetch(:access)
Hyrax::CollectionTypeParticipant.create!(hyrax_collection_type_id: collection_type_id, agent_type: agent_type, agent_id: agent_id, access: access)
rescue
Rails.logger.error "Participant not created for collection type #{collection_type_id}: #{agent_type}, #{agent_id}, #{access}\n"
end
end
end
end
end
end
Loading

0 comments on commit 6129ffe

Please sign in to comment.