Added general check for Group access based on agent.ticket permission.

This commit is contained in:
Thorsten Eckel 2017-06-20 17:13:42 +02:00
parent b1884c82f6
commit 18a9eed038
9 changed files with 391 additions and 259 deletions

View file

@ -7,8 +7,8 @@ module HasGroups
attr_accessor :group_access_buffer
after_create :check_group_access_buffer
after_update :check_group_access_buffer
after_create :check_group_access_buffer
after_update :check_group_access_buffer
association_attributes_ignored :groups
@ -62,6 +62,7 @@ module HasGroups
# @return [Boolean]
def group_access?(group_id, access)
return false if !active?
return false if !groups_access_permission?
group_id = self.class.ensure_group_id_parameter(group_id)
access = self.class.ensure_group_access_list_parameter(access)
@ -95,6 +96,7 @@ module HasGroups
# @return [Array<Integer>] Group IDs the instance has the given access(es) to.
def group_ids_access(access)
return [] if !active?
return [] if !groups_access_permission?
access = self.class.ensure_group_access_list_parameter(access)
foreign_key = group_through.foreign_key
@ -128,6 +130,7 @@ module HasGroups
# @return [Array<Group>] Groups the instance has the given access(es) to.
def groups_access(access)
return [] if !active?
return [] if !groups_access_permission?
group_ids = group_ids_access(access)
Group.where(id: group_ids)
end
@ -183,10 +186,24 @@ module HasGroups
@group_through ||= self.class.group_through
end
# Checks if the instance has general permission to Group access.
#
# @example
# customer_user.groups_access_permission?
# #=> false
#
# @return [Boolean]
def groups_access_permission?
return true if !respond_to?(:permissions?)
permissions?('ticket.agent')
end
private
def groups_access_map(key)
return {} if !active?
return {} if !groups_access_permission?
{}.tap do |hash|
groups.access.where(active: true).pluck(key, :access).each do |entry|
hash[ entry[0] ] ||= []
@ -262,20 +279,7 @@ module HasGroups
#
# @return [Array<Integer>]
def group_access_ids(group_id, access)
group_id = ensure_group_id_parameter(group_id)
access = ensure_group_access_list_parameter(access)
# check direct access
ids = group_through.klass.includes(name.downcase).where(group_id: group_id, access: access, table_name => { active: true }).pluck(group_through.foreign_key)
ids ||= []
# check indirect access through roles if possible
return ids if !respond_to?(:role_access_ids)
role_instance_ids = role_access_ids(group_id, access)
# combines and removes duplicates
# and returns them in one statement
ids | role_instance_ids
group_access(group_id, access).collect(&:id)
end
# Lists instances having the given access(es) to the given Group.
@ -294,8 +298,22 @@ module HasGroups
#
# @return [Array<Class>]
def group_access(group_id, access)
instance_ids = group_access_ids(group_id, access)
where(id: instance_ids)
group_id = ensure_group_id_parameter(group_id)
access = ensure_group_access_list_parameter(access)
# check direct access
ids = group_through.klass.includes(name.downcase).where(group_id: group_id, access: access, table_name => { active: true }).pluck(group_through.foreign_key)
ids ||= []
# get instances and check for required permission
instances = where(id: ids).select(&:groups_access_permission?)
# check indirect access through roles if possible
return instances if !respond_to?(:role_access)
# combines and removes duplicates
# and returns them in one statement
instances | role_access(group_id, access)
end
# The reflection instance containing the association data

View file

