From d222c351d329c69b253d646d0d8d7e063ba5cfcf Mon Sep 17 00:00:00 2001 From: "E. Lynette Rayle" Date: Sun, 17 Sep 2017 12:09:10 -0400 Subject: [PATCH 1/2] Implement can_deposit_in_collection in collection permissions service NOTE: Removed all other stubbed methods as Hyrax::PermissionTemplate model already provides the functionality. --- .../hyrax/collections/permissions_service.rb | 78 +++++--------- .../collections/permissions_service_spec.rb | 101 +++++++++++++----- 2 files changed, 102 insertions(+), 77 deletions(-) diff --git a/app/services/hyrax/collections/permissions_service.rb b/app/services/hyrax/collections/permissions_service.rb index 637f4e6f02..40e73a25d5 100644 --- a/app/services/hyrax/collections/permissions_service.rb +++ b/app/services/hyrax/collections/permissions_service.rb @@ -1,18 +1,6 @@ module Hyrax module Collections class PermissionsService - # @api public - # - # Get a list of users who should be added as user editors for a collection - # - # @param collection [Hyrax::Collection] the collection for which permissions are being set - # @return [Array] array of user identifiers (typically emails) for users who can edit this collection - def self.user_edit_grants_for_collection(collection: nil) - return [] unless collection - # Stubbed to return no grants - [] - end - # @api public # # Determine if the given user has permissions to deposit into the given collection @@ -22,56 +10,40 @@ def self.user_edit_grants_for_collection(collection: nil) # @return [Boolean] true if the user has permission to depoisit into the collection def self.can_deposit_in_collection(user:, collection:) return false unless user && collection - # stubbed - end - - # @api public - # - # Get a list of users who should be added as user viewers for a collection - # - # @param collection [Hyrax::Collection] the collection for which permissions are being set - # @return [Array] array of user identifiers (typically emails) for users who can view this collection - def self.user_view_grants_for_collection(collection: nil) - return [] unless collection - # Stubbed to return no grants - [] + 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 end - # @api public - # - # Get a list of groups that should be added as group editors for a collection - # - # @param collection [Hyrax::Collection] the collection for which permissions are being set - # @return [Array] array of group identifiers (typically groupname) for groups who can edit this collection - def self.group_edit_grants_for_collection(collection: nil) - return [] unless collection - # Stubbed to return no grants - [] - end - - # @api public + # @api private # - # Get a list of groups that should be added as group depositors for a collection + # Does the user have 'manage' or 'deposit' access? # - # @param collection [Hyrax::Collection] the collection for which permissions are being set - # @return [Array] array of group identifiers (typically groupname) for groups who can deposit to this collection - def self.group_deposit_grants_for_collection(collection: nil) - return [] unless collection - # Stubbed to return no grants - [] + # @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 end + private_class_method :access_as_user? - # @api public + # @api private # - # Get a list of groups that should be added as group viewers for a collection + # Do any of the groups have 'manage' or 'deposit' access? # - # @param collection [Hyrax::Collection] the collection for which permissions are being set - # @return [Array] array of group identifiers (typically groupname) for groups who can view this collection - def self.group_view_grants_for_collection(collection: nil) - return [] unless collection - # Stubbed to return no grants - [] + # @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 # diff --git a/spec/services/hyrax/collections/permissions_service_spec.rb b/spec/services/hyrax/collections/permissions_service_spec.rb index b7dfec5a35..48498498e6 100644 --- a/spec/services/hyrax/collections/permissions_service_spec.rb +++ b/spec/services/hyrax/collections/permissions_service_spec.rb @@ -1,9 +1,10 @@ RSpec.describe Hyrax::Collections::PermissionsService do - describe "create_default" do + let(:user) { create(:user) } + let(:user2) { create(:user) } + + describe ".create_default" do subject { described_class.create_default(collection: collection, creating_user: user) } - let(:user) { create(:user) } - let(:user2) { create(:user) } let(:collection_type) { create(:collection_type) } let(:user_manage_attributes) do { @@ -38,39 +39,91 @@ end end - describe "user_edit_grants_for_collection" do - it "exists" do - expect(described_class).to respond_to(:user_edit_grants_for_collection) + describe ".can_deposit_in_collection" do + subject { described_class.can_deposit_in_collection(collection: collection, user: user) } + + 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) end - end - describe "can_deposit_in_collection" do it "exists" do expect(described_class).to respond_to(:can_deposit_in_collection) end - end - describe "user_view_grants_for_collection" do - it "exists" do - expect(described_class).to respond_to(:user_view_grants_for_collection) + 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 - end - describe "group_edit_grants_for_collection" do - it "exists" do - expect(described_class).to respond_to(:group_edit_grants_for_collection) + 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 - end - describe "group_deposit_grants_for_collection" do - it "exists" do - expect(described_class).to respond_to(:group_deposit_grants_for_collection) + 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 false if no user groups" do + allow(user).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']) + 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']) + expect(subject).to be true + end end - end - describe "group_view_grants_for_collection" do - it "exists" do - expect(described_class).to respond_to(:group_view_grants_for_collection) + 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 false if no user groups" do + allow(user).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(['depositors']) + 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']) + expect(subject).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(user).to receive(:user_groups).and_return([]) + expect(subject).to be false end end end From c103003af1d2e7b5ef8a5d7c43f27906e3b044ef Mon Sep 17 00:00:00 2001 From: "E. Lynette Rayle" Date: Thu, 21 Sep 2017 21:00:41 -0400 Subject: [PATCH 2/2] Implement helper methods for getting collection ids based on user and access --- .../hyrax/collections/permissions_service.rb | 71 ++++++++++++++++++- .../collections/permissions_service_spec.rb | 52 ++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/app/services/hyrax/collections/permissions_service.rb b/app/services/hyrax/collections/permissions_service.rb index 40e73a25d5..b50db30b68 100644 --- a/app/services/hyrax/collections/permissions_service.rb +++ b/app/services/hyrax/collections/permissions_service.rb @@ -1,13 +1,82 @@ module Hyrax module Collections class PermissionsService + # @api private + # + # IDs of collections, including 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') + else + PermissionTemplateAccess.joins(:permission_template) + .where(agent_type: 'user', + agent_id: user.user_key, + access: access) + .or( + PermissionTemplateAccess.joins(:permission_template) + .where(agent_type: 'group', + agent_id: user.groups, + access: access) + ).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 + # + # @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]) + end + + # @api public + # + # IDs of collections, including admin sets, for which the user is assigned manage access + # + # @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]) + end + + # @api public + # + # IDs of collections, including admin sets, for which the user is assigned deposit access + # + # @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]) + end + + # @api public + # + # IDs of collections, including admin sets, into which the user can deposit + # + # @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]) + 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 - # @return [Boolean] true if the user has permission to depoisit into the collection + # @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) diff --git a/spec/services/hyrax/collections/permissions_service_spec.rb b/spec/services/hyrax/collections/permissions_service_spec.rb index 48498498e6..9b455783fe 100644 --- a/spec/services/hyrax/collections/permissions_service_spec.rb +++ b/spec/services/hyrax/collections/permissions_service_spec.rb @@ -126,4 +126,56 @@ expect(subject).to be false end end + + context "access helper method" do + 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) } + + 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 + + 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 + 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] + 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] + 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] + end + end + end + + def collection_access(permission_template, agent_type, agent_id, access) + create(:permission_template_access, + access, + permission_template: permission_template, + agent_type: agent_type, + agent_id: agent_id) + end end