From 8b6beb69de63e0b21110408a7f70c3de30ed3841 Mon Sep 17 00:00:00 2001 From: "E. Lynette Rayle" Date: Mon, 2 Oct 2017 14:11:50 -0400 Subject: [PATCH 1/2] Adjust permission service methods to be what is actually needed for abilities checks --- .../hyrax/dashboard/collections_controller.rb | 2 +- .../collections/permissions_create_service.rb | 71 +++++ .../hyrax/collections/permissions_service.rb | 258 ++++++++-------- .../permissions_create_service_spec.rb | 41 +++ .../collections/permissions_service_spec.rb | 284 +++++++++++++----- 5 files changed, 469 insertions(+), 187 deletions(-) create mode 100644 app/services/hyrax/collections/permissions_create_service.rb create mode 100644 spec/services/hyrax/collections/permissions_create_service_spec.rb diff --git a/app/controllers/hyrax/dashboard/collections_controller.rb b/app/controllers/hyrax/dashboard/collections_controller.rb index 1f9c6bbdff..8166fc9c03 100644 --- a/app/controllers/hyrax/dashboard/collections_controller.rb +++ b/app/controllers/hyrax/dashboard/collections_controller.rb @@ -472,7 +472,7 @@ def form end def set_default_permissions - Collections::PermissionsService.create_default(collection: @collection, creating_user: current_user, grants: @participants) + Collections::PermissionsCreateService.create_default(collection: @collection, creating_user: current_user, grants: @participants) end end end diff --git a/app/services/hyrax/collections/permissions_create_service.rb b/app/services/hyrax/collections/permissions_create_service.rb new file mode 100644 index 0000000000..137c8d7d98 --- /dev/null +++ b/app/services/hyrax/collections/permissions_create_service.rb @@ -0,0 +1,71 @@ +module Hyrax + module Collections + class PermissionsCreateService + # @api public + # + # Set the default permissions for a (newly created) collection + # + # @param collection [Collection] the collection the new permissions will act on + # @param creating_user [User] the user that created the collection + # @param grants [Array] additional grants to apply to the new collection + # @return [Hyrax::PermissionTemplate] + def self.create_default(collection:, creating_user:, grants: []) + collection_type = Hyrax::CollectionType.find_by_gid!(collection.collection_type_gid) + access_grants = access_grants_attributes(collection_type: collection_type, creating_user: creating_user, grants: grants) + PermissionTemplate.create!(source_id: collection.id, source_type: 'collection', + access_grants_attributes: access_grants.uniq) + collection.update_access_controls! + end + + # @api private + # + # Gather the default permissions needed for a new collection + # + # @param collection_type [CollectionType] the collection type of the new collection + # @param creating_user [User] the user that created the collection + # @param grants [Array] additional grants to apply to the new collection + # @return [Hash] a hash containing permission attributes + def self.access_grants_attributes(collection_type:, creating_user:, grants:) + [ + { agent_type: 'group', agent_id: admin_group_name, access: Hyrax::PermissionTemplateAccess::MANAGE } + ].tap do |attribute_list| + # Grant manage access to the creating_user if it exists + if creating_user + attribute_list << { agent_type: 'user', agent_id: creating_user.user_key, access: Hyrax::PermissionTemplateAccess::MANAGE } + end + end + managers_of_collection_type(collection_type: collection_type) + grants + end + private_class_method :access_grants_attributes + + # @api private + # + # Retrieve the users or groups with manage permissions for a collection type + # + # @param collection_type [CollectionType] the collection type of the new collection + # @return [Hash] a hash containing permission attributes + def self.managers_of_collection_type(collection_type:) + attribute_list = [] + user_managers = Hyrax::CollectionTypes::PermissionsService.user_edit_grants_for_collection_of_type(collection_type: collection_type) + user_managers.each do |user| + attribute_list << { agent_type: 'user', agent_id: user, access: Hyrax::PermissionTemplateAccess::MANAGE } + end + group_managers = Hyrax::CollectionTypes::PermissionsService.group_edit_grants_for_collection_of_type(collection_type: collection_type) + group_managers.each do |group| + attribute_list << { agent_type: 'group', agent_id: group, access: Hyrax::PermissionTemplateAccess::MANAGE } + end + attribute_list + end + private_class_method :managers_of_collection_type + + # @api private + # + # The value of the admin group name + # + # @return [String] a string representation of the admin group name + def self.admin_group_name + ::Ability.admin_group_name + end + private_class_method :admin_group_name + end + end +end diff --git a/app/services/hyrax/collections/permissions_service.rb b/app/services/hyrax/collections/permissions_service.rb index b50db30b68..ae9a5dba02 100644 --- a/app/services/hyrax/collections/permissions_service.rb +++ b/app/services/hyrax/collections/permissions_service.rb @@ -1,74 +1,105 @@ module Hyrax module Collections class PermissionsService - # @api private + # @api public # - # IDs of collections, including admin sets, a user can access based on participant roles. + # IDs of admin sets a user can access based on participant roles. # # @param user [User] user # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) - # @return [Array] IDs of collections for which the user has specified roles - def self.collection_ids_for_user(user:, access:) # rubocop:disable Metrics/MethodLength - if user.ability.admin? - PermissionTemplate.all.where(source_type: 'collection').pluck('DISTINCT source_id') + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Array] IDs of admin sets for which the user has specified roles + def self.admin_set_ids_for_user(user:, access:, ability: nil) + if user_admin?(user, ability) + PermissionTemplate.all.where(source_type: 'admin_set').pluck('DISTINCT source_id') else PermissionTemplateAccess.joins(:permission_template) - .where(agent_type: 'user', - agent_id: user.user_key, - access: access) + .where(user_where(user: user, access: access, source_type: 'admin_set')) .or( PermissionTemplateAccess.joins(:permission_template) - .where(agent_type: 'group', - agent_id: user.groups, - access: access) + .where(group_where(user: user, access: access, source_type: 'admin_set', ability: ability)) ).pluck('DISTINCT source_id') end end - private_class_method :collection_ids_for_user # @api public # - # IDs of collections, including admin sets, for which the user is assigned view access + # IDs of collections a user can access based on participant roles. # - # @param user [User] - # @return [Array] a list of collection ids for which the user is assigned view access - def self.collection_ids_with_view_access(user:) - return [] unless user - collection_ids_for_user(user: user, access: [Hyrax::PermissionTemplateAccess::VIEW]) + # @param user [User] user + # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Array] IDs of collections for which the user has specified roles + def self.collection_ids_for_user(user:, access:, ability: nil) + if user_admin?(user, ability) + PermissionTemplate.all.where(source_type: 'collection').pluck('DISTINCT source_id') + else + PermissionTemplateAccess.joins(:permission_template) + .where(user_where(user: user, access: access, source_type: 'collection')) + .or( + PermissionTemplateAccess.joins(:permission_template) + .where(group_where(user: user, access: access, source_type: 'collection', ability: ability)) + ).pluck('DISTINCT source_id') + end end # @api public # - # IDs of collections, including admin sets, for which the user is assigned manage access + # IDs of collections and admin_sets a user can access based on participant roles. # - # @param user [User] - # @return [Array] a list of collection ids for which the user is assigned manage access - def self.collection_ids_with_manage_access(user:) - return [] unless user - collection_ids_for_user(user: user, access: [Hyrax::PermissionTemplateAccess::MANAGE]) + # @param user [User] user + # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Array] IDs of collections and admin sets for which the user has specified roles + def self.source_ids_for_user(user:, access:, ability: nil) + if user_admin?(user, ability) + PermissionTemplate.all.pluck('DISTINCT source_id') + else + PermissionTemplateAccess.joins(:permission_template) + .where(user_where(user: user, access: access)) + .or( + PermissionTemplateAccess.joins(:permission_template) + .where(group_where(user: user, access: access, ability: ability)) + ).pluck('DISTINCT source_id') + end end - # @api public + # @api private # - # IDs of collections, including admin sets, for which the user is assigned deposit access + # Generate the user where clause hash for joining the permissions tables # - # @param user [User] - # @return [Array] a list of collection ids for which the user is assigned deposit access - def self.collection_ids_with_deposit_access(user:) - return [] unless user - collection_ids_for_user(user: user, access: [Hyrax::PermissionTemplateAccess::DEPOSIT]) + # @param user [User] the user wanting access + # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param source_type [String] 'collection', 'admin_set', or nil to get all types + # @return [Hash] the where clause hash to pass to joins for users + def self.user_where(user:, access:, source_type: nil) + where_clause = {} + where_clause[:agent_type] = 'user' + where_clause[:agent_id] = user.user_key + where_clause[:access] = access + where_clause[:permission_templates] = { source_type: source_type } if source_type.present? + where_clause end + private_class_method :user_where - # @api public + # @api private # - # IDs of collections, including admin sets, into which the user can deposit + # Generate the group where clause hash for joining the permissions tables # - # @param user [User] the user that wants to deposit - # @return [Array] a list of collection ids for collections in which the user can deposit - def self.collection_ids_for_deposit(user:) - return [] unless user - collection_ids_for_user(user: user, access: [Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT]) + # @param user [User] the user wanting access + # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param source_type [String] 'collection', 'admin_set', or nil to get all types + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Hash] the where clause hash to pass to joins for groups + def self.group_where(user:, access:, source_type: nil, ability: nil) + where_clause = {} + where_clause[:agent_type] = 'group' + where_clause[:agent_id] = user_groups(user, ability) + where_clause[:access] = access + where_clause[:permission_templates] = { source_type: source_type } if source_type.present? + where_clause end + private_class_method :user_where # @api public # @@ -76,109 +107,102 @@ def self.collection_ids_for_deposit(user:) # # @param user [User] the user that wants to deposit # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param ability [Ability] the ability coming from cancan ability check (default: nil) # @return [Boolean] true if the user has permission to deposit into the collection - def self.can_deposit_in_collection(user:, collection:) - return false unless user && collection - template = Hyrax::PermissionTemplate.find_by!(source_id: collection.id) - return true if access_as_user?(user: user, template: template) - return true if access_through_group?(groups: user.user_groups, template: template) - false + def self.can_deposit_in_collection?(user:, collection:, ability: nil) + deposit_access_to_collection?(user: user, collection: collection, ability: ability) || + manage_access_to_collection?(user: user, collection: collection, ability: ability) end - # @api private + # @api public # - # Does the user have 'manage' or 'deposit' access? + # Determine if the given user has permissions to view the admin show page for the collection # - # @param user [User] the user that wants to deposit in the collection - # @param template [PermissionTemplate] the permission template controlling access - # @return [True | False] true, if user has access; otherwise, false - def self.access_as_user?(user:, template:) - return true if template.agent_ids_for(agent_type: 'user', access: 'manage').include? user.user_key - return true if template.agent_ids_for(agent_type: 'user', access: 'deposit').include? user.user_key - false + # @param user [User] the user that wants to view + # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Boolean] true if the user has permission to view the admin show page for the collection + def self.can_view_admin_show_for_collection?(user:, collection:, ability: nil) + deposit_access_to_collection?(user: user, collection: collection, ability: ability) || + manage_access_to_collection?(user: user, collection: collection, ability: ability) || + view_access_to_collection?(user: user, collection: collection, ability: ability) end - private_class_method :access_as_user? # @api private # - # Do any of the groups have 'manage' or 'deposit' access? + # Determine if the given user has :deposit access for the given collection # - # @param groups [Array] the groups for the user that wants to deposit in the collection - # @param template [PermissionTemplate] the permission template controlling access - # @return [True | False] true, if any of the groups have access; otherwise, false - def self.access_through_group?(groups:, template:) - return false if groups.blank? - return true if groups & template.agent_ids_for(agent_type: 'group', access: 'manage') - return true if groups & template.agent_ids_for(agent_type: 'group', access: 'deposit') - false - end - private_class_method :access_through_group? - - # @api public - # - # Set the default permissions for a (newly created) collection - # - # @param collection [Collection] the collection the new permissions will act on - # @param creating_user [User] the user that created the collection - # @param grants [Array] additional grants to apply to the new collection - # @return [Hyrax::PermissionTemplate] - def self.create_default(collection:, creating_user:, grants: []) - collection_type = Hyrax::CollectionType.find_by_gid!(collection.collection_type_gid) - access_grants = access_grants_attributes(collection_type: collection_type, creating_user: creating_user, grants: grants) - PermissionTemplate.create!(source_id: collection.id, source_type: 'collection', - access_grants_attributes: access_grants.uniq) - collection.update_access_controls! + # @param user [User] the user who wants to deposit + # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Boolean] true if the user has :deposit access to the collection + def self.deposit_access_to_collection?(user:, collection:, ability: nil) + access_to_collection?(user: user, collection: collection, access: 'deposit', ability: ability) end + private_class_method :deposit_access_to_collection? # @api private # - # Gather the default permissions needed for a new collection - # - # @param collection_type [CollectionType] the collection type of the new collection - # @param creating_user [User] the user that created the collection - # @param grants [Array] additional grants to apply to the new collection - # @return [Hash] a hash containing permission attributes - def self.access_grants_attributes(collection_type:, creating_user:, grants:) - [ - { agent_type: 'group', agent_id: admin_group_name, access: Hyrax::PermissionTemplateAccess::MANAGE } - ].tap do |attribute_list| - # Grant manage access to the creating_user if it exists - if creating_user - attribute_list << { agent_type: 'user', agent_id: creating_user.user_key, access: Hyrax::PermissionTemplateAccess::MANAGE } - end - end + managers_of_collection_type(collection_type: collection_type) + grants + # Determine if the given user has :manage access for the given collection + # + # @param user [User] the user who wants to manage + # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Boolean] true if the user has :manage access to the collection + def self.manage_access_to_collection?(user:, collection:, ability: nil) + access_to_collection?(user: user, collection: collection, access: 'manage', ability: ability) end - private_class_method :access_grants_attributes + private_class_method :manage_access_to_collection? # @api private # - # Retrieve the users or groups with manage permissions for a collection type + # Determine if the given user has :view access for the given collection # - # @param collection_type [CollectionType] the collection type of the new collection - # @return [Hash] a hash containing permission attributes - def self.managers_of_collection_type(collection_type:) - attribute_list = [] - user_managers = Hyrax::CollectionTypes::PermissionsService.user_edit_grants_for_collection_of_type(collection_type: collection_type) - user_managers.each do |user| - attribute_list << { agent_type: 'user', agent_id: user, access: Hyrax::PermissionTemplateAccess::MANAGE } - end - group_managers = Hyrax::CollectionTypes::PermissionsService.group_edit_grants_for_collection_of_type(collection_type: collection_type) - group_managers.each do |group| - attribute_list << { agent_type: 'group', agent_id: group, access: Hyrax::PermissionTemplateAccess::MANAGE } - end - attribute_list + # @param user [User] the user who wants to view + # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Boolean] true if the user has permission to view the collection + def self.view_access_to_collection?(user:, collection:, ability: nil) + access_to_collection?(user: user, collection: collection, access: 'view', ability: ability) end - private_class_method :managers_of_collection_type + private_class_method :view_access_to_collection? # @api private # - # The value of the admin group name + # Determine if the given user has specified access for the given collection # - # @return [String] a string representation of the admin group name - def self.admin_group_name - ::Ability.admin_group_name + # @param user [User] the user who wants to view + # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param access [Symbol] the access level to check + # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @return [Boolean] true if the user has permission to view the collection + def self.access_to_collection?(user:, collection:, access:, ability: nil) + return false unless user && collection + template = Hyrax::PermissionTemplate.find_by!(source_id: collection.id) + return true if (user_id(user) & template.agent_ids_for(agent_type: 'user', access: access)).present? + return true if (user_groups(user, ability) & template.agent_ids_for(agent_type: 'group', access: access)).present? + false + end + private_class_method :access_to_collection? + + def self.user_groups(user, ability) + # if called from abilities class, use ability instead of user; otherwise, you end up in an infinite loop + return ability.user_groups if ability.present? + user.ability.user_groups + end + private_class_method :user_groups + + def self.user_admin?(user, ability) + # if called from abilities class, use ability instead of user; otherwise, you end up in an infinite loop + return ability.admin? if ability.present? + user.ability.admin? + end + private_class_method :user_groups + + def self.user_id(user) + [user.user_key] end - private_class_method :admin_group_name + private_class_method :user_id end end end diff --git a/spec/services/hyrax/collections/permissions_create_service_spec.rb b/spec/services/hyrax/collections/permissions_create_service_spec.rb new file mode 100644 index 0000000000..9aef03e6e9 --- /dev/null +++ b/spec/services/hyrax/collections/permissions_create_service_spec.rb @@ -0,0 +1,41 @@ +RSpec.describe Hyrax::Collections::PermissionsCreateService do + let(:user) { create(:user) } + let(:user2) { create(:user) } + + describe ".create_default" do + subject { described_class.create_default(collection: collection, creating_user: user) } + + let(:collection_type) { create(:collection_type) } + let(:user_manage_attributes) do + { + hyrax_collection_type_id: collection_type.id, + access: 'manage', + agent_id: user2.user_key, + agent_type: 'user' + } + end + let(:group_manage_attributes) do + { + hyrax_collection_type_id: collection_type.id, + access: 'manage', + agent_id: 'manage_group', + agent_type: 'group' + } + end + let!(:collection_type_participant) { create(:collection_type_participant, user_manage_attributes) } + let!(:collection_type_participant2) { create(:collection_type_participant, group_manage_attributes) } + let(:collection) { create(:collection, collection_type_gid: collection_type.gid) } + + before do + subject + end + + it "creates the default permission template for the collection" do + expect(Hyrax::PermissionTemplate.find_by_source_id(collection.id)).to be_persisted + end + + it "creates the default permission template access entries for the collection" do + expect(Hyrax::PermissionTemplate.find_by_source_id(collection.id).access_grants.count).to eq 4 + end + end +end diff --git a/spec/services/hyrax/collections/permissions_service_spec.rb b/spec/services/hyrax/collections/permissions_service_spec.rb index 9b455783fe..1716627a27 100644 --- a/spec/services/hyrax/collections/permissions_service_spec.rb +++ b/spec/services/hyrax/collections/permissions_service_spec.rb @@ -2,70 +2,165 @@ let(:user) { create(:user) } let(:user2) { create(:user) } - describe ".create_default" do - subject { described_class.create_default(collection: collection, creating_user: user) } - - let(:collection_type) { create(:collection_type) } - let(:user_manage_attributes) do - { - hyrax_collection_type_id: collection_type.id, - access: 'manage', - agent_id: user2.user_key, - agent_type: 'user' - } - end - let(:group_manage_attributes) do - { - hyrax_collection_type_id: collection_type.id, - access: 'manage', - agent_id: 'manage_group', - agent_type: 'group' - } - end - let!(:collection_type_participant) { create(:collection_type_participant, user_manage_attributes) } - let!(:collection_type_participant2) { create(:collection_type_participant, group_manage_attributes) } - let(:collection) { create(:collection, collection_type_gid: collection_type.gid) } + describe ".can_deposit_in_collection?" do + subject { described_class.can_deposit_in_collection?(collection: collection, user: user) } + + let(:ability) { double } + + let(:permission_template) { create(:permission_template) } + let(:collection) { create(:collection, user: user) } before do - subject + allow(Hyrax::PermissionTemplate).to receive(:find_by!).with(source_id: collection.id).and_return(permission_template) + allow(ability).to receive(:current_user).and_return(user) + allow(user).to receive(:ability).and_return(ability) + allow(ability).to receive(:user_groups).and_return(['public', 'registered']) + end + + it "exists" do + expect(described_class).to respond_to(:can_deposit_in_collection?) end - it "creates the default permission template for the collection" do - expect(Hyrax::PermissionTemplate.find_by_source_id(collection.id)).to be_persisted + it "returns true when user is a manager" do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + expect(subject).to be true + end + + it "returns true when user is a depositor" do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + expect(subject).to be true + end + + it "returns false when user is a viewer" do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([user.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) + expect(subject).to be false end - it "creates the default permission template access entries for the collection" do - expect(Hyrax::PermissionTemplate.find_by_source_id(collection.id).access_grants.count).to eq 4 + context "when manage group access defined" do + before do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + end + + it "returns true if user has any valid group" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'managers']) + expect(subject).to be true + end + + it "returns true if user has multiple valid groups" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_managers', 'managers', 'other_group']) + expect(subject).to be true + end + end + + context "when deposit group access defined" do + before do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) + end + + it "returns true if user has any valid group" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'depositors']) + expect(subject).to be true + end + + it "returns true if user has multiple valid groups" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_depositors', 'depositors', 'other_group']) + expect(subject).to be true + end + end + + context "when view group access defined" do + before do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return(['viewers', 'more_viewers']) + end + + it "returns false if user has any view group" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'viewers']) + expect(subject).to be false + end + + it "returns false if user has multiple view groups" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_viewers', 'viewers', 'other_group']) + expect(subject).to be false + end + end + + it "returns false when user is neither a manager nor depositor" do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user2.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user2.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) + allow(ability).to receive(:user_groups).and_return(['public', 'registered']) + expect(subject).to be false end end - describe ".can_deposit_in_collection" do - subject { described_class.can_deposit_in_collection(collection: collection, user: user) } + describe ".can_view_admin_show_for_collection?" do + subject { described_class.can_view_admin_show_for_collection?(collection: collection, user: user) } + let(:ability) { double } let(:permission_template) { create(:permission_template) } let(:collection) { create(:collection, user: user) } before do allow(Hyrax::PermissionTemplate).to receive(:find_by!).with(source_id: collection.id).and_return(permission_template) + allow(ability).to receive(:current_user).and_return(user) + allow(user).to receive(:ability).and_return(ability) + allow(ability).to receive(:user_groups).and_return(['public', 'registered']) end it "exists" do - expect(described_class).to respond_to(:can_deposit_in_collection) + expect(described_class).to respond_to(:can_view_admin_show_for_collection?) end it "returns true when user is a manager" do allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user.user_key]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) expect(subject).to be true end it "returns true when user is a depositor" do allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) + expect(subject).to be true + end + + it "returns true when user is a viewer" do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([user.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) expect(subject).to be true end @@ -73,22 +168,24 @@ before do allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) end it "returns false if no user groups" do - allow(user).to receive(:user_groups).and_return([]) + allow(ability).to receive(:user_groups).and_return([]) expect(subject).to be false end it "returns true if user has any valid group" do - allow(user).to receive(:user_groups).and_return(['managers']) + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'managers']) expect(subject).to be true end it "returns true if user has multiple valid groups" do - allow(user).to receive(:user_groups).and_return(['more managers', 'managers', 'other_group']) + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_managers', 'managers', 'other_group']) expect(subject).to be true end end @@ -97,81 +194,130 @@ before do allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) end - it "returns false if no user groups" do - allow(user).to receive(:user_groups).and_return([]) - expect(subject).to be false + it "returns true if user has any valid group" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'depositors']) + expect(subject).to be true + end + + it "returns true if user has multiple valid groups" do + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_depositors', 'depositors', 'other_group']) + expect(subject).to be true + end + end + + context "when view group access defined" do + before do + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return(['viewers', 'more_viewers']) end it "returns true if user has any valid group" do - allow(user).to receive(:user_groups).and_return(['depositors']) + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'viewers']) expect(subject).to be true end it "returns true if user has multiple valid groups" do - allow(user).to receive(:user_groups).and_return(['more depositors', 'depositors', 'other_group']) + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_viewers', 'viewers', 'other_group']) expect(subject).to be true end end - it "returns false when user is neither a manager nor depositor" do + it "returns false when user is does not have access as manager, depositor, or viewer" do allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user2.user_key]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user2.user_key]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([user2.user_key]) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) - allow(user).to receive(:user_groups).and_return([]) + allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return(['viewers', 'more_viewers']) + allow(ability).to receive(:user_groups).and_return([]) expect(subject).to be false end end context "access helper method" do + let(:ability) { double } let(:user) { create(:user) } - let(:col_vu) { create(:collection, with_permission_template: true) } - let(:col_vg) { create(:collection, with_permission_template: true) } - let(:col_mu) { create(:collection, with_permission_template: true) } - let(:col_mg) { create(:collection, with_permission_template: true) } - let(:col_du) { create(:collection, with_permission_template: true) } - let(:col_dg) { create(:collection, with_permission_template: true) } + let(:col_vu) { create(:collection, id: 'col_vu', with_permission_template: true) } + let(:col_vg) { create(:collection, id: 'col_vg', with_permission_template: true) } + let(:col_mu) { create(:collection, id: 'col_mu', with_permission_template: true) } + let(:col_mg) { create(:collection, id: 'col_mg', with_permission_template: true) } + let(:col_du) { create(:collection, id: 'col_du', with_permission_template: true) } + let(:col_dg) { create(:collection, id: 'col_dg', with_permission_template: true) } + let(:as_vu) { create(:admin_set, id: 'as_vu', with_permission_template: true) } + let(:as_vg) { create(:admin_set, id: 'as_vg', with_permission_template: true) } + let(:as_mu) { create(:admin_set, id: 'as_mu', with_permission_template: true) } + let(:as_mg) { create(:admin_set, id: 'as_mg', with_permission_template: true) } + let(:as_du) { create(:admin_set, id: 'as_du', with_permission_template: true) } + let(:as_dg) { create(:admin_set, id: 'as_dg', with_permission_template: true) } before do - collection_access(col_vu.permission_template, 'user', user.user_key, :view) - collection_access(col_vg.permission_template, 'group', 'view_group', :view) - collection_access(col_mu.permission_template, 'user', user.user_key, :manage) - collection_access(col_mg.permission_template, 'group', 'manage_group', :manage) - collection_access(col_du.permission_template, 'user', user.user_key, :deposit) - collection_access(col_dg.permission_template, 'group', 'deposit_group', :deposit) - allow(user).to receive(:groups).and_return(['view_group', 'deposit_group', 'manage_group']) - end + source_access(col_vu.permission_template, 'user', user.user_key, :view) + source_access(col_vg.permission_template, 'group', 'view_group', :view) + source_access(col_mu.permission_template, 'user', user.user_key, :manage) + source_access(col_mg.permission_template, 'group', 'manage_group', :manage) + source_access(col_du.permission_template, 'user', user.user_key, :deposit) + source_access(col_dg.permission_template, 'group', 'deposit_group', :deposit) + source_access(as_vu.permission_template, 'user', user.user_key, :view) + source_access(as_vg.permission_template, 'group', 'view_group', :view) + source_access(as_mu.permission_template, 'user', user.user_key, :manage) + source_access(as_mg.permission_template, 'group', 'manage_group', :manage) + source_access(as_du.permission_template, 'user', user.user_key, :deposit) + source_access(as_dg.permission_template, 'group', 'deposit_group', :deposit) - describe '.collection_ids_with_view_access' do - it 'returns ids for view user and group' do - expect(described_class.collection_ids_with_view_access(user: user)).to match_array [col_vu.id, col_vg.id] - end + allow(ability).to receive(:current_user).and_return(user) + allow(user).to receive(:ability).and_return(ability) + allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'view_group', 'manage_group', 'deposit_group']) + allow(ability).to receive(:admin?).and_return(false) end - describe '.collection_ids_with_manage_access' do - it 'returns ids for manage user and group' do - expect(described_class.collection_ids_with_manage_access(user: user)).to match_array [col_mu.id, col_mg.id] + describe '.admin_set_ids_for_user' do + it 'returns ids for admin sets with view user and group' do + expect(described_class.admin_set_ids_for_user(user: user, access: 'view')).to match_array [as_vu.id, as_vg.id] + end + it 'returns ids for admin sets with manage user and group' do + expect(described_class.admin_set_ids_for_user(user: user, access: 'manage')).to match_array [as_mu.id, as_mg.id] + end + it 'returns ids for admin sets with deposit user and group' do + expect(described_class.admin_set_ids_for_user(user: user, access: 'deposit')).to match_array [as_du.id, as_dg.id] end end - describe '.collection_ids_with_deposit_access' do - it 'returns ids for deposit user and group' do - expect(described_class.collection_ids_with_deposit_access(user: user)).to match_array [col_du.id, col_dg.id] + describe '.collection_ids_for_user' do + it 'returns ids for collections with view user and group' do + expect(described_class.collection_ids_for_user(user: user, access: 'view')).to match_array [col_vu.id, col_vg.id] + end + it 'returns ids for collections with manage user and group' do + expect(described_class.collection_ids_for_user(user: user, access: 'manage')).to match_array [col_mu.id, col_mg.id] + end + it 'returns ids for collections with deposit user and group' do + expect(described_class.collection_ids_for_user(user: user, access: 'deposit')).to match_array [col_du.id, col_dg.id] end end - describe '.collection_ids_for_deposit' do - it 'returns ids for deposit user and group and manage user and group' do - expect(described_class.collection_ids_for_deposit(user: user)).to match_array [col_du.id, col_dg.id, col_mu.id, col_mg.id] + describe '.source_ids_for_user' do + it 'returns ids for collections with view user and group' do + expect(described_class.source_ids_for_user(user: user, access: 'view')).to match_array [col_vu.id, col_vg.id, as_vu.id, as_vg.id] + end + it 'returns ids for collections with manage user and group' do + expect(described_class.source_ids_for_user(user: user, access: 'manage')).to match_array [col_mu.id, col_mg.id, as_mu.id, as_mg.id] + end + it 'returns ids for collections with deposit user and group' do + expect(described_class.source_ids_for_user(user: user, access: 'deposit')).to match_array [col_du.id, col_dg.id, as_du.id, as_dg.id] end end end - def collection_access(permission_template, agent_type, agent_id, access) + def source_access(permission_template, agent_type, agent_id, access) create(:permission_template_access, access, permission_template: permission_template, From 6129ffe68d7b150470729ff2c937f2d27ea8dda2 Mon Sep 17 00:00:00 2001 From: "E. Lynette Rayle" Date: Thu, 5 Oct 2017 23:15:24 -0400 Subject: [PATCH 2/2] Solidify abilities using permission services --- .../admin/collection_types_controller.rb | 2 +- app/models/concerns/hyrax/ability.rb | 57 +-- .../hyrax/ability/admin_set_ability.rb | 31 ++ .../hyrax/ability/collection_ability.rb | 27 ++ .../hyrax/ability/collection_type_ability.rb | 12 + .../ability/permission_template_ability.rb | 16 + .../hyrax/admin_set_search_builder.rb | 9 +- .../dashboard/collections_search_builder.rb | 13 +- .../hyrax/collection_types/create_service.rb | 57 ++- .../collection_types/permissions_service.rb | 225 +++++++-- .../hyrax/collections/permissions_service.rb | 285 ++++++++--- spec/abilities/ability_spec.rb | 3 + spec/abilities/admin_set_abilities_spec.rb | 15 - spec/abilities/admin_set_ability_spec.rb | 138 ++++++ spec/abilities/collection_abilities_spec.rb | 51 -- spec/abilities/collection_ability_spec.rb | 159 ++++++ .../abilities/collection_type_ability_spec.rb | 72 +++ .../permission_template_ability_spec.rb | 145 ++++++ .../hyrax/admin_set_search_builder_spec.rb | 8 +- .../collections_search_builder_spec.rb | 8 +- .../collection_types/create_service_spec.rb | 19 + .../permissions_service_spec.rb | 114 ++++- .../collections/permissions_service_spec.rb | 454 +++++++++--------- 23 files changed, 1424 insertions(+), 496 deletions(-) create mode 100644 app/models/concerns/hyrax/ability/admin_set_ability.rb create mode 100644 app/models/concerns/hyrax/ability/collection_ability.rb create mode 100644 app/models/concerns/hyrax/ability/collection_type_ability.rb create mode 100644 app/models/concerns/hyrax/ability/permission_template_ability.rb delete mode 100644 spec/abilities/admin_set_abilities_spec.rb create mode 100644 spec/abilities/admin_set_ability_spec.rb delete mode 100644 spec/abilities/collection_abilities_spec.rb create mode 100644 spec/abilities/collection_ability_spec.rb create mode 100644 spec/abilities/collection_type_ability_spec.rb create mode 100644 spec/abilities/permission_template_ability_spec.rb diff --git a/app/controllers/hyrax/admin/collection_types_controller.rb b/app/controllers/hyrax/admin/collection_types_controller.rb index 33099af0b4..38eb8e7906 100644 --- a/app/controllers/hyrax/admin/collection_types_controller.rb +++ b/app/controllers/hyrax/admin/collection_types_controller.rb @@ -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 diff --git a/app/models/concerns/hyrax/ability.rb b/app/models/concerns/hyrax/ability.rb index de806185bc..1f7db891d4 100644 --- a/app/models/concerns/hyrax/ability.rb +++ b/app/models/concerns/hyrax/ability.rb @@ -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' @@ -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 @@ -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 @@ -55,35 +63,6 @@ def admin? user_groups.include? admin_group_name end - # @return [Array] 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] 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] roles the roles to be used when searching for admin - # sets for the user - # @return [Array] 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) @@ -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 @@ -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 diff --git a/app/models/concerns/hyrax/ability/admin_set_ability.rb b/app/models/concerns/hyrax/ability/admin_set_ability.rb new file mode 100644 index 0000000000..f1764a4ec6 --- /dev/null +++ b/app/models/concerns/hyrax/ability/admin_set_ability.rb @@ -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 diff --git a/app/models/concerns/hyrax/ability/collection_ability.rb b/app/models/concerns/hyrax/ability/collection_ability.rb new file mode 100644 index 0000000000..4d4fd6ab68 --- /dev/null +++ b/app/models/concerns/hyrax/ability/collection_ability.rb @@ -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 diff --git a/app/models/concerns/hyrax/ability/collection_type_ability.rb b/app/models/concerns/hyrax/ability/collection_type_ability.rb new file mode 100644 index 0000000000..77af0aed21 --- /dev/null +++ b/app/models/concerns/hyrax/ability/collection_type_ability.rb @@ -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 diff --git a/app/models/concerns/hyrax/ability/permission_template_ability.rb b/app/models/concerns/hyrax/ability/permission_template_ability.rb new file mode 100644 index 0000000000..c644eb5006 --- /dev/null +++ b/app/models/concerns/hyrax/ability/permission_template_ability.rb @@ -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 diff --git a/app/search_builders/hyrax/admin_set_search_builder.rb b/app/search_builders/hyrax/admin_set_search_builder.rb index 5a9c159693..1e4b0e715d 100644 --- a/app/search_builders/hyrax/admin_set_search_builder.rb +++ b/app/search_builders/hyrax/admin_set_search_builder.rb @@ -30,10 +30,13 @@ def discovery_permissions # @return [Array] 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 diff --git a/app/search_builders/hyrax/dashboard/collections_search_builder.rb b/app/search_builders/hyrax/dashboard/collections_search_builder.rb index 19bb4ad3a5..123dff46e0 100644 --- a/app/search_builders/hyrax/dashboard/collections_search_builder.rb +++ b/app/search_builders/hyrax/dashboard/collections_search_builder.rb @@ -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 @@ -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 diff --git a/app/services/hyrax/collection_types/create_service.rb b/app/services/hyrax/collection_types/create_service.rb index be06130613..15bbf213bc 100644 --- a/app/services/hyrax/collection_types/create_service.rb +++ b/app/services/hyrax/collection_types/create_service.rb @@ -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| @@ -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] 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 diff --git a/app/services/hyrax/collection_types/permissions_service.rb b/app/services/hyrax/collection_types/permissions_service.rb index 9a603f5d18..e24d4cbef4 100644 --- a/app/services/hyrax/collection_types/permissions_service.rb +++ b/app/services/hyrax/collection_types/permissions_service.rb @@ -3,40 +3,189 @@ module CollectionTypes class PermissionsService # @api public # - # What types of collection can the user create or manage + # Ids of collection types that a user can create or manage # - # @param user [User] user - The user requesting to create/manage a Collection # @param roles [String] type of access, Hyrax::CollectionTypeParticipant::MANAGE_ACCESS and/or Hyrax::CollectionTypeParticipant::CREATE_ACCESS - # @return [Array] - def self.collection_types_for_user(user:, roles:) - return Hyrax::CollectionType.all if user.ability.admin? - ids = Hyrax::CollectionTypeParticipant.where(agent_type: Hyrax::CollectionTypeParticipant::USER_TYPE, - agent_id: user.user_key, - access: roles) - .or( - Hyrax::CollectionTypeParticipant.where(agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, - agent_id: user.ability.user_groups, - access: roles) - ).pluck('DISTINCT hyrax_collection_type_id') - Hyrax::CollectionType.where(id: ids) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Array] ids for collection types for which a user has the specified role + # @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.collection_type_ids_for_user(roles:, user: nil, ability: nil) + return false unless user.present? || ability.present? + return Hyrax::CollectionType.all.pluck('DISTINCT id') if user_admin?(user, ability) + Hyrax::CollectionTypeParticipant.where(agent_type: Hyrax::CollectionTypeParticipant::USER_TYPE, + agent_id: user_id(user, ability), + access: roles) + .or( + Hyrax::CollectionTypeParticipant.where(agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, + agent_id: user_groups(user, ability), + access: roles) + ).pluck('DISTINCT hyrax_collection_type_id') + end + + # @api public + # + # Instances of collection types that a user can create or manage + # + # @param roles [String] type of access, Hyrax::CollectionTypeParticipant::MANAGE_ACCESS and/or Hyrax::CollectionTypeParticipant::CREATE_ACCESS + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Array] instances of collection types for which a user has the specified role + # @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.collection_types_for_user(roles:, user: nil, ability: nil) + return false unless user.present? || ability.present? + return Hyrax::CollectionType.all if user_admin?(user, ability) + Hyrax::CollectionType.where(id: collection_type_ids_for_user(user: user, roles: roles, ability: ability)) + end + + # @api public + # + # Is the user a creator for any collection types? + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to create collections of at least one 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.can_create_any_collection_type?(user: nil, ability: nil) + return false unless user.present? || ability.present? + return true if user_admin?(user, ability) + # both manage and create access can create collections of a type, so no need to include access in the query + return true if Hyrax::CollectionTypeParticipant.where(agent_type: Hyrax::CollectionTypeParticipant::USER_TYPE, + agent_id: user_id(user, ability)).any? + return true if Hyrax::CollectionTypeParticipant.where(agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, + agent_id: user_groups(user, ability)).any? + false + end + + # @api public + # + # Is the user a creator for admin sets collection types? + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to create collections of type admin_set + # @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.can_create_admin_set_collection_type?(user: nil, ability: nil) + return false unless user.present? || ability.present? + return true if user_admin?(user, ability) + # both manage and create access can create collections of a type, so no need to include access in the query + return true if Hyrax::CollectionTypeParticipant.joins(:hyrax_collection_type) + .where(agent_type: Hyrax::CollectionTypeParticipant::USER_TYPE, + agent_id: user_id(user, ability), + hyrax_collection_types: { machine_id: Hyrax::CollectionType::ADMIN_SET_MACHINE_ID }).present? + return true if Hyrax::CollectionTypeParticipant.joins(:hyrax_collection_type) + .where(agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, + agent_id: user_groups(user, ability), + hyrax_collection_types: { machine_id: Hyrax::CollectionType::ADMIN_SET_MACHINE_ID }).present? + false end # @api public # # Get a list of collection types that a user can create # - # @param user [User] the user that will be creating a collection (default: current_user) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Array] array of collection types the user can create - def self.can_create_collection_types(user: current_user) - collection_types_for_user(user: user, roles: [Hyrax::CollectionTypeParticipant::MANAGE_ACCESS, Hyrax::CollectionTypeParticipant::CREATE_ACCESS]) + # @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.can_create_collection_types(user: nil, ability: nil) + collection_types_for_user(user: user, ability: ability, roles: [Hyrax::CollectionTypeParticipant::MANAGE_ACCESS, Hyrax::CollectionTypeParticipant::CREATE_ACCESS]) end + # @api public + # + # Get a list of collection types that a user can create + # + # @param collection_type [Hyrax::CollectionType] the type of the collection being created + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to create collections of specified 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.can_create_collection_of_type?(collection_type:, user: nil, ability: nil) + manage_access_for_collection_type?(user: user, ability: ability, collection_type: collection_type) || + create_access_for_collection_type?(user: user, ability: ability, collection_type: collection_type) + end + + # @api private + # + # Determine if the given user has :manage access for the given collection type + # + # @param collection_type [Hyrax::CollectionType] the collection type we are checking permissions on + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to manage collections of the specified 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.manage_access_for_collection_type?(collection_type:, user: nil, ability: nil) + access_to_collection_type?(user: user, ability: ability, collection_type: collection_type, access: 'manage') + end + private_class_method :manage_access_for_collection_type? + + # @api private + # + # Determine if the given user has :create access for the given collection type + # + # @param collection_type [Hyrax::CollectionType] the collection type we are checking permissions on + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to create collections of the specified 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.create_access_for_collection_type?(collection_type:, user: nil, ability: nil) + access_to_collection_type?(user: user, ability: ability, collection_type: collection_type, access: 'create') + end + private_class_method :create_access_for_collection_type? + + # @api private + # + # Determine if the given user has specified access for the given collection type + # + # @param collection_type [Hyrax::CollectionType] the collection type we are checking permissions on + # @param access [Symbol] the access level to check + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to create collections of the specified 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.access_to_collection_type?(collection_type:, access:, user: nil, ability: nil) # rubocop:disable Metrics/CyclomaticComplexity + return false unless user.present? || ability.present? + return false unless user && collection_type + return true if ([user_id(user, ability)] & agent_ids_for(collection_type: collection_type, agent_type: 'user', access: access)).present? + return true if (user_groups(user, ability) & agent_ids_for(collection_type: collection_type, agent_type: 'group', access: access)).present? + false + end + private_class_method :access_to_collection_type? + + # @api public + # + # What types of collection can the user create or manage + # + # @param user [User] user - The user requesting to create/manage a Collection + # @param roles [String] type of access, Hyrax::CollectionTypeParticipant::MANAGE_ACCESS and/or Hyrax::CollectionTypeParticipant::CREATE_ACCESS + # @return [Array] + # @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.agent_ids_for(collection_type:, agent_type:, access:) + Hyrax::CollectionTypeParticipant.where(hyrax_collection_type_id: collection_type.id, + agent_type: agent_type, + access: access).pluck('DISTINCT agent_id') + end + private_class_method :agent_ids_for + # @api public # # Get a list of users who should be added as user editors for a new collection of the specified collection type # # @param collection_type [Hyrax::CollectionType] the type of the collection being created # @return [Array] array of user identifiers (typically emails) for users who can edit collections of this 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.user_edit_grants_for_collection_of_type(collection_type: nil) return [] unless collection_type Hyrax::CollectionTypeParticipant.joins(:hyrax_collection_type).where(hyrax_collection_type_id: collection_type.id, @@ -50,6 +199,8 @@ def self.user_edit_grants_for_collection_of_type(collection_type: nil) # # @param collection_type [Hyrax::CollectionType] the type of the collection being created # @return [Array] array of group identifiers (typically groupname) for groups who can edit collections of this 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.group_edit_grants_for_collection_of_type(collection_type: nil) return [] unless collection_type groups = Hyrax::CollectionTypeParticipant.joins(:hyrax_collection_type).where(hyrax_collection_type_id: collection_type.id, @@ -58,33 +209,25 @@ def self.group_edit_grants_for_collection_of_type(collection_type: nil) groups | ['admin'] end - # @param collection_type_id [Integer] - 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) + def self.user_groups(user, ability) + # if called from abilities class, use ability instead of user; otherwise, you end up in an infinite loop + return ability.user_groups if ability.present? + user.ability.user_groups + end + private_class_method :user_groups + + def self.user_admin?(user, ability) + # if called from abilities class, use ability instead of user; otherwise, you end up in an infinite loop + return ability.admin? if ability.present? + user.ability.admin? end + private_class_method :user_groups - # @param collection_type_id [Integer] - # @param participants [Array] - 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 + def self.user_id(user, ability) + return ability.current_user.user_key if ability.present? + user.user_key end + private_class_method :user_id end end end diff --git a/app/services/hyrax/collections/permissions_service.rb b/app/services/hyrax/collections/permissions_service.rb index ae9a5dba02..f3fb725629 100644 --- a/app/services/hyrax/collections/permissions_service.rb +++ b/app/services/hyrax/collections/permissions_service.rb @@ -1,81 +1,156 @@ module Hyrax module Collections - class PermissionsService + class PermissionsService # rubocop:disable Metrics/ClassLength # @api public # - # IDs of admin sets a user can access based on participant roles. + # IDs of collections/or admin_sets a user can access based on participant roles. # - # @param user [User] user # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) - # @param ability [Ability] the ability coming from cancan ability check (default: nil) - # @return [Array] IDs of admin sets for which the user has specified roles - def self.admin_set_ids_for_user(user:, access:, ability: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @param source_type [String] 'collection', 'admin_set', or nil to get all types + # @return [Array] IDs of collections and admin sets for which the user has specified roles + # @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.source_ids_for_user(access:, user: nil, ability: nil, source_type: nil) + return false unless user.present? || ability.present? # One of these two are required. Will prefer ability over user if both are specified. if user_admin?(user, ability) - PermissionTemplate.all.where(source_type: 'admin_set').pluck('DISTINCT source_id') + PermissionTemplate.all.pluck('DISTINCT source_id') else PermissionTemplateAccess.joins(:permission_template) - .where(user_where(user: user, access: access, source_type: 'admin_set')) + .where(user_where(access: access, user: user, ability: ability, source_type: source_type)) .or( PermissionTemplateAccess.joins(:permission_template) - .where(group_where(user: user, access: access, source_type: 'admin_set', ability: ability)) + .where(group_where(access: access, user: user, ability: ability, source_type: source_type)) ).pluck('DISTINCT source_id') end end + # @api public + # + # IDs of admin sets a user can access based on participant roles. + # + # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Array] IDs of admin sets for which the user has specified roles + # @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.admin_set_ids_for_user(access:, user: nil, ability: nil) + source_ids_for_user(user: user, access: access, ability: ability, source_type: 'admin_set') + end + # @api public # # IDs of collections a user can access based on participant roles. # - # @param user [User] user # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) - # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Array] IDs of collections for which the user has specified roles - def self.collection_ids_for_user(user:, access:, ability: nil) - if user_admin?(user, ability) - PermissionTemplate.all.where(source_type: 'collection').pluck('DISTINCT source_id') - else - PermissionTemplateAccess.joins(:permission_template) - .where(user_where(user: user, access: access, source_type: 'collection')) - .or( - PermissionTemplateAccess.joins(:permission_template) - .where(group_where(user: user, access: access, source_type: 'collection', ability: ability)) - ).pluck('DISTINCT source_id') - end + # @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.collection_ids_for_user(access:, user: nil, ability: nil) + source_ids_for_user(user: user, access: access, ability: ability, source_type: 'collection') end # @api public # - # IDs of collections and admin_sets a user can access based on participant roles. + # IDs of collections and/or admin_sets into which a user can deposit. # - # @param user [User] user - # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) - # @param ability [Ability] the ability coming from cancan ability check (default: nil) - # @return [Array] IDs of collections and admin sets for which the user has specified roles - def self.source_ids_for_user(user:, access:, ability: nil) - if user_admin?(user, ability) - PermissionTemplate.all.pluck('DISTINCT source_id') - else - PermissionTemplateAccess.joins(:permission_template) - .where(user_where(user: user, access: access)) - .or( - PermissionTemplateAccess.joins(:permission_template) - .where(group_where(user: user, access: access, ability: ability)) - ).pluck('DISTINCT source_id') - end + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @param source_type [String] 'collection', 'admin_set', or nil to get all types + # @return [Array] IDs of collections and/or admin_sets into which the user can deposit + # @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.source_ids_for_deposit(user: nil, ability: nil, source_type: nil) + access = [Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT] + source_ids_for_user(user: user, access: access, ability: ability, source_type: source_type) + end + + # @api public + # + # IDs of collections and/or admin_sets that a user can manage. + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @param source_type [String] 'collection', 'admin_set', or nil to get all types + # @return [Array] IDs of collections and/or admin_sets that the user can manage + # @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.source_ids_for_manage(user: nil, ability: nil, source_type: nil) + access = [Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::MANAGE] + source_ids_for_user(user: user, access: access, ability: ability, source_type: source_type) + end + + # @api public + # + # IDs of admin_sets into which a user can deposit. + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Array] IDs of admin_sets into which the user can deposit + # @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.admin_set_ids_for_deposit(user: nil, ability: nil) + source_ids_for_deposit(user: user, ability: ability, source_type: 'admin_set') + end + + # @api public + # + # IDs of collections into which a user can deposit. + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Array] IDs of collections into which the user can deposit + # @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.collection_ids_for_deposit(user: nil, ability: nil) + source_ids_for_deposit(user: user, ability: ability, source_type: 'collection') + end + + # @api public + # + # IDs of admin sets that a user can manage. + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Array] IDs of admin sets that the user can manage + # @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.admin_set_ids_for_manage(user: nil, ability: nil) + source_ids_for_manage(user: user, ability: ability, source_type: 'admin_set') + end + + # @api public + # + # IDs of collections that a user can manage. + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Array] IDs of collections that the user can manage + # @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.collection_ids_for_manage(user: nil, ability: nil) + source_ids_for_manage(user: user, ability: ability, source_type: 'collection') end # @api private # # Generate the user where clause hash for joining the permissions tables # - # @param user [User] the user wanting access - # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @param source_type [String] 'collection', 'admin_set', or nil to get all types # @return [Hash] the where clause hash to pass to joins for users - def self.user_where(user:, access:, source_type: nil) + # @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.user_where(access:, user: nil, ability: nil, source_type: nil) where_clause = {} where_clause[:agent_type] = 'user' - where_clause[:agent_id] = user.user_key + where_clause[:agent_id] = user_id(user, ability) where_clause[:access] = access where_clause[:permission_templates] = { source_type: source_type } if source_type.present? where_clause @@ -86,12 +161,14 @@ def self.user_where(user:, access:, source_type: nil) # # Generate the group where clause hash for joining the permissions tables # - # @param user [User] the user wanting access - # @param collection [Hyrax::Collection] the collection we are checking permissions on + # @param access [Array] one or more types of access (e.g. Hyrax::PermissionTemplateAccess::MANAGE, Hyrax::PermissionTemplateAccess::DEPOSIT, Hyrax::PermissionTemplateAccess::VIEW) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @param source_type [String] 'collection', 'admin_set', or nil to get all types - # @param ability [Ability] the ability coming from cancan ability check (default: nil) # @return [Hash] the where clause hash to pass to joins for groups - def self.group_where(user:, access:, source_type: nil, ability: nil) + # @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.group_where(access:, user: nil, ability: nil, source_type: nil) where_clause = {} where_clause[:agent_type] = 'group' where_clause[:agent_id] = user_groups(user, ability) @@ -99,17 +176,75 @@ def self.group_where(user:, access:, source_type: nil, ability: nil) where_clause[:permission_templates] = { source_type: source_type } if source_type.present? where_clause end - private_class_method :user_where + private_class_method :group_where + + # @api public + # + # Determine if the given user has permissions to view the admin show page for at least one collection + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to view the admin show page for at least one collection + # @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.can_view_admin_show_for_any_collection?(user: nil, ability: nil) + collection_ids_for_user(user: user, ability: ability, access: [Hyrax::PermissionTemplateAccess::MANAGE, + Hyrax::PermissionTemplateAccess::DEPOSIT, + Hyrax::PermissionTemplateAccess::VIEW]).present? + end + + # @api public + # + # Determine if the given user has permissions to view the admin show page for at least one admin set + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to view the admin show page for at least one admin_set + # @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.can_view_admin_show_for_any_admin_set?(user: nil, ability: nil) + admin_set_ids_for_user(user: user, ability: ability, access: [Hyrax::PermissionTemplateAccess::MANAGE, + Hyrax::PermissionTemplateAccess::DEPOSIT, + Hyrax::PermissionTemplateAccess::VIEW]).present? + end + + # @api public + # + # Determine if the given user has permissions to manage at least one collection + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to manage at least one collection + # @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.can_manage_any_collection?(user: nil, ability: nil) + collection_ids_for_user(user: user, ability: ability, access: [Hyrax::PermissionTemplateAccess::MANAGE]).present? + end + + # @api public + # + # Determine if the given user has permissions to manage at least one admin set + # + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) + # @return [Boolean] true if the user has permission to manage at least one admin_set + # @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.can_manage_any_admin_set?(user: nil, ability: nil) + admin_set_ids_for_user(user: user, ability: ability, access: [Hyrax::PermissionTemplateAccess::MANAGE]).present? + end # @api public # # Determine if the given user has permissions to deposit into the given collection # - # @param user [User] the user that wants to deposit # @param collection [Hyrax::Collection] the collection we are checking permissions on - # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Boolean] true if the user has permission to deposit into the collection - def self.can_deposit_in_collection?(user:, collection:, ability: nil) + # @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.can_deposit_in_collection?(collection:, user: nil, ability: nil) deposit_access_to_collection?(user: user, collection: collection, ability: ability) || manage_access_to_collection?(user: user, collection: collection, ability: ability) end @@ -118,11 +253,13 @@ def self.can_deposit_in_collection?(user:, collection:, ability: nil) # # Determine if the given user has permissions to view the admin show page for the collection # - # @param user [User] the user that wants to view # @param collection [Hyrax::Collection] the collection we are checking permissions on - # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Boolean] true if the user has permission to view the admin show page for the collection - def self.can_view_admin_show_for_collection?(user:, collection:, ability: nil) + # @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.can_view_admin_show_for_collection?(collection:, user: nil, ability: nil) deposit_access_to_collection?(user: user, collection: collection, ability: ability) || manage_access_to_collection?(user: user, collection: collection, ability: ability) || view_access_to_collection?(user: user, collection: collection, ability: ability) @@ -132,11 +269,13 @@ def self.can_view_admin_show_for_collection?(user:, collection:, ability: nil) # # Determine if the given user has :deposit access for the given collection # - # @param user [User] the user who wants to deposit # @param collection [Hyrax::Collection] the collection we are checking permissions on - # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Boolean] true if the user has :deposit access to the collection - def self.deposit_access_to_collection?(user:, collection:, ability: nil) + # @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.deposit_access_to_collection?(collection:, user: nil, ability: nil) access_to_collection?(user: user, collection: collection, access: 'deposit', ability: ability) end private_class_method :deposit_access_to_collection? @@ -145,11 +284,13 @@ def self.deposit_access_to_collection?(user:, collection:, ability: nil) # # Determine if the given user has :manage access for the given collection # - # @param user [User] the user who wants to manage # @param collection [Hyrax::Collection] the collection we are checking permissions on - # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Boolean] true if the user has :manage access to the collection - def self.manage_access_to_collection?(user:, collection:, ability: nil) + # @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.manage_access_to_collection?(collection:, user: nil, ability: nil) access_to_collection?(user: user, collection: collection, access: 'manage', ability: ability) end private_class_method :manage_access_to_collection? @@ -158,11 +299,13 @@ def self.manage_access_to_collection?(user:, collection:, ability: nil) # # Determine if the given user has :view access for the given collection # - # @param user [User] the user who wants to view # @param collection [Hyrax::Collection] the collection we are checking permissions on - # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Boolean] true if the user has permission to view the collection - def self.view_access_to_collection?(user:, collection:, ability: nil) + # @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.view_access_to_collection?(collection:, user: nil, ability: nil) access_to_collection?(user: user, collection: collection, access: 'view', ability: ability) end private_class_method :view_access_to_collection? @@ -171,15 +314,18 @@ def self.view_access_to_collection?(user:, collection:, ability: nil) # # Determine if the given user has specified access for the given collection # - # @param user [User] the user who wants to view # @param collection [Hyrax::Collection] the collection we are checking permissions on # @param access [Symbol] the access level to check - # @param ability [Ability] the ability coming from cancan ability check (default: nil) + # @param user [User] user (required if ability is nil) + # @param ability [Ability] the ability coming from cancan ability check (default: nil) (required if user is nil) # @return [Boolean] true if the user has permission to view the collection - def self.access_to_collection?(user:, collection:, access:, ability: nil) - return false unless user && collection + # @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.access_to_collection?(collection:, access:, user: nil, ability: nil) + return false unless user.present? || ability.present? + return false unless collection template = Hyrax::PermissionTemplate.find_by!(source_id: collection.id) - return true if (user_id(user) & template.agent_ids_for(agent_type: 'user', access: access)).present? + return true if ([user_id(user, ability)] & template.agent_ids_for(agent_type: 'user', access: access)).present? return true if (user_groups(user, ability) & template.agent_ids_for(agent_type: 'group', access: access)).present? false end @@ -199,8 +345,9 @@ def self.user_admin?(user, ability) end private_class_method :user_groups - def self.user_id(user) - [user.user_key] + def self.user_id(user, ability) + return ability.current_user.user_key if ability.present? + user.user_key end private_class_method :user_id end diff --git a/spec/abilities/ability_spec.rb b/spec/abilities/ability_spec.rb index 5b429630ba..7e1bbd8c16 100644 --- a/spec/abilities/ability_spec.rb +++ b/spec/abilities/ability_spec.rb @@ -33,10 +33,13 @@ end context "when user can deposit into an admin set" do + let(:permission_template) { create(:permission_template, source_type: 'admin_set') } + before do # Grant the user access to deposit into an admin set. create(:permission_template_access, :deposit, + permission_template: permission_template, agent_type: 'user', agent_id: user.user_key) end diff --git a/spec/abilities/admin_set_abilities_spec.rb b/spec/abilities/admin_set_abilities_spec.rb deleted file mode 100644 index 932b057451..0000000000 --- a/spec/abilities/admin_set_abilities_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'cancan/matchers' - -RSpec.describe 'User Abilities' do - subject { ability } - - let(:ability) { Ability.new(current_user) } - let(:user) { create(:user) } - let(:current_user) { user } - let(:admin_set) { create(:admin_set, edit_users: [user]) } - - it "allows the edit_users to edit and read" do - is_expected.to be_able_to(:read, admin_set) - is_expected.to be_able_to(:edit, admin_set) - end -end diff --git a/spec/abilities/admin_set_ability_spec.rb b/spec/abilities/admin_set_ability_spec.rb new file mode 100644 index 0000000000..637edb7ba6 --- /dev/null +++ b/spec/abilities/admin_set_ability_spec.rb @@ -0,0 +1,138 @@ +require 'cancan/matchers' + +RSpec.describe 'AdminSetAbility' do + subject { ability } + + let(:ability) { Ability.new(current_user) } + let(:user) { create(:user) } + let(:current_user) { user } + let(:admin_set) { create(:admin_set, edit_users: [user], with_permission_template: true) } + + context 'when user who created the admin set' do + it 'allows the edit_users to edit and read' do + is_expected.to be_able_to(:read, admin_set) + is_expected.to be_able_to(:edit, admin_set) + end + end + + context 'when admin user' do + let(:user) { FactoryGirl.create(:admin) } + + it 'allows all abilities' do # rubocop:disable RSpec/ExampleLength + is_expected.to be_able_to(:manage, AdminSet) + is_expected.to be_able_to(:manage_any, AdminSet) + is_expected.to be_able_to(:create_any, AdminSet) + is_expected.to be_able_to(:view_admin_show_any, AdminSet) + is_expected.to be_able_to(:edit, admin_set) + is_expected.to be_able_to(:update, admin_set) + is_expected.to be_able_to(:destroy, admin_set) + is_expected.to be_able_to(:deposit, admin_set) + is_expected.to be_able_to(:view_admin_show, admin_set) + is_expected.to be_able_to(:read, admin_set) # admins can do everything + end + end + + context 'when admin set manager' do + let(:admin_set) { create(:admin_set, id: 'as_mu', with_permission_template: true) } + + before do + create(:permission_template_access, + :manage, + permission_template: admin_set.permission_template, + agent_type: 'user', + agent_id: user.user_key) + admin_set.update_access_controls! + end + + it 'allows most abilities' do + is_expected.to be_able_to(:manage_any, AdminSet) + is_expected.to be_able_to(:view_admin_show_any, AdminSet) + is_expected.to be_able_to(:edit, admin_set) + is_expected.to be_able_to(:update, admin_set) + is_expected.to be_able_to(:destroy, admin_set) + is_expected.to be_able_to(:deposit, admin_set) + is_expected.to be_able_to(:view_admin_show, admin_set) + is_expected.to be_able_to(:read, admin_set) # edit access grants read and write + end + + it 'denies manage ability' do + is_expected.not_to be_able_to(:manage, AdminSet) + is_expected.not_to be_able_to(:create_any, AdminSet) # granted by collection type, not collection + end + end + + context 'when admin set depositor' do + let(:admin_set) { create(:admin_set, id: 'as_du', with_permission_template: true) } + + before do + create(:permission_template_access, + :deposit, + permission_template: admin_set.permission_template, + agent_type: 'user', + agent_id: user.user_key) + admin_set.update_access_controls! + end + + it 'allows deposit related abilities' do + is_expected.to be_able_to(:view_admin_show_any, AdminSet) + is_expected.to be_able_to(:deposit, admin_set) + is_expected.to be_able_to(:view_admin_show, admin_set) + end + + it 'denies non-deposit related abilities' do + is_expected.not_to be_able_to(:manage, AdminSet) + is_expected.not_to be_able_to(:manage_any, AdminSet) + is_expected.not_to be_able_to(:create_any, AdminSet) # granted by collection type, not collection + is_expected.not_to be_able_to(:edit, admin_set) + is_expected.not_to be_able_to(:update, admin_set) + is_expected.not_to be_able_to(:destroy, admin_set) + is_expected.not_to be_able_to(:read, admin_set) # no public page for admin sets + end + end + + context 'when admin set viewer' do + let(:admin_set) { create(:admin_set, id: 'as_vu', with_permission_template: true) } + + before do + create(:permission_template_access, + :view, + permission_template: admin_set.permission_template, + agent_type: 'user', + agent_id: user.user_key) + admin_set.update_access_controls! + end + + it 'allows viewing only ability' do + is_expected.to be_able_to(:view_admin_show_any, AdminSet) + is_expected.to be_able_to(:view_admin_show, admin_set) + end + + it 'denies most abilities' do + is_expected.not_to be_able_to(:manage, AdminSet) + is_expected.not_to be_able_to(:manage_any, AdminSet) + is_expected.not_to be_able_to(:create_any, AdminSet) # granted by collection type, not collection + is_expected.not_to be_able_to(:edit, admin_set) + is_expected.not_to be_able_to(:update, admin_set) + is_expected.not_to be_able_to(:destroy, admin_set) + is_expected.not_to be_able_to(:deposit, admin_set) + is_expected.not_to be_able_to(:read, admin_set) # no public page for admin sets + end + end + + context 'when user has no special access' do + let(:admin_set) { create(:admin_set, id: 'as', with_permission_template: true) } + + it 'denies all abilities' do # rubocop:disable RSpec/ExampleLength + is_expected.not_to be_able_to(:manage, AdminSet) + is_expected.not_to be_able_to(:manage_any, AdminSet) + is_expected.not_to be_able_to(:create_any, AdminSet) # granted by collection type, not collection + is_expected.not_to be_able_to(:view_admin_show_any, AdminSet) + is_expected.not_to be_able_to(:edit, admin_set) + is_expected.not_to be_able_to(:update, admin_set) + is_expected.not_to be_able_to(:destroy, admin_set) + is_expected.not_to be_able_to(:deposit, admin_set) + is_expected.not_to be_able_to(:view_admin_show, admin_set) + is_expected.not_to be_able_to(:read, admin_set) # no public page for admin sets + end + end +end diff --git a/spec/abilities/collection_abilities_spec.rb b/spec/abilities/collection_abilities_spec.rb deleted file mode 100644 index 17007445ac..0000000000 --- a/spec/abilities/collection_abilities_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'cancan/matchers' - -RSpec.describe 'User' do - describe 'Abilities' do - subject { ability } - - let(:ability) { Ability.new(current_user) } - let(:visibility) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE } - let(:creating_user) { create(:user) } - let(:user) { create(:user) } - let(:current_user) { user } - let(:collection) { create(:collection, visibility: visibility, user: creating_user) } - - before do - collection.visibility = visibility - collection.save - end - describe 'the collection creator' do - let(:current_user) { creating_user } - - it do - is_expected.to be_able_to(:create, ::Collection.new) - is_expected.to be_able_to(:create, ::Collection) - is_expected.to be_able_to(:read, collection) - is_expected.to be_able_to(:update, collection) - is_expected.to be_able_to(:destroy, collection) - end - end - - describe 'another authenticated user' do - it do - is_expected.to be_able_to(:create, ::Collection.new) - is_expected.to be_able_to(:create, ::Collection) - is_expected.not_to be_able_to(:read, collection) - is_expected.not_to be_able_to(:update, collection) - is_expected.not_to be_able_to(:destroy, collection) - end - end - - describe 'a nil user' do - let(:current_user) { nil } - - it do - is_expected.not_to be_able_to(:create, ::Collection.new) - is_expected.not_to be_able_to(:read, collection) - is_expected.not_to be_able_to(:update, collection) - is_expected.not_to be_able_to(:destroy, collection) - end - end - end -end diff --git a/spec/abilities/collection_ability_spec.rb b/spec/abilities/collection_ability_spec.rb new file mode 100644 index 0000000000..463e75c409 --- /dev/null +++ b/spec/abilities/collection_ability_spec.rb @@ -0,0 +1,159 @@ +require 'cancan/matchers' + +RSpec.describe 'CollectionAbility' do + subject { ability } + + let(:ability) { Ability.new(current_user) } + let(:user) { create(:user) } + let(:current_user) { user } + let(:collection_type_gid) { create(:collection_type).gid } + + context 'when admin user' do + let(:user) { FactoryGirl.create(:admin) } + let!(:collection) { create(:collection, id: 'as_au', with_permission_template: true, collection_type_gid: collection_type_gid) } + + it 'allows all abilities' do # rubocop:disable RSpec/ExampleLength + is_expected.to be_able_to(:manage, Collection) + is_expected.to be_able_to(:manage_any, Collection) + is_expected.to be_able_to(:create_any, Collection) + is_expected.to be_able_to(:view_admin_show_any, Collection) + is_expected.to be_able_to(:edit, collection) + is_expected.to be_able_to(:update, collection) + is_expected.to be_able_to(:destroy, collection) + is_expected.to be_able_to(:deposit, collection) + is_expected.to be_able_to(:view_admin_show, collection) + is_expected.to be_able_to(:read, collection) + end + end + + context 'when collection manager' do + let!(:collection) { create(:collection, id: 'as_mu', with_permission_template: true, collection_type_gid: collection_type_gid) } + + before do + create(:permission_template_access, + :manage, + permission_template: collection.permission_template, + agent_type: 'user', + agent_id: user.user_key) + collection.update_access_controls! + end + + it 'allows most abilities' do + is_expected.to be_able_to(:manage_any, Collection) + is_expected.to be_able_to(:view_admin_show_any, Collection) + is_expected.to be_able_to(:edit, collection) + is_expected.to be_able_to(:update, collection) + is_expected.to be_able_to(:destroy, collection) + is_expected.to be_able_to(:deposit, collection) + is_expected.to be_able_to(:view_admin_show, collection) + is_expected.to be_able_to(:read, collection) # edit access grants read and write + end + + it 'denies manage ability' do + is_expected.not_to be_able_to(:manage, Collection) + end + end + + context 'when collection depositor' do + let!(:collection) { create(:collection, id: 'as_du', with_permission_template: true, collection_type_gid: collection_type_gid) } + + before do + create(:permission_template_access, + :deposit, + permission_template: collection.permission_template, + agent_type: 'user', + agent_id: user.user_key) + collection.update_access_controls! + end + + it 'allows deposit related abilities' do + is_expected.to be_able_to(:view_admin_show_any, Collection) + is_expected.to be_able_to(:deposit, collection) + is_expected.to be_able_to(:view_admin_show, collection) + end + + it 'denies non-deposit related abilities' do + is_expected.not_to be_able_to(:manage, Collection) + is_expected.not_to be_able_to(:manage_any, Collection) + is_expected.not_to be_able_to(:edit, collection) + is_expected.not_to be_able_to(:update, collection) + is_expected.not_to be_able_to(:destroy, collection) + is_expected.not_to be_able_to(:read, collection) + end + end + + context 'when collection viewer' do + let!(:collection) { create(:collection, id: 'as_vu', with_permission_template: true, collection_type_gid: collection_type_gid) } + + before do + create(:permission_template_access, + :view, + permission_template: collection.permission_template, + agent_type: 'user', + agent_id: user.user_key) + collection.update_access_controls! + end + + it 'allows viewing only ability' do + is_expected.to be_able_to(:view_admin_show_any, Collection) + is_expected.to be_able_to(:view_admin_show, collection) + is_expected.to be_able_to(:read, collection) + end + + it 'denies most abilities' do + is_expected.not_to be_able_to(:manage, Collection) + is_expected.not_to be_able_to(:manage_any, Collection) + is_expected.not_to be_able_to(:edit, collection) + is_expected.not_to be_able_to(:update, collection) + is_expected.not_to be_able_to(:destroy, collection) + is_expected.not_to be_able_to(:deposit, collection) + end + end + + context 'when user has no special access' do + let!(:collection) { create(:collection, id: 'as', with_permission_template: true, collection_type_gid: collection_type_gid) } + + it 'denies all abilities' do + is_expected.not_to be_able_to(:manage, Collection) + is_expected.not_to be_able_to(:manage_any, Collection) + is_expected.not_to be_able_to(:view_admin_show_any, Collection) + is_expected.not_to be_able_to(:edit, collection) + is_expected.not_to be_able_to(:update, collection) + is_expected.not_to be_able_to(:destroy, collection) + is_expected.not_to be_able_to(:deposit, collection) + is_expected.not_to be_able_to(:view_admin_show, collection) + is_expected.not_to be_able_to(:read, collection) + end + end + + context 'create_any' do + # Whether a user can create a collection depends on collection type participants, so need to test separately. + + context 'when there are no collection types that have create access' do + before do + # User Collection type is always created and gives all users the ability to create. To be able to test that + # particular roles don't automatically give users create abilities, the create access for User Collection type + # has to be removed. + uct = Hyrax::CollectionType.find_by(machine_id: Hyrax::CollectionType::USER_COLLECTION_MACHINE_ID) + if uct.present? + uctp = Hyrax::CollectionTypeParticipant.find_by(hyrax_collection_type_id: uct.id, access: "create") + uctp.destroy if uctp.present? + end + end + + it 'denies create_any' do + is_expected.not_to be_able_to(:create_any, Collection) + end + end + + context 'when there are collection types that have create access' do + before do + Hyrax::CollectionType.find_or_create_default_collection_type + end + + it 'allows create_any' do + is_expected.to be_able_to(:create_any, Collection) + end + end + end +end diff --git a/spec/abilities/collection_type_ability_spec.rb b/spec/abilities/collection_type_ability_spec.rb new file mode 100644 index 0000000000..d4442ea0c7 --- /dev/null +++ b/spec/abilities/collection_type_ability_spec.rb @@ -0,0 +1,72 @@ +require 'cancan/matchers' + +RSpec.describe 'CollectionAbility' do + subject { ability } + + let(:ability) { Ability.new(current_user) } + let(:user) { create(:user) } + let(:current_user) { user } + + context 'when admin user' do + let(:user) { FactoryGirl.create(:admin) } + let(:collection_type) { create(:collection_type) } + + it 'allows all abilities' do + is_expected.to be_able_to(:manage, Hyrax::CollectionType) + is_expected.to be_able_to(:create, Hyrax::CollectionType) + is_expected.to be_able_to(:edit, collection_type) + is_expected.to be_able_to(:update, collection_type) + is_expected.to be_able_to(:destroy, collection_type) + is_expected.to be_able_to(:read, collection_type) + is_expected.to be_able_to(:create_collection_of_type, collection_type) + end + end + + context 'when user has manage access for collection type' do + let(:collection_type) { create(:collection_type, manager_user: user) } + + it 'allows creating collections of collection type' do + is_expected.to be_able_to(:create_collection_of_type, collection_type) + end + + it 'denies all abilities to collection type' do + is_expected.not_to be_able_to(:manage, Hyrax::CollectionType) + is_expected.not_to be_able_to(:create, Hyrax::CollectionType) + is_expected.not_to be_able_to(:edit, collection_type) + is_expected.not_to be_able_to(:update, collection_type) + is_expected.not_to be_able_to(:destroy, collection_type) + is_expected.not_to be_able_to(:read, collection_type) + end + end + + context 'when user has create access for collection type' do + let!(:collection_type) { create(:collection_type, creator_user: user) } + + it 'allows creating collections of collection type' do + is_expected.to be_able_to(:create_collection_of_type, collection_type) + end + + it 'denies all abilities to collection type' do + is_expected.not_to be_able_to(:manage, Hyrax::CollectionType) + is_expected.not_to be_able_to(:create, Hyrax::CollectionType) + is_expected.not_to be_able_to(:edit, collection_type) + is_expected.not_to be_able_to(:update, collection_type) + is_expected.not_to be_able_to(:destroy, collection_type) + is_expected.not_to be_able_to(:read, collection_type) + end + end + + context 'when user has no special access' do + let(:collection_type) { create(:collection_type) } + + it 'denies all abilities to collection type' do + is_expected.not_to be_able_to(:manage, Hyrax::CollectionType) + is_expected.not_to be_able_to(:create, Hyrax::CollectionType) + is_expected.not_to be_able_to(:edit, collection_type) + is_expected.not_to be_able_to(:update, collection_type) + is_expected.not_to be_able_to(:destroy, collection_type) + is_expected.not_to be_able_to(:read, collection_type) + is_expected.not_to be_able_to(:create_collection_of_type, collection_type) + end + end +end diff --git a/spec/abilities/permission_template_ability_spec.rb b/spec/abilities/permission_template_ability_spec.rb new file mode 100644 index 0000000000..68072ced37 --- /dev/null +++ b/spec/abilities/permission_template_ability_spec.rb @@ -0,0 +1,145 @@ +require 'cancan/matchers' + +RSpec.describe 'PermissionTemplateAbility' do + subject { ability } + + let(:ability) { Ability.new(current_user) } + let(:user) { create(:user) } + let(:current_user) { user } + let(:collection_type_gid) { create(:collection_type).gid } + + let!(:collection) { create(:collection, with_permission_template: true, collection_type_gid: collection_type_gid) } + let(:permission_template) { collection.permission_template } + let!(:permission_template_access) do + create(:permission_template_access, + :manage, + permission_template: permission_template, + agent_type: 'group', + agent_id: 'manage_group') + end + + context 'when admin user' do + let(:user) { FactoryGirl.create(:admin) } + + it 'allows all template abilities' do + is_expected.to be_able_to(:manage, Hyrax::PermissionTemplate) + is_expected.to be_able_to(:create, permission_template) + is_expected.to be_able_to(:edit, permission_template) + is_expected.to be_able_to(:update, permission_template) + is_expected.to be_able_to(:destroy, permission_template) + end + + it 'allows all template access abilities' do + is_expected.to be_able_to(:manage, Hyrax::PermissionTemplateAccess) + is_expected.to be_able_to(:create, permission_template_access) + is_expected.to be_able_to(:edit, permission_template_access) + is_expected.to be_able_to(:update, permission_template_access) + is_expected.to be_able_to(:destroy, permission_template_access) + end + end + + context 'when user has manage access for the source' do + before do + create(:permission_template_access, + :manage, + permission_template: permission_template, + agent_type: 'user', + agent_id: user.user_key) + collection.update_access_controls! + end + + it 'allows most template abilities' do + is_expected.to be_able_to(:create, permission_template) + is_expected.to be_able_to(:edit, permission_template) + is_expected.to be_able_to(:update, permission_template) + is_expected.to be_able_to(:destroy, permission_template) + end + + it 'denies manage ability for template' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplate) + end + + it 'allows most template access abilities' do + is_expected.to be_able_to(:create, permission_template_access) + is_expected.to be_able_to(:edit, permission_template_access) + is_expected.to be_able_to(:update, permission_template_access) + is_expected.to be_able_to(:destroy, permission_template_access) + end + + it 'denies manage ability for template access' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplateAccess) + end + end + + context 'when user has deposit access for the source' do + before do + create(:permission_template_access, + :deposit, + permission_template: permission_template, + agent_type: 'user', + agent_id: user.user_key) + collection.update_access_controls! + end + + it 'denies all template abilities' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplate) + is_expected.not_to be_able_to(:create, permission_template) + is_expected.not_to be_able_to(:edit, permission_template) + is_expected.not_to be_able_to(:update, permission_template) + is_expected.not_to be_able_to(:destroy, permission_template) + end + + it 'denies all template access abilities' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplateAccess) + is_expected.not_to be_able_to(:create, permission_template_access) + is_expected.not_to be_able_to(:edit, permission_template_access) + is_expected.not_to be_able_to(:update, permission_template_access) + is_expected.not_to be_able_to(:destroy, permission_template_access) + end + end + + context 'when user has view access for the source' do + before do + create(:permission_template_access, + :view, + permission_template: permission_template, + agent_type: 'user', + agent_id: user.user_key) + collection.update_access_controls! + end + + it 'denies all template abilities' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplate) + is_expected.not_to be_able_to(:create, permission_template) + is_expected.not_to be_able_to(:edit, permission_template) + is_expected.not_to be_able_to(:update, permission_template) + is_expected.not_to be_able_to(:destroy, permission_template) + end + + it 'denies all template access abilities' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplateAccess) + is_expected.not_to be_able_to(:create, permission_template_access) + is_expected.not_to be_able_to(:edit, permission_template_access) + is_expected.not_to be_able_to(:update, permission_template_access) + is_expected.not_to be_able_to(:destroy, permission_template_access) + end + end + + context 'when user has no special access' do + it 'denies all template abilities' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplate) + is_expected.not_to be_able_to(:create, permission_template) + is_expected.not_to be_able_to(:edit, permission_template) + is_expected.not_to be_able_to(:update, permission_template) + is_expected.not_to be_able_to(:destroy, permission_template) + end + + it 'denies all template access abilities' do + is_expected.not_to be_able_to(:manage, Hyrax::PermissionTemplateAccess) + is_expected.not_to be_able_to(:create, permission_template_access) + is_expected.not_to be_able_to(:edit, permission_template_access) + is_expected.not_to be_able_to(:update, permission_template_access) + is_expected.not_to be_able_to(:destroy, permission_template_access) + end + end +end diff --git a/spec/search_builders/hyrax/admin_set_search_builder_spec.rb b/spec/search_builders/hyrax/admin_set_search_builder_spec.rb index 156ce4428b..493083b25d 100644 --- a/spec/search_builders/hyrax/admin_set_search_builder_spec.rb +++ b/spec/search_builders/hyrax/admin_set_search_builder_spec.rb @@ -25,7 +25,7 @@ context "when access is :deposit" do let(:access) { :deposit } let(:admin_set) { create(:admin_set) } - let(:permission_template) { create(:permission_template, source_id: admin_set.id) } + let(:permission_template) { create(:permission_template, source_id: admin_set.id, source_type: 'admin_set') } context "and user has access" do before do @@ -83,9 +83,9 @@ context "when searching for deposit access" do let(:access) { :deposit } - let(:permission_template1) { create(:permission_template, source_id: 7) } - let(:permission_template2) { create(:permission_template, source_id: 8) } - let(:permission_template3) { create(:permission_template, source_id: 9) } + let(:permission_template1) { create(:permission_template, source_id: 7, source_type: 'admin_set') } + let(:permission_template2) { create(:permission_template, source_id: 8, source_type: 'admin_set') } + let(:permission_template3) { create(:permission_template, source_id: 9, source_type: 'admin_set') } before do create(:permission_template_access, diff --git a/spec/search_builders/hyrax/dashboard/collections_search_builder_spec.rb b/spec/search_builders/hyrax/dashboard/collections_search_builder_spec.rb index 2de9a327b0..04d2b0853b 100644 --- a/spec/search_builders/hyrax/dashboard/collections_search_builder_spec.rb +++ b/spec/search_builders/hyrax/dashboard/collections_search_builder_spec.rb @@ -51,8 +51,8 @@ describe "#gated_discovery_filters" do subject { builder.gated_discovery_filters } - let(:admin_set) { create(:admin_set) } - let(:permission_template) { create(:permission_template, source_id: admin_set.id) } + let(:collection) { create(:collection) } + let(:permission_template) { create(:permission_template, source_id: collection.id, source_type: 'collection') } context "user has deposit access" do before do @@ -63,7 +63,7 @@ access: 'deposit') end - it { is_expected.to include ["{!terms f=id}#{admin_set.id}"] } + it { is_expected.to include ["{!terms f=id}#{collection.id}"] } end context "group has deposit access" do @@ -75,7 +75,7 @@ access: 'deposit') end - it { is_expected.to include ["{!terms f=id}#{admin_set.id}"] } + it { is_expected.to include ["{!terms f=id}#{collection.id}"] } end context "does not include public group for read access" do diff --git a/spec/services/hyrax/collection_types/create_service_spec.rb b/spec/services/hyrax/collection_types/create_service_spec.rb index eb48575295..847c904081 100644 --- a/spec/services/hyrax/collection_types/create_service_spec.rb +++ b/spec/services/hyrax/collection_types/create_service_spec.rb @@ -22,4 +22,23 @@ end.to change(Hyrax::CollectionTypeParticipant, :count).by(described_class::DEFAULT_OPTIONS[:participants].count) end end + + describe '.add_default_participants' do + let(:coltype) { create(:collection_type) } + + it 'adds the default participants to a collection type' do + expect(Hyrax::CollectionTypeParticipant).to receive(:create!).exactly(2).times + described_class.add_default_participants(coltype.id) + end + end + + describe '.add_participants' do + let(:participants) { [{ agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, agent_id: 'test_group', access: Hyrax::CollectionTypeParticipant::MANAGE_ACCESS }] } + let(:coltype) { create(:collection_type) } + + it 'adds the participants to a collection type' do + expect(Hyrax::CollectionTypeParticipant).to receive(:create!) + described_class.add_participants(coltype.id, participants) + end + end end diff --git a/spec/services/hyrax/collection_types/permissions_service_spec.rb b/spec/services/hyrax/collection_types/permissions_service_spec.rb index 60b846449e..104fc620b0 100644 --- a/spec/services/hyrax/collection_types/permissions_service_spec.rb +++ b/spec/services/hyrax/collection_types/permissions_service_spec.rb @@ -10,7 +10,7 @@ let!(:admin_set_collection_type) { create(:admin_set_collection_type) } let!(:collection_type) { create(:collection_type, creator_user: user_cu, creator_group: 'create_group', manager_user: user_mu, manager_group: 'manage_group') } - describe '.collection_types_for_user' do + describe '.collection_types_for_user' do # Also tests .collection_type_ids_for_user which is called by .collection_types_for_user let!(:ability) { ::Ability.new(user) } before { allow(ability).to receive(:current_user).and_return(user) } @@ -114,6 +114,99 @@ end end + describe '.can_create_any_collection_type?' do + let!(:ability) { ::Ability.new(user) } + + before do + allow(ability).to receive(:current_user).and_return(user) + end + + subject { described_class.can_create_any_collection_type?(user: user) } + + context 'when user is a create user' do + let(:user) { user_cu } + + it { is_expected.to be true } + end + + context 'when user is in create group' do + let(:user) { user_cg } + + it { is_expected.to be true } + end + + context 'when user is a manage user' do + let(:user) { user_mu } + + it { is_expected.to be true } + end + + context 'when user is in manage group' do + let(:user) { user_mg } + + it { is_expected.to be true } + end + + context 'when user is an admin' do + let(:user) { user_admin } + + it { is_expected.to be true } + end + + context 'when user with no access' do + let(:user) { user_other } + + # TODO: Fails for now becauser User Collection type is always created and it allows every logged in user to create one. + # Would require additional work to remove or change the User Collection participants so there are 0 collection types the + # user can create. + xit { is_expected.to be false } + end + end + + describe '.can_create_admin_set?' do + let!(:ability) { ::Ability.new(user) } + + before { allow(ability).to receive(:current_user).and_return(user) } + + subject { described_class.can_create_admin_set_collection_type?(user: user) } + + context 'when user is a create user' do + let(:user) { user_cu } + + it { is_expected.to be false } + end + + context 'when user is in create group' do + let(:user) { user_cg } + + it { is_expected.to be false } + end + + context 'when user is a manage user' do + let(:user) { user_mu } + + it { is_expected.to be false } + end + + context 'when user is in manage group' do + let(:user) { user_mg } + + it { is_expected.to be false } + end + + context 'when user is an admin' do + let(:user) { user_admin } + + it { is_expected.to be true } + end + + context 'when user with no access' do + let(:user) { user_other } + + it { is_expected.to be false } + end + end + describe '.can_create_collection_types' do let!(:ability) { ::Ability.new(user) } @@ -201,23 +294,4 @@ it { is_expected.to match_array ['manage_group', 'admin'] } end end - - describe '.add_default_participants' do - let(:coltype) { create(:collection_type) } - - it 'adds the default participants to a collection type' do - expect(Hyrax::CollectionTypeParticipant).to receive(:create!).exactly(2).times - described_class.add_default_participants(coltype.id) - end - end - - describe ".add_participants" do - let(:participants) { [{ agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, agent_id: 'test_group', access: Hyrax::CollectionTypeParticipant::MANAGE_ACCESS }] } - let(:coltype) { create(:collection_type) } - - it 'adds the participants to a collection type' do - expect(Hyrax::CollectionTypeParticipant).to receive(:create!) - described_class.add_participants(coltype.id, participants) - end - end end diff --git a/spec/services/hyrax/collections/permissions_service_spec.rb b/spec/services/hyrax/collections/permissions_service_spec.rb index 1716627a27..d62d951a00 100644 --- a/spec/services/hyrax/collections/permissions_service_spec.rb +++ b/spec/services/hyrax/collections/permissions_service_spec.rb @@ -1,258 +1,105 @@ RSpec.describe Hyrax::Collections::PermissionsService do let(:user) { create(:user) } - let(:user2) { create(:user) } - describe ".can_deposit_in_collection?" do - subject { described_class.can_deposit_in_collection?(collection: collection, user: user) } + let(:ability) { double } - let(:ability) { double } - - let(:permission_template) { create(:permission_template) } - let(:collection) { create(:collection, user: user) } + context 'collection specific methods' do + let(:collection) { create(:collection) } + let(:admin_set) { create(:admin_set) } + let(:col_permission_template) { create(:permission_template, source_type: 'collection', source_id: collection.id) } + let(:as_permission_template) { create(:permission_template, source_type: 'admin_set', source_id: admin_set.id) } before do - allow(Hyrax::PermissionTemplate).to receive(:find_by!).with(source_id: collection.id).and_return(permission_template) + allow(Hyrax::PermissionTemplate).to receive(:find_by!).with(source_id: collection.id).and_return(col_permission_template) allow(ability).to receive(:current_user).and_return(user) - allow(user).to receive(:ability).and_return(ability) allow(ability).to receive(:user_groups).and_return(['public', 'registered']) + allow(described_class).to receive(:user_admin?).with(user, nil).and_return(false) + allow(user).to receive(:ability).and_return(ability) end - it "exists" do - expect(described_class).to respond_to(:can_deposit_in_collection?) - end - - it "returns true when user is a manager" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - expect(subject).to be true - end - - it "returns true when user is a depositor" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - expect(subject).to be true - end - - it "returns false when user is a viewer" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([user.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) - expect(subject).to be false - end - - context "when manage group access defined" do + context 'when manage user' do before do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - end - - it "returns true if user has any valid group" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'managers']) - expect(subject).to be true - end - - it "returns true if user has multiple valid groups" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_managers', 'managers', 'other_group']) - expect(subject).to be true + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user.user_key]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) end - end - context "when deposit group access defined" do - before do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) - end + subject { described_class } - it "returns true if user has any valid group" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'depositors']) - expect(subject).to be true + it ".can_deposit_in_collection? returns true" do + expect(subject.can_deposit_in_collection?(collection: collection, user: user)).to be true end - - it "returns true if user has multiple valid groups" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_depositors', 'depositors', 'other_group']) - expect(subject).to be true + it ".can_view_admin_show_for_collection? returns true" do + expect(subject.can_view_admin_show_for_collection?(collection: collection, user: user)).to be true end end - context "when view group access defined" do + context 'when deposit user' do before do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return(['viewers', 'more_viewers']) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user.user_key]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) end - it "returns false if user has any view group" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'viewers']) - expect(subject).to be false - end + subject { described_class } - it "returns false if user has multiple view groups" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_viewers', 'viewers', 'other_group']) - expect(subject).to be false + it ".can_deposit_in_collection? returns true" do + expect(subject.can_deposit_in_collection?(collection: collection, user: user)).to be true end - end - - it "returns false when user is neither a manager nor depositor" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user2.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user2.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) - allow(ability).to receive(:user_groups).and_return(['public', 'registered']) - expect(subject).to be false - end - end - - describe ".can_view_admin_show_for_collection?" do - subject { described_class.can_view_admin_show_for_collection?(collection: collection, user: user) } - - let(:ability) { double } - let(:permission_template) { create(:permission_template) } - let(:collection) { create(:collection, user: user) } - - before do - allow(Hyrax::PermissionTemplate).to receive(:find_by!).with(source_id: collection.id).and_return(permission_template) - allow(ability).to receive(:current_user).and_return(user) - allow(user).to receive(:ability).and_return(ability) - allow(ability).to receive(:user_groups).and_return(['public', 'registered']) - end - - it "exists" do - expect(described_class).to respond_to(:can_view_admin_show_for_collection?) - end - - it "returns true when user is a manager" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) - expect(subject).to be true - end - - it "returns true when user is a depositor" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) - expect(subject).to be true - end - - it "returns true when user is a viewer" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([user.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) - expect(subject).to be true - end - - context "when manage group access defined" do - before do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) - end - - it "returns false if no user groups" do - allow(ability).to receive(:user_groups).and_return([]) - expect(subject).to be false - end - - it "returns true if user has any valid group" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'managers']) - expect(subject).to be true - end - - it "returns true if user has multiple valid groups" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_managers', 'managers', 'other_group']) - expect(subject).to be true + it ".can_view_admin_show_for_collection? returns true" do + expect(subject.can_view_admin_show_for_collection?(collection: collection, user: user)).to be true end end - context "when deposit group access defined" do + context 'when view user' do before do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([user.user_key]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) + allow(col_permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return([]) end - it "returns true if user has any valid group" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'depositors']) - expect(subject).to be true - end + subject { described_class } - it "returns true if user has multiple valid groups" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_depositors', 'depositors', 'other_group']) - expect(subject).to be true + it ".can_deposit_in_collection? returns true" do + expect(subject.can_deposit_in_collection?(collection: collection, user: user)).to be false + end + it ".can_view_admin_show_for_collection? returns true" do + expect(subject.can_view_admin_show_for_collection?(collection: collection, user: user)).to be true end end - context "when view group access defined" do - before do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return([]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return(['viewers', 'more_viewers']) - end + context 'when user without access' do + subject { described_class } - it "returns true if user has any valid group" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'viewers']) - expect(subject).to be true + it ".can_deposit_in_collection? returns true" do + expect(subject.can_deposit_in_collection?(collection: collection, user: user)).to be false end - - it "returns true if user has multiple valid groups" do - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'more_viewers', 'viewers', 'other_group']) - expect(subject).to be true + it ".can_view_admin_show_for_collection? returns true" do + expect(subject.can_view_admin_show_for_collection?(collection: collection, user: user)).to be false end end - - it "returns false when user is does not have access as manager, depositor, or viewer" do - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'manage').and_return([user2.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'deposit').and_return([user2.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'user', access: 'view').and_return([user2.user_key]) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'manage').and_return(['managers', 'more_managers']) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'deposit').and_return(['depositors', 'more_depositors']) - allow(permission_template).to receive(:agent_ids_for).with(agent_type: 'group', access: 'view').and_return(['viewers', 'more_viewers']) - allow(ability).to receive(:user_groups).and_return([]) - expect(subject).to be false - end end - context "access helper method" do - let(:ability) { double } + context 'methods returning ids' do let(:user) { create(:user) } + let(:user2) { create(:user) } + let(:col_vu) { create(:collection, id: 'col_vu', with_permission_template: true) } let(:col_vg) { create(:collection, id: 'col_vg', with_permission_template: true) } let(:col_mu) { create(:collection, id: 'col_mu', with_permission_template: true) } let(:col_mg) { create(:collection, id: 'col_mg', with_permission_template: true) } let(:col_du) { create(:collection, id: 'col_du', with_permission_template: true) } let(:col_dg) { create(:collection, id: 'col_dg', with_permission_template: true) } + let(:as_vu) { create(:admin_set, id: 'as_vu', with_permission_template: true) } let(:as_vg) { create(:admin_set, id: 'as_vg', with_permission_template: true) } let(:as_mu) { create(:admin_set, id: 'as_mu', with_permission_template: true) } @@ -267,6 +114,7 @@ source_access(col_mg.permission_template, 'group', 'manage_group', :manage) source_access(col_du.permission_template, 'user', user.user_key, :deposit) source_access(col_dg.permission_template, 'group', 'deposit_group', :deposit) + source_access(as_vu.permission_template, 'user', user.user_key, :view) source_access(as_vg.permission_template, 'group', 'view_group', :view) source_access(as_mu.permission_template, 'user', user.user_key, :manage) @@ -274,45 +122,185 @@ source_access(as_du.permission_template, 'user', user.user_key, :deposit) source_access(as_dg.permission_template, 'group', 'deposit_group', :deposit) - allow(ability).to receive(:current_user).and_return(user) - allow(user).to receive(:ability).and_return(ability) - allow(ability).to receive(:user_groups).and_return(['public', 'registered', 'view_group', 'manage_group', 'deposit_group']) - allow(ability).to receive(:admin?).and_return(false) + allow(user).to receive(:groups).and_return(['view_group', 'deposit_group', 'manage_group']) end + describe '.source_ids_for_user' do + it 'returns collection and admin set ids where user has manage access' do + expect(described_class.source_ids_for_user(access: 'manage', user: user)).to match_array [col_mu.id, col_mg.id, as_mu.id, as_mg.id] + end + it 'returns collection ids where user has manage access' do + expect(described_class.source_ids_for_user(access: 'manage', user: user, source_type: 'collection')).to match_array [col_mu.id, col_mg.id] + end + it 'returns admin set ids where user has manage access' do + expect(described_class.source_ids_for_user(access: 'manage', user: user, source_type: 'admin_set')).to match_array [as_mu.id, as_mg.id] + end + it 'returns collection and admin set ids where user has deposit access' do + expect(described_class.source_ids_for_user(access: 'deposit', user: user)).to match_array [col_du.id, col_dg.id, as_du.id, as_dg.id] + end + it 'returns collection ids where user has deposit access' do + expect(described_class.source_ids_for_user(access: 'deposit', user: user, source_type: 'collection')).to match_array [col_du.id, col_dg.id] + end + it 'returns admin set ids where user has deposit access' do + expect(described_class.source_ids_for_user(access: 'deposit', user: user, source_type: 'admin_set')).to match_array [as_du.id, as_dg.id] + end + it 'returns collection and admin set ids where user has view access' do + expect(described_class.source_ids_for_user(access: 'view', user: user)).to match_array [col_vu.id, col_vg.id, as_vu.id, as_vg.id] + end + it 'returns collection ids where user has view access' do + expect(described_class.source_ids_for_user(access: 'view', user: user, source_type: 'collection')).to match_array [col_vu.id, col_vg.id] + end + it 'returns admin set ids where user has view access' do + expect(described_class.source_ids_for_user(access: 'view', user: user, source_type: 'admin_set')).to match_array [as_vu.id, as_vg.id] + end + it 'returns collection and admin set ids where user has manage, deposit, or view access' do + all = [col_mu.id, col_mg.id, col_du.id, col_dg.id, col_vu.id, col_vg.id, as_mu.id, as_mg.id, as_du.id, as_dg.id, as_vu.id, as_vg.id] + expect(described_class.source_ids_for_user(access: ['manage', 'deposit', 'view'], user: user)).to match_array all + end + it 'returns collection ids where user has manage, deposit, or view access' do + all = [col_mu.id, col_mg.id, col_du.id, col_dg.id, col_vu.id, col_vg.id] + expect(described_class.source_ids_for_user(access: ['manage', 'deposit', 'view'], user: user, source_type: 'collection')).to match_array all + end + it 'returns admin set ids where user has manage, deposit, or view access' do + all = [as_mu.id, as_mg.id, as_du.id, as_dg.id, as_vu.id, as_vg.id] + expect(described_class.source_ids_for_user(access: ['manage', 'deposit', 'view'], user: user, source_type: 'admin_set')).to match_array all + end + it 'returns empty array when user has no access' do + expect(described_class.source_ids_for_user(access: ['manage', 'deposit', 'view'], user: user2)).to match_array [] + end + end describe '.admin_set_ids_for_user' do - it 'returns ids for admin sets with view user and group' do - expect(described_class.admin_set_ids_for_user(user: user, access: 'view')).to match_array [as_vu.id, as_vg.id] + it 'returns admin set ids where user has manage access' do + expect(described_class.admin_set_ids_for_user(access: 'manage', user: user)).to match_array [as_mu.id, as_mg.id] + end + it 'returns admin set ids where user has deposit access' do + expect(described_class.admin_set_ids_for_user(access: 'deposit', user: user)).to match_array [as_du.id, as_dg.id] + end + it 'returns admin set ids where user has view access' do + expect(described_class.admin_set_ids_for_user(access: 'view', user: user)).to match_array [as_vu.id, as_vg.id] end - it 'returns ids for admin sets with manage user and group' do - expect(described_class.admin_set_ids_for_user(user: user, access: 'manage')).to match_array [as_mu.id, as_mg.id] + it 'returns admin set ids where user has manage, deposit, or view access' do + all = [as_mu.id, as_mg.id, as_du.id, as_dg.id, as_vu.id, as_vg.id] + expect(described_class.admin_set_ids_for_user(access: ['manage', 'deposit', 'view'], user: user)).to match_array all end - it 'returns ids for admin sets with deposit user and group' do - expect(described_class.admin_set_ids_for_user(user: user, access: 'deposit')).to match_array [as_du.id, as_dg.id] + it 'returns empty array when user has no access' do + expect(described_class.admin_set_ids_for_user(access: ['manage', 'deposit', 'view'], user: user2)).to match_array [] end end - describe '.collection_ids_for_user' do - it 'returns ids for collections with view user and group' do - expect(described_class.collection_ids_for_user(user: user, access: 'view')).to match_array [col_vu.id, col_vg.id] + it 'returns collection ids where user has manage access' do + expect(described_class.collection_ids_for_user(access: 'manage', user: user)).to match_array [col_mu.id, col_mg.id] + end + it 'returns collection ids where user has deposit access' do + expect(described_class.collection_ids_for_user(access: 'deposit', user: user)).to match_array [col_du.id, col_dg.id] + end + it 'returns collection ids where user has view access' do + expect(described_class.collection_ids_for_user(access: 'view', user: user)).to match_array [col_vu.id, col_vg.id] end - it 'returns ids for collections with manage user and group' do - expect(described_class.collection_ids_for_user(user: user, access: 'manage')).to match_array [col_mu.id, col_mg.id] + it 'returns collection ids where user has manage, deposit, or view access' do + all = [col_mu.id, col_mg.id, col_du.id, col_dg.id, col_vu.id, col_vg.id] + expect(described_class.collection_ids_for_user(access: ['manage', 'deposit', 'view'], user: user)).to match_array all end - it 'returns ids for collections with deposit user and group' do - expect(described_class.collection_ids_for_user(user: user, access: 'deposit')).to match_array [col_du.id, col_dg.id] + it 'returns empty array when user has no access' do + expect(described_class.collection_ids_for_user(access: ['manage', 'deposit', 'view'], user: user2)).to match_array [] end end - describe '.source_ids_for_user' do - it 'returns ids for collections with view user and group' do - expect(described_class.source_ids_for_user(user: user, access: 'view')).to match_array [col_vu.id, col_vg.id, as_vu.id, as_vg.id] + describe '.source_ids_for_manage' do + it 'returns collection and admin set ids where user has manage access' do + expect(described_class.source_ids_for_manage(user: user)).to match_array [col_mu.id, col_mg.id, as_mu.id, as_mg.id] + end + it 'returns collection ids where user has manage access' do + expect(described_class.source_ids_for_manage(user: user, source_type: 'collection')).to match_array [col_mu.id, col_mg.id] + end + it 'returns admin set ids where user has manage access' do + expect(described_class.source_ids_for_manage(user: user, source_type: 'admin_set')).to match_array [as_mu.id, as_mg.id] + end + it 'returns empty array when user has no access' do + expect(described_class.source_ids_for_manage(user: user2)).to match_array [] + end + end + describe '.admin_set_ids_for_manage' do + it 'returns admin set ids where user has manage access' do + expect(described_class.admin_set_ids_for_manage(user: user)).to match_array [as_mu.id, as_mg.id] + end + it 'returns empty array when user has no access' do + expect(described_class.admin_set_ids_for_manage(user: user2)).to match_array [] end - it 'returns ids for collections with manage user and group' do - expect(described_class.source_ids_for_user(user: user, access: 'manage')).to match_array [col_mu.id, col_mg.id, as_mu.id, as_mg.id] + end + describe '.collection_ids_for_manage' do + it 'returns collection ids where user has manage access' do + expect(described_class.collection_ids_for_manage(user: user)).to match_array [col_mu.id, col_mg.id] + end + it 'returns empty array when user has no access' do + expect(described_class.collection_ids_for_manage(user: user2)).to match_array [] + end + end + + describe '.source_ids_for_deposit' do + it 'returns collection and admin set ids where user has deposit access' do + expect(described_class.source_ids_for_deposit(user: user)).to match_array [col_du.id, col_dg.id, col_mu.id, col_mg.id, as_du.id, as_dg.id, as_mu.id, as_mg.id] + end + it 'returns collection ids where user has deposit access' do + expect(described_class.source_ids_for_deposit(user: user, source_type: 'collection')).to match_array [col_du.id, col_dg.id, col_mu.id, col_mg.id] + end + it 'returns admin set ids where user has deposit access' do + expect(described_class.source_ids_for_deposit(user: user, source_type: 'admin_set')).to match_array [as_du.id, as_dg.id, as_mu.id, as_mg.id] + end + it 'returns empty array when user has no access' do + expect(described_class.source_ids_for_deposit(user: user2)).to match_array [] + end + end + describe '.collection_ids_for_deposit' do + it 'returns collection ids where user has manage access' do + expect(described_class.collection_ids_for_deposit(user: user)).to match_array [col_du.id, col_dg.id, col_mu.id, col_mg.id] + end + it 'returns empty array when user has no access' do + expect(described_class.collection_ids_for_deposit(user: user2)).to match_array [] + end + end + describe '.admin_set_ids_for_deposit' do + it 'returns admin set ids where user has manage access' do + expect(described_class.admin_set_ids_for_deposit(user: user)).to match_array [as_du.id, as_dg.id, as_mu.id, as_mg.id] + end + it 'returns empty array when user has no access' do + expect(described_class.admin_set_ids_for_deposit(user: user2)).to match_array [] + end + end + + describe '.can_manage_any_collection?' do + it 'returns true when user has manage access to at least one collection' do + expect(described_class.can_manage_any_collection?(user: user)).to be true + end + it 'returns false when user does not have manage access to any collections' do + expect(described_class.can_manage_any_collection?(user: user2)).to be false + end + end + + describe '.can_manage_any_admin_set?' do + it 'returns true when user has manage access to at least one admin set' do + expect(described_class.can_manage_any_admin_set?(user: user)).to be true + end + it 'returns false when user does not have manage access to any admin sets' do + expect(described_class.can_manage_any_admin_set?(user: user2)).to be false + end + end + + describe '.can_view_admin_show_for_any_collection?' do + it 'returns true when user has manage, deposit, or view access to at least one collection' do + expect(described_class.can_view_admin_show_for_any_collection?(user: user)).to be true + end + it 'returns false when user does not have manage, deposit, or view access to any collections' do + expect(described_class.can_view_admin_show_for_any_collection?(user: user2)).to be false + end + end + + describe '.can_view_admin_show_for_any_admin set?' do + it 'returns true when user has manage, deposit, or view access to at least one admin set' do + expect(described_class.can_view_admin_show_for_any_admin_set?(user: user)).to be true end - it 'returns ids for collections with deposit user and group' do - expect(described_class.source_ids_for_user(user: user, access: 'deposit')).to match_array [col_du.id, col_dg.id, as_du.id, as_dg.id] + it 'returns false when user does not have manage, deposit, or view access to any admin sets' do + expect(described_class.can_view_admin_show_for_any_admin_set?(user: user2)).to be false end end end