@ -18,6 +18,8 @@ module HasRoles
#
# @return [Boolean]
def role_access?(group_id, access)
return false if !groups_access_permission?
group_id = self.class.ensure_group_id_parameter(group_id)
access = self.class.ensure_group_access_list_parameter(access)
@ -37,6 +39,30 @@ module HasRoles
# methods defined here are going to extend the class, not the instance of it
class_methods do
# Lists instances having the given access(es) to the given Group through Roles.
#
# @example Group ID param
# User.role_access(1, 'read')
# #=> [1, 3, ...]
#
# @example Group param
# User.role_access(group, 'read')
# #=> [1, 3, ...]
#
# @example Access list
# User.role_access(group, ['read', 'create'])
# #=> [1, 3, ...]
#
# @return [Array<Integer>]
def role_access(group_id, access)
group_id = ensure_group_id_parameter(group_id)
access = ensure_group_access_list_parameter(access)
role_ids = RoleGroup.includes(:role).where(group_id: group_id, access: access, roles: { active: true }).pluck(:role_id)
join_table = reflect_on_association(:roles).join_table
joins(:roles).where(active: true, join_table => { role_id: role_ids }).distinct.select(&:groups_access_permission?)
end
# Lists IDs of instances having the given access(es) to the given Group through Roles.
#
# @example Group ID param
@ -53,12 +79,7 @@ module HasRoles
#
# @return [Array<Integer>]
def role_access_ids(group_id, access)
group_id = ensure_group_id_parameter(group_id)
access = ensure_group_access_list_parameter(access)
role_ids = RoleGroup.includes(:role).where(group_id: group_id, access: access, roles: { active: true }).pluck(:role_id)
join_table = reflect_on_association(:roles).join_table
includes(:roles).where(active: true, join_table => { role_id: role_ids }).distinct.pluck(:id)
role_access(group_id, access).collect(&:id)
end
def ensure_group_id_parameter(group_or_id)

View file

@ -768,7 +768,7 @@ perform changes on ticket
email = User.lookup(id: owner_id).email
recipients_raw.push(email)
elsif recipient == 'ticket_agents'
User.group_access(group_id, 'full').order(:login).each do |user|
User.group_access(group_id, 'full').sort_by(&:login).each do |user|
recipients_raw.push(user.email)
end
else

View file

@ -47,10 +47,11 @@ class Transaction::Notification
recipients_and_channels = []
# loop through all users
possible_recipients = User.group_access(ticket.group_id, 'full').order(:login)
possible_recipients = User.group_access(ticket.group_id, 'full').sort_by(&:login)
if ticket.owner_id == 1
possible_recipients.push ticket.owner
end
already_checked_recipient_ids = {}
possible_recipients.each { |user|
result = NotificationFactory::Mailer.notification_settings(user, ticket, @item[:type])

View file

@ -1,10 +1,12 @@
# Requires: let(:group_access_instance) { ... }
# Requires: let(:new_group_access_instance) { ... }
RSpec.shared_examples 'HasGroups' do
context 'group' do
let(:factory_name) { described_class.name.downcase.to_sym }
let(:instance) { create(factory_name) }
let(:instance_inactive) { create(factory_name, active: false) }
let(:group_access_instance_inactive) {
group_access_instance.update_attribute(:active, false)
group_access_instance
}
let(:group_full) { create(:group) }
let(:group_read) { create(:group) }
let(:group_inactive) { create(:group, active: false) }
@ -20,7 +22,7 @@ RSpec.shared_examples 'HasGroups' do
end
it 'instance responds to group_through_identifier method' do
expect(instance).to respond_to(described_class.group_through_identifier)
expect(group_access_instance).to respond_to(described_class.group_through_identifier)
end
end
@ -38,19 +40,19 @@ RSpec.shared_examples 'HasGroups' do
context '#groups' do
it 'responds to groups' do
expect(instance).to respond_to(:groups)
expect(group_access_instance).to respond_to(:groups)
end
context '#groups.access' do
it 'responds to groups.access' do
expect(instance.groups).to respond_to(:access)
expect(group_access_instance.groups).to respond_to(:access)
end
context 'result' do
before(:each) do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => 'read',
group_inactive.name => 'write',
@ -58,23 +60,23 @@ RSpec.shared_examples 'HasGroups' do
end
it 'returns all related Groups' do
expect(instance.groups.access.size).to eq(3)
expect(group_access_instance.groups.access.size).to eq(3)
end
it 'adds join table attribute(s like) access' do
expect(instance.groups.access.first).to respond_to(:access)
expect(group_access_instance.groups.access.first).to respond_to(:access)
end
it 'filters for given access parameter' do
expect(instance.groups.access('read')).to include(group_read)
expect(group_access_instance.groups.access('read')).to include(group_read)
end
it 'filters for given access list parameter' do
expect(instance.groups.access('read', 'write')).to include(group_read, group_inactive)
expect(group_access_instance.groups.access('read', 'write')).to include(group_read, group_inactive)
end
it 'always includes full access groups' do
expect(instance.groups.access('read')).to include(group_full)
expect(group_access_instance.groups.access('read')).to include(group_full)
end
end
end
@ -82,14 +84,14 @@ RSpec.shared_examples 'HasGroups' do
context '#group_access?' do
before(:each) do
instance.group_names_access_map = {
group_read.name => 'read',
}
it 'responds to group_access?' do
expect(group_access_instance).to respond_to(:group_access?)
end
it 'responds to group_access?' do
expect(instance).to respond_to(:group_access?)
before(:each) do
group_access_instance.group_names_access_map = {
group_read.name => 'read',
}
end
context 'Group ID parameter' do
@ -105,61 +107,61 @@ RSpec.shared_examples 'HasGroups' do
end
it 'prevents inactive Group' do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_inactive.name => 'read',
}
expect(instance.group_access?(group_inactive.id, 'read')).to be false
expect(group_access_instance.group_access?(group_inactive.id, 'read')).to be false
end
it 'prevents inactive instances' do
instance_inactive.group_names_access_map = {
group_access_instance_inactive.group_names_access_map = {
group_read.name => 'read',
}
expect(instance_inactive.group_access?(group_read.id, 'read')).to be false
expect(group_access_instance_inactive.group_access?(group_read.id, 'read')).to be false
end
end
context '#group_ids_access' do
it 'responds to group_ids_access' do
expect(group_access_instance).to respond_to(:group_ids_access)
end
before(:each) do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_read.name => 'read',
}
end
it 'responds to group_ids_access' do
expect(instance).to respond_to(:group_ids_access)
end
it 'lists only active Group IDs' do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_read.name => 'read',
group_inactive.name => 'read',
}
result = instance.group_ids_access('read')
result = group_access_instance.group_ids_access('read')
expect(result).not_to include(group_inactive.id)
end
it "doesn't list for inactive instances" do
instance_inactive.group_names_access_map = {
group_access_instance_inactive.group_names_access_map = {
group_read.name => 'read',
}
expect(instance_inactive.group_ids_access('read')).to be_empty
expect(group_access_instance_inactive.group_ids_access('read')).to be_empty
end
context 'single access' do
it 'lists access Group IDs' do
result = instance.group_ids_access('read')
result = group_access_instance.group_ids_access('read')
expect(result).to include(group_read.id)
end
it "doesn't list for no access" do
result = instance.group_ids_access('write')
result = group_access_instance.group_ids_access('write')
expect(result).not_to include(group_read.id)
end
end
@ -167,12 +169,12 @@ RSpec.shared_examples 'HasGroups' do
context 'access list' do
it 'lists access Group IDs' do
result = instance.group_ids_access(%w(read write))
result = group_access_instance.group_ids_access(%w(read write))
expect(result).to include(group_read.id)
end
it "doesn't list for no access" do
result = instance.group_ids_access(%w(write create))
result = group_access_instance.group_ids_access(%w(write create))
expect(result).not_to include(group_read.id)
end
end
@ -181,19 +183,19 @@ RSpec.shared_examples 'HasGroups' do
context '#groups_access' do
it 'responds to groups_access' do
expect(instance).to respond_to(:groups_access)
expect(group_access_instance).to respond_to(:groups_access)
end
it 'wraps #group_ids_access' do
expect(instance).to receive(:group_ids_access)
instance.groups_access('read')
expect(group_access_instance).to receive(:group_ids_access)
group_access_instance.groups_access('read')
end
it 'returns Groups' do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_read.name => 'read',
}
result = instance.groups_access('read')
result = group_access_instance.groups_access('read')
expect(result).to include(group_read)
end
end
@ -201,14 +203,14 @@ RSpec.shared_examples 'HasGroups' do
context '#group_names_access_map=' do
it 'responds to group_names_access_map=' do
expect(instance).to respond_to(:group_names_access_map=)
expect(group_access_instance).to respond_to(:group_names_access_map=)
end
context 'Group name => access relation storage' do
context 'existing instance' do
it 'stores Hash with String values' do
expect do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => 'read',
}
@ -217,9 +219,9 @@ RSpec.shared_examples 'HasGroups' do
}.by(2)
end
it 'stores Hash with String values' do
it 'stores Hash with Array<String> values' do
expect do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => %w(read write),
}
@ -227,33 +229,32 @@ RSpec.shared_examples 'HasGroups' do
described_class.group_through.klass.count
}.by(3)
end
end
context 'new instance' do
let(:new_instance) { build(factory_name) }
context 'new instance' do
it "doesn't store directly" do
expect do
new_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => 'read',
}
end.not_to change {
described_class.group_through.klass.count
it "doesn't store directly" do
expect do
new_group_access_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => 'read',
}
end
end.not_to change {
described_class.group_through.klass.count
}
end
it 'stores after save' do
expect do
new_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => 'read',
}
it 'stores after save' do
expect do
new_group_access_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => 'read',
}
new_instance.save
end.to change {
described_class.group_through.klass.count
}.by(2)
end
new_group_access_instance.save
end.to change {
described_class.group_through.klass.count
}.by(2)
end
end
end
@ -261,7 +262,7 @@ RSpec.shared_examples 'HasGroups' do
context '#group_names_access_map' do
it 'responds to group_names_access_map' do
expect(instance).to respond_to(:group_names_access_map)
expect(group_access_instance).to respond_to(:group_names_access_map)
end
it 'returns instance Group name => access relations as Hash' do
@ -270,32 +271,32 @@ RSpec.shared_examples 'HasGroups' do
group_read.name => ['read'],
}
instance.group_names_access_map = expected
group_access_instance.group_names_access_map = expected
expect(instance.group_names_access_map).to eq(expected)
expect(group_access_instance.group_names_access_map).to eq(expected)
end
it "doesn't map for inactive instances" do
instance_inactive.group_names_access_map = {
group_access_instance_inactive.group_names_access_map = {
group_full.name => ['full'],
group_read.name => ['read'],
}
expect(instance_inactive.group_names_access_map).to be_empty
expect(group_access_instance_inactive.group_names_access_map).to be_empty
end
end
context '#group_ids_access_map=' do
it 'responds to group_ids_access_map=' do
expect(instance).to respond_to(:group_ids_access_map=)
expect(group_access_instance).to respond_to(:group_ids_access_map=)
end
context 'Group ID => access relation storage' do
context 'existing instance' do
it 'stores Hash with String values' do
expect do
instance.group_ids_access_map = {
group_access_instance.group_ids_access_map = {
group_full.id => 'full',
group_read.id => 'read',
}
@ -306,7 +307,7 @@ RSpec.shared_examples 'HasGroups' do
it 'stores Hash with String values' do
expect do
instance.group_ids_access_map = {
group_access_instance.group_ids_access_map = {
group_full.id => 'full',
group_read.id => %w(read write),
}
@ -314,33 +315,32 @@ RSpec.shared_examples 'HasGroups' do
described_class.group_through.klass.count
}.by(3)
end
end
context 'new instance' do
let(:new_instance) { build(factory_name) }
context 'new instance' do
it "doesn't store directly" do
expect do
new_instance.group_ids_access_map = {
group_full.id => 'full',
group_read.id => 'read',
}
end.not_to change {
described_class.group_through.klass.count
it "doesn't store directly" do
expect do
new_group_access_instance.group_ids_access_map = {
group_full.id => 'full',
group_read.id => 'read',
}
end
end.not_to change {
described_class.group_through.klass.count
}
end
it 'stores after save' do
expect do
new_instance.group_ids_access_map = {
group_full.id => 'full',
group_read.id => 'read',
}
it 'stores after save' do
expect do
new_group_access_instance.group_ids_access_map = {
group_full.id => 'full',
group_read.id => 'read',
}
new_instance.save
end.to change {
described_class.group_through.klass.count
}.by(2)
end
new_group_access_instance.save
end.to change {
described_class.group_through.klass.count
}.by(2)
end
end
end
@ -348,7 +348,7 @@ RSpec.shared_examples 'HasGroups' do
context '#group_ids_access_map' do
it 'responds to group_ids_access_map' do
expect(instance).to respond_to(:group_ids_access_map)
expect(group_access_instance).to respond_to(:group_ids_access_map)
end
it 'returns instance Group ID => access relations as Hash' do
@ -357,18 +357,18 @@ RSpec.shared_examples 'HasGroups' do
group_read.id => ['read'],
}
instance.group_ids_access_map = expected
group_access_instance.group_ids_access_map = expected
expect(instance.group_ids_access_map).to eq(expected)
expect(group_access_instance.group_ids_access_map).to eq(expected)
end
it "doesn't map for inactive instances" do
instance_inactive.group_ids_access_map = {
group_access_instance_inactive.group_ids_access_map = {
group_full.id => ['full'],
group_read.id => ['read'],
}
expect(instance_inactive.group_ids_access_map).to be_empty
expect(group_access_instance_inactive.group_ids_access_map).to be_empty
end
end
@ -380,8 +380,8 @@ RSpec.shared_examples 'HasGroups' do
group_read.id => ['read'],
}
instance.associations_from_param(group_ids: expected)
expect(instance.group_ids_access_map).to eq(expected)
group_access_instance.associations_from_param(group_ids: expected)
expect(group_access_instance.group_ids_access_map).to eq(expected)
end
it 'handles groups parameter as group_names_access_map' do
@ -390,8 +390,8 @@ RSpec.shared_examples 'HasGroups' do
group_read.name => ['read'],
}
instance.associations_from_param(groups: expected)
expect(instance.group_names_access_map).to eq(expected)
group_access_instance.associations_from_param(groups: expected)
expect(group_access_instance.group_names_access_map).to eq(expected)
end
end
@ -403,9 +403,9 @@ RSpec.shared_examples 'HasGroups' do
group_read.id => ['read'],
}
instance.group_ids_access_map = expected
group_access_instance.group_ids_access_map = expected
result = instance.attributes_with_association_ids
result = group_access_instance.attributes_with_association_ids
expect(result['group_ids']).to eq(expected)
end
end
@ -418,9 +418,9 @@ RSpec.shared_examples 'HasGroups' do
group_read.id => ['read'],
}
instance.group_ids_access_map = expected
group_access_instance.group_ids_access_map = expected
result = instance.attributes_with_association_names
result = group_access_instance.attributes_with_association_names
expect(result['group_ids']).to eq(expected)
end
@ -430,77 +430,77 @@ RSpec.shared_examples 'HasGroups' do
group_read.name => ['read'],
}
instance.group_names_access_map = expected
group_access_instance.group_names_access_map = expected
result = instance.attributes_with_association_names
result = group_access_instance.attributes_with_association_names
expect(result['groups']).to eq(expected)
end
end
context '.group_access_ids' do
before(:each) do
instance.group_names_access_map = {
group_read.name => 'read',
}
end
it 'responds to group_access_ids' do
expect(described_class).to respond_to(:group_access_ids)
end
it 'lists only active instance IDs' do
instance_inactive.group_names_access_map = {
group_read.name => 'read',
}
result = described_class.group_access_ids(group_read.id, 'read')
expect(result).not_to include(instance_inactive.id)
end
context 'Group ID parameter' do
include_examples '.group_access_ids call' do
let(:group_parameter) { group_read.id }
end
end
context 'Group parameter' do
include_examples '.group_access_ids call' do
let(:group_parameter) { group_read.id }
end
end
end
context '.group_access' do
it 'responds to group_access' do
expect(described_class).to respond_to(:group_access)
end
it 'wraps .group_access_ids' do
expect(described_class).to receive(:group_access_ids)
described_class.group_access(group_read, 'read')
before(:each) do
group_access_instance.group_names_access_map = {
group_read.name => 'read',
}
end
it 'returns class instances' do
instance.group_names_access_map = {
it 'lists only active instances' do
group_access_instance_inactive.group_names_access_map = {
group_read.name => 'read',
}
result = described_class.group_access(group_read, 'read')
expect(result).to include(instance)
result = described_class.group_access(group_read.id, 'read')
expect(result).not_to include(group_access_instance_inactive)
end
context 'Group ID parameter' do
include_examples '.group_access call' do
let(:group_parameter) { group_read.id }
end
end
context 'Group parameter' do
include_examples '.group_access call' do
let(:group_parameter) { group_read }
end
end
end
context '.group_access_ids' do
it 'responds to group_access_ids' do
expect(described_class).to respond_to(:group_access_ids)
end
it 'wraps .group_access' do
expect(described_class).to receive(:group_access).and_call_original
described_class.group_access_ids(group_read, 'read')
end
it 'returns class instances' do
group_access_instance.group_names_access_map = {
group_read.name => 'read',
}
result = described_class.group_access_ids(group_read, 'read')
expect(result).to include(group_access_instance.id)
end
end
it 'destroys relations before instance gets destroyed' do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_full.name => 'full',
group_read.name => 'read',
group_inactive.name => 'write',
}
expect do
instance.destroy
group_access_instance.destroy
end.to change {
described_class.group_through.klass.count
}.by(-3)
@ -512,46 +512,46 @@ RSpec.shared_examples '#group_access? call' do
context 'single access' do
it 'checks positive' do
expect(instance.group_access?(group_parameter, 'read')).to be true
expect(group_access_instance.group_access?(group_parameter, 'read')).to be true
end
it 'checks negative' do
expect(instance.group_access?(group_parameter, 'write')).to be false
expect(group_access_instance.group_access?(group_parameter, 'write')).to be false
end
end
context 'access list' do
it 'checks positive' do
expect(instance.group_access?(group_parameter, %w(read write))).to be true
expect(group_access_instance.group_access?(group_parameter, %w(read write))).to be true
end
it 'checks negative' do
expect(instance.group_access?(group_parameter, %w(write create))).to be false
expect(group_access_instance.group_access?(group_parameter, %w(write create))).to be false
end
end
end
RSpec.shared_examples '.group_access_ids call' do
RSpec.shared_examples '.group_access call' do
context 'single access' do
it 'lists access IDs' do
expect(described_class.group_access_ids(group_parameter, 'read')).to include(instance.id)
expect(described_class.group_access(group_parameter, 'read')).to include(group_access_instance)
end
it 'excludes non access IDs' do
expect(described_class.group_access_ids(group_parameter, 'write')).not_to include(instance.id)
expect(described_class.group_access(group_parameter, 'write')).not_to include(group_access_instance)
end
end
context 'access list' do
it 'lists access IDs' do
expect(described_class.group_access_ids(group_parameter, %w(read write))).to include(instance.id)
expect(described_class.group_access(group_parameter, %w(read write))).to include(group_access_instance)
end
it 'excludes non access IDs' do
expect(described_class.group_access_ids(group_parameter, %w(write create))).not_to include(instance.id)
expect(described_class.group_access(group_parameter, %w(write create))).not_to include(group_access_instance)
end
end
end

View file

@ -0,0 +1,79 @@
# Requires: let(:group_access_no_permission_instance) { ... }
RSpec.shared_examples 'HasGroups and Permissions' do
context 'group' do
let(:group_read) { create(:group) }
before(:each) do
group_access_no_permission_instance.group_names_access_map = {
group_read.name => 'read',
}
end
context '#group_access?' do
it 'prevents instances without permissions' do
expect(group_access_no_permission_instance.group_access?(group_read, 'read')).to be false
end
end
context '#group_ids_access' do
it 'prevents instances without permissions' do
expect(group_access_no_permission_instance.group_ids_access('read')).to be_empty
end
end
context '#groups_access' do
it 'prevents instances without permissions' do
expect(group_access_no_permission_instance.groups_access('read')).to be_empty
end
end
context '#group_names_access_map' do
it 'prevents instances without permissions' do
expect(group_access_no_permission_instance.group_names_access_map).to be_empty
end
end
context '#group_ids_access_map' do
it 'prevents instances without permissions' do
expect(group_access_no_permission_instance.group_ids_access_map).to be_empty
end
end
context '#attributes_with_association_ids' do
it 'prevents instances without permissions' do
expect(group_access_no_permission_instance.attributes_with_association_ids['group_ids']).to be_empty
end
end
context '#attributes_with_association_names' do
it 'prevents instances without permissions' do
expect(group_access_no_permission_instance.attributes_with_association_names['group_ids']).to be_empty
end
end
context '.group_access' do
it 'prevents instances without permissions' do
result = described_class.group_access(group_read.id, 'read')
expect(result).not_to include(group_access_no_permission_instance)
end
end
context '.group_access_ids' do
it 'prevents instances without permissions' do
result = described_class.group_access(group_read.id, 'read')
expect(result).not_to include(group_access_no_permission_instance.id)
end
end
end
end

View file

@ -1,10 +1,13 @@
# Requires: let(:group_access_instance) { ... }
# Requires: let(:new_group_access_instance) { ... }
RSpec.shared_examples 'HasRoles' do
context 'role' do
let(:factory_name) { described_class.name.downcase.to_sym }
let(:instance) { create(factory_name) }
let(:instance_inactive) { create(factory_name, active: false) }
let(:group_access_instance_inactive) {
group_access_instance.update_attribute(:active, false)
group_access_instance
}
let(:role) { create(:role) }
let(:group_instance) { create(:group) }
let(:group_role) { create(:group) }
@ -12,36 +15,39 @@ RSpec.shared_examples 'HasRoles' do
context '#role_access?' do
before(:each) do
role.group_names_access_map = {
group_role.name => 'read',
}
instance.roles = [role]
end
it 'responds to role_access?' do
expect(instance).to respond_to(:role_access?)
expect(group_access_instance).to respond_to(:role_access?)
end
context 'Group ID parameter' do
include_examples '#role_access? call' do
let(:group_parameter) { group_role.id }
context 'active Role' do
before(:each) do
role.group_names_access_map = {
group_role.name => 'read',
}
group_access_instance.roles.push(role)
group_access_instance.save
end
end
context 'Group parameter' do
include_examples '#role_access? call' do
let(:group_parameter) { group_role }
context 'Group ID parameter' do
include_examples '#role_access? call' do
let(:group_parameter) { group_role.id }
end
end
end
it 'prevents inactive Group' do
role.group_names_access_map = {
group_inactive.name => 'read',
}
context 'Group parameter' do
include_examples '#role_access? call' do
let(:group_parameter) { group_role }
end
end
expect(instance.group_access?(group_inactive.id, 'read')).to be false
it 'prevents inactive Group' do
role.group_names_access_map = {
group_inactive.name => 'read',
}
expect(group_access_instance.group_access?(group_inactive.id, 'read')).to be false
end
end
it 'prevents inactive Role' do
@ -50,9 +56,10 @@ RSpec.shared_examples 'HasRoles' do
group_role.name => 'read',
}
instance.roles = [role_inactive]
group_access_instance.roles.push(role_inactive)
group_access_instance.save
expect(instance.group_access?(group_role.id, 'read')).to be false
expect(group_access_instance.group_access?(group_role.id, 'read')).to be false
end
end
@ -63,7 +70,8 @@ RSpec.shared_examples 'HasRoles' do
group_role.name => 'read',
}
instance.roles = [role]
group_access_instance.roles.push(role)
group_access_instance.save
end
it 'responds to role_access_ids' do
@ -75,19 +83,12 @@ RSpec.shared_examples 'HasRoles' do
group_role.name => 'read',
}
result = described_class.group_access_ids(group_role.id, 'read')
expect(result).not_to include(instance_inactive.id)
end
it 'lists only active instance IDs' do
role.group_names_access_map = {
group_role.name => 'read',
}
instance_inactive.roles = [role]
group_access_instance_inactive.roles.push(role)
group_access_instance_inactive.save
group_access_instance_inactive.save
result = described_class.role_access_ids(group_role.id, 'read')
expect(result).not_to include(instance_inactive.id)
expect(result).not_to include(group_access_instance_inactive.id)
end
context 'Group ID parameter' do
@ -98,7 +99,7 @@ RSpec.shared_examples 'HasRoles' do
context 'Group parameter' do
include_examples '.role_access_ids call' do
let(:group_parameter) { group_role.id }
let(:group_parameter) { group_role }
end
end
end
@ -110,9 +111,10 @@ RSpec.shared_examples 'HasRoles' do
group_role.name => 'read',
}
instance.roles = [role]
group_access_instance.roles.push(role)
group_access_instance.save
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_instance.name => 'read',
}
end
@ -120,13 +122,13 @@ RSpec.shared_examples 'HasRoles' do
context '#group_access?' do
it 'falls back to #role_access?' do
expect(instance).to receive(:role_access?)
instance.group_access?(group_role, 'read')
expect(group_access_instance).to receive(:role_access?)
group_access_instance.group_access?(group_role, 'read')
end
it "doesn't fall back to #role_access? if not needed" do
expect(instance).not_to receive(:role_access?)
instance.group_access?(group_instance, 'read')
expect(group_access_instance).not_to receive(:role_access?)
group_access_instance.group_access?(group_instance, 'read')
end
end
@ -137,9 +139,10 @@ RSpec.shared_examples 'HasRoles' do
group_role.name => 'read',
}
instance.roles = [role]
group_access_instance.roles.push(role)
group_access_instance.save
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_instance.name => 'read',
}
end
@ -150,28 +153,28 @@ RSpec.shared_examples 'HasRoles' do
group_inactive.name => 'read',
}
result = instance.group_ids_access('read')
result = group_access_instance.group_ids_access('read')
expect(result).not_to include(group_inactive.id)
end
context 'single access' do
it 'lists access Group IDs' do
result = instance.group_ids_access('read')
result = group_access_instance.group_ids_access('read')
expect(result).to include(group_role.id)
end
it "doesn't list for no access" do
result = instance.group_ids_access('write')
result = group_access_instance.group_ids_access('write')
expect(result).not_to include(group_role.id)
end
it "doesn't contain duplicate IDs" do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_role.name => 'read',
}
result = instance.group_ids_access('read')
result = group_access_instance.group_ids_access('read')
expect(result.uniq).to eq(result)
end
end
@ -179,21 +182,21 @@ RSpec.shared_examples 'HasRoles' do
context 'access list' do
it 'lists access Group IDs' do
result = instance.group_ids_access(%w(read write))
result = group_access_instance.group_ids_access(%w(read write))
expect(result).to include(group_role.id)
end
it "doesn't list for no access" do
result = instance.group_ids_access(%w(write create))
result = group_access_instance.group_ids_access(%w(write create))
expect(result).not_to include(group_role.id)
end
it "doesn't contain duplicate IDs" do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_role.name => 'read',
}
result = instance.group_ids_access(%w(read create))
result = group_access_instance.group_ids_access(%w(read create))
expect(result.uniq).to eq(result)
end
end
@ -203,11 +206,11 @@ RSpec.shared_examples 'HasRoles' do
it 'includes the result of .role_access_ids' do
result = described_class.group_access_ids(group_role, 'read')
expect(result).to include(instance.id)
expect(result).to include(group_access_instance.id)
end
it "doesn't contain duplicate IDs" do
instance.group_names_access_map = {
group_access_instance.group_names_access_map = {
group_role.name => 'read',
}
@ -223,22 +226,22 @@ RSpec.shared_examples '#role_access? call' do
context 'single access' do
it 'checks positive' do
expect(instance.role_access?(group_parameter, 'read')).to be true
expect(group_access_instance.role_access?(group_parameter, 'read')).to be true
end
it 'checks negative' do
expect(instance.role_access?(group_parameter, 'write')).to be false
expect(group_access_instance.role_access?(group_parameter, 'write')).to be false
end
end
context 'access list' do
it 'checks positive' do
expect(instance.role_access?(group_parameter, %w(read write))).to be true
expect(group_access_instance.role_access?(group_parameter, %w(read write))).to be true
end
it 'checks negative' do
expect(instance.role_access?(group_parameter, %w(write create))).to be false
expect(group_access_instance.role_access?(group_parameter, %w(write create))).to be false
end
end
end
@ -247,22 +250,22 @@ RSpec.shared_examples '.role_access_ids call' do
context 'single access' do
it 'lists access IDs' do
expect(described_class.role_access_ids(group_parameter, 'read')).to include(instance.id)
expect(described_class.role_access_ids(group_parameter, 'read')).to include(group_access_instance.id)
end
it 'excludes non access IDs' do
expect(described_class.role_access_ids(group_parameter, 'write')).not_to include(instance.id)
expect(described_class.role_access_ids(group_parameter, 'write')).not_to include(group_access_instance.id)
end
end
context 'access list' do
it 'lists access IDs' do
expect(described_class.role_access_ids(group_parameter, %w(read write))).to include(instance.id)
expect(described_class.role_access_ids(group_parameter, %w(read write))).to include(group_access_instance.id)
end
it 'excludes non access IDs' do
expect(described_class.role_access_ids(group_parameter, %w(write create))).not_to include(instance.id)
expect(described_class.role_access_ids(group_parameter, %w(write create))).not_to include(group_access_instance.id)
end
end
end

View file

@ -2,5 +2,8 @@ require 'rails_helper'
require 'models/concerns/has_groups_examples'
RSpec.describe Role do
let(:group_access_instance) { create(:role) }
let(:new_group_access_instance) { build(:role) }
include_examples 'HasGroups'
end

View file

@ -1,10 +1,17 @@
require 'rails_helper'
require 'models/concerns/has_groups_examples'
require 'models/concerns/has_roles_examples'
require 'models/concerns/has_groups_permissions_examples'
RSpec.describe User do
let(:group_access_instance) { create(:user, roles: [Role.find_by(name: 'Agent')]) }
let(:new_group_access_instance) { build(:user, roles: [Role.find_by(name: 'Agent')]) }
let(:group_access_no_permission_instance) { build(:user) }
include_examples 'HasGroups'
include_examples 'HasRoles'
include_examples 'HasGroups and Permissions'
let(:new_password) { 'N3W54V3PW!' }