permissify 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -3
- data/lib/generators/permissify/role/template/role.rb +5 -0
- data/lib/generators/permissify/role/template/roles.rb +1 -1
- data/lib/permissify/ability_class.rb +5 -0
- data/lib/permissify/aggregate.rb +75 -58
- data/lib/permissify/controller.rb +16 -7
- data/lib/permissify/model.rb +10 -4
- data/lib/permissify/model_class.rb +8 -12
- data/lib/permissify/roles.rb +36 -18
- data/spec/permissify/aggregate_spec.rb +83 -0
- data/spec/permissify/controller_spec.rb +74 -0
- data/spec/permissify/model_class_spec.rb +68 -0
- data/spec/permissify/model_spec.rb +102 -0
- data/spec/permissify/roles_spec.rb +29 -0
- data/spec/spec_helper.rb +29 -6
- metadata +9 -4
data/Gemfile
CHANGED
@@ -43,12 +43,10 @@
|
|
43
43
|
source :rubygems
|
44
44
|
|
45
45
|
# gem "sqlite3"
|
46
|
-
# TODO : any activerecord version dependency?
|
47
46
|
# gem "activerecord", '~> 3.0.9', :require => "active_record"
|
48
|
-
# gem "activerecord", :require => "active_record"
|
49
47
|
# gem "with_model", "~> 0.2.5"
|
50
48
|
# gem "meta_where"
|
51
49
|
|
52
50
|
gemspec
|
53
51
|
|
54
|
-
gem 'rspec'
|
52
|
+
gem 'rspec'
|
@@ -16,6 +16,11 @@ class Role < ActiveRecord::Base
|
|
16
16
|
class << self
|
17
17
|
include Permissify::ModelClass
|
18
18
|
include SystemFixtures::Roles
|
19
|
+
|
20
|
+
def force_seed_id(table, permissions_model, id)
|
21
|
+
# not sure if this is still needed, may differ depending on db adapter (written against mysql)
|
22
|
+
ActiveRecord::Base.connection.execute "UPDATE #{table}s SET id=#{id} WHERE id=#{permissions_model.id};"
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
def initialize_non_permission_values
|
@@ -5,7 +5,7 @@ module SystemFixtures::Roles
|
|
5
5
|
|
6
6
|
def seeded?(role); role.id <= SEEDED_ORDERED_ROLES.length; end
|
7
7
|
def seed
|
8
|
-
create_seeds
|
8
|
+
create_seeds SEED_SPECIFICATIONS
|
9
9
|
Role.find(1).manage_ids = [2,3,4,5,6]
|
10
10
|
Role.find(2).manage_ids = [2,3,4,5,6]
|
11
11
|
Role.find(3).manage_ids = [3,4,5,6]
|
@@ -46,6 +46,11 @@ module Permissify
|
|
46
46
|
@@permissions.keys.each{ |key| @@permissions.delete(key) if key.start_with?(key_prefix) }
|
47
47
|
@@permissions
|
48
48
|
end
|
49
|
+
|
50
|
+
def remove_permissions(key_prefixes)
|
51
|
+
key_prefixes.each{ |key_prefix| remove_permission(key_prefix) }
|
52
|
+
@@permissions
|
53
|
+
end
|
49
54
|
|
50
55
|
def current_permissions_hash
|
51
56
|
@@permissions
|
data/lib/permissify/aggregate.rb
CHANGED
@@ -2,13 +2,34 @@ module Permissify
|
|
2
2
|
module Aggregate
|
3
3
|
attr_accessor :abilities
|
4
4
|
|
5
|
-
def permissions_union
|
5
|
+
def permissions_union
|
6
6
|
@union ||= construct_union
|
7
|
+
@working_permissions = @union
|
7
8
|
end
|
8
9
|
|
10
|
+
def permissions_intersection(product_permissions)
|
11
|
+
@intersection ||= construct_intersection
|
12
|
+
@working_permissions = @intersection
|
13
|
+
end
|
14
|
+
|
15
|
+
def allowed_to?(action, feature)
|
16
|
+
@working_permissions ||= permissions_union
|
17
|
+
(@working_permissions["#{feature}_#{action}"]['0'] == true rescue false)
|
18
|
+
end
|
19
|
+
|
20
|
+
def viewable?(feature); allowed_to?(:view, feature); end
|
21
|
+
def createable?(feature); allowed_to?(:create, feature); end
|
22
|
+
def updateable?(feature); allowed_to?(:update, feature); end
|
23
|
+
def deleteable?(feature); allowed_to?(:delete, feature); end
|
24
|
+
def subscribed_to?(feature); allowed_to?(:on, feature); end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
9
28
|
def construct_union
|
10
29
|
union = {}
|
11
|
-
self.send(self.class::PERMISSIFIED_ASSOCIATION)
|
30
|
+
permissified_models = self.send(self.class::PERMISSIFIED_ASSOCIATION)
|
31
|
+
permissions_hashes = permissified_models.collect(&:permissions)
|
32
|
+
permissions_hashes.each do |permissions_hash|
|
12
33
|
permissions_hash.each do |key, descriptor|
|
13
34
|
descriptor ||= {'0' => false}
|
14
35
|
if union[key].nil?
|
@@ -16,70 +37,66 @@ module Permissify
|
|
16
37
|
else
|
17
38
|
arbitrate(union, descriptor, key, :max)
|
18
39
|
end
|
19
|
-
union[key]['0'] = (union[key]['0'] ==
|
40
|
+
union[key]['0'] = (union[key]['0'] == true || descriptor['0'] == '1')
|
20
41
|
end
|
21
42
|
end
|
22
43
|
union
|
23
44
|
end
|
24
|
-
|
25
|
-
def permissions_intersection(product_permissions)
|
26
|
-
return @intersection if @intersection
|
27
|
-
@intersection = {}
|
28
|
-
permissions_union
|
29
|
-
|
30
|
-
# TODO : Product/Role references should be plugged-in...
|
31
|
-
# - could aggregate keep track of class names that it is included in?
|
32
|
-
# - there is a lot tangled up in here...
|
33
|
-
Ability.all_for(%w(Product Role)).each do |ability|
|
34
|
-
key = ability[:key]
|
35
|
-
descriptor = @union[key]
|
36
|
-
product_descriptor = product_permissions[key]
|
37
|
-
if permissable?(descriptor) && permissable?(product_descriptor)
|
38
|
-
@intersection[key] = descriptor
|
39
|
-
arbitrate(@intersection, product_descriptor, key, :min)
|
40
|
-
else
|
41
|
-
@intersection[key] = null_permission
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
include_permissions_unless_common_to_role_and_product('Product', product_permissions)
|
46
|
-
include_permissions_unless_common_to_role_and_product('Role', @union)
|
47
|
-
@intersection
|
48
|
-
end
|
49
|
-
|
50
|
-
def permissable?(descriptor); descriptor && (descriptor['0'] == true || descriptor['0'] == '1'); end
|
51
|
-
def subscribed_to?(feature); allowed_to?('on', feature); end
|
52
|
-
def allowed_to?(action, feature); (permissions_union["#{feature}_#{action}"]['0'] == true rescue false); end
|
53
|
-
|
54
|
-
def include_permissions_unless_common_to_role_and_product(applicability_type, applicable_permissions)
|
55
|
-
Ability.all_for(applicability_type).each do |ability|
|
56
|
-
key = ability[:key]
|
57
|
-
descriptor = applicable_permissions[key]
|
58
|
-
unless @intersection.has_key?(key)
|
59
|
-
if permissable?(descriptor)
|
60
|
-
descriptor['0'] = true
|
61
|
-
@intersection[key] = descriptor
|
62
|
-
arbitrate(@intersection, descriptor, key, :min)
|
63
|
-
else
|
64
|
-
@intersection[key] = null_permission
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
45
|
+
|
71
46
|
def arbitrate(aggregation, other_descriptor, key, min_or_max) # assuming all permission 'args' are integers stored as strings
|
72
47
|
1.upto(other_descriptor.size-1) do |i|
|
73
|
-
is = i.to_s
|
48
|
+
is = i.to_s
|
49
|
+
aggregation[key][is] = [aggregation[key][is].to_i, other_descriptor[is].to_i].send(min_or_max) # .to_s ?
|
74
50
|
end
|
75
51
|
end
|
76
|
-
|
77
|
-
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
52
|
+
|
53
|
+
# TODO : flush out intersection stuff in corp/brand/business products phase
|
54
|
+
# def construct_intersection
|
55
|
+
# intersection = {}
|
56
|
+
# permissions_union
|
57
|
+
#
|
58
|
+
# # TODO : Product/Role references should be plugged-in...
|
59
|
+
# # - could aggregate keep track of class names that it is included in?
|
60
|
+
# # - there is a lot tangled up in here...
|
61
|
+
# Ability.all_for(%w(Product Role)).each do |ability|
|
62
|
+
# key = ability[:key]
|
63
|
+
# descriptor = @union[key]
|
64
|
+
# product_descriptor = product_permissions[key]
|
65
|
+
# if permissable?(descriptor) && permissable?(product_descriptor)
|
66
|
+
# intersection[key] = descriptor
|
67
|
+
# arbitrate(intersection, product_descriptor, key, :min)
|
68
|
+
# else
|
69
|
+
# intersection[key] = null_permission
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# include_permissions_unless_common_to_role_and_product('Product', product_permissions)
|
74
|
+
# include_permissions_unless_common_to_role_and_product('Role', @union)
|
75
|
+
# intersection
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# def permissable?(descriptor)
|
79
|
+
# descriptor && (descriptor['0'] == true || descriptor['0'] == '1')
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# def include_permissions_unless_common_to_role_and_product(applicability_type, applicable_permissions)
|
83
|
+
# Ability.all_for(applicability_type).each do |ability|
|
84
|
+
# key = ability[:key]
|
85
|
+
# descriptor = applicable_permissions[key]
|
86
|
+
# unless @intersection.has_key?(key)
|
87
|
+
# if permissable?(descriptor)
|
88
|
+
# descriptor['0'] = true
|
89
|
+
# @intersection[key] = descriptor
|
90
|
+
# arbitrate(@intersection, descriptor, key, :min)
|
91
|
+
# else
|
92
|
+
# @intersection[key] = null_permission
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# def null_permission
|
99
|
+
# {'0' => false, '1' => 0}
|
83
100
|
# end
|
84
101
|
end
|
85
102
|
end
|
@@ -1,15 +1,24 @@
|
|
1
1
|
module Permissify
|
2
2
|
module Controller
|
3
|
-
|
3
|
+
|
4
|
+
def allowed_to?(action, permission_category)
|
5
|
+
(domain_permissions["#{permission_category}_#{action}"]['0'] == true rescue false)
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
4
10
|
def domain_permissions
|
5
|
-
|
6
|
-
return current_user.permissions_union unless current_entity # admin, by convention, not subscribed to any products
|
7
|
-
current_user.permissions_intersection(current_entity.permissions_union)
|
11
|
+
@permissions ||= determine_domain_permissions
|
8
12
|
end
|
9
13
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
14
|
+
def determine_domain_permissions
|
15
|
+
e = current_entity
|
16
|
+
u = current_user
|
17
|
+
if u.nil?
|
18
|
+
e ? e.permissions_union : {} # public pages display according to just corp/brand/merchant product permissions
|
19
|
+
else
|
20
|
+
e ? u.permissions_intersection(e.permissions_union) : u.permissions_union
|
21
|
+
end
|
13
22
|
end
|
14
23
|
|
15
24
|
end
|
data/lib/permissify/model.rb
CHANGED
@@ -12,17 +12,23 @@ module Permissify
|
|
12
12
|
|
13
13
|
def allows?(ability_key)
|
14
14
|
allowed = self.permissions[ability_key];
|
15
|
-
allowed && allowed['0']
|
16
|
-
|
15
|
+
# allowed && allowed['0']
|
16
|
+
allowed && (allowed['0'] == '1')
|
17
|
+
end
|
18
|
+
|
17
19
|
def remove_permissions(keys)
|
18
|
-
keys = [keys] if keys.class
|
20
|
+
keys = [keys] if keys.class != Array
|
19
21
|
keys.each{ |k| self.permissions[k] = nil}
|
20
22
|
self.save
|
21
23
|
end
|
24
|
+
|
22
25
|
def update_permissions(new_or_updated_permissions)
|
23
26
|
self.permissions = self.permissions.merge(new_or_updated_permissions)
|
24
27
|
self.save
|
25
28
|
end
|
26
|
-
|
29
|
+
|
30
|
+
def underscored_name_symbol
|
31
|
+
self.class.underscored_name_symbol(self.name)
|
32
|
+
end
|
27
33
|
end
|
28
34
|
end
|
@@ -1,17 +1,12 @@
|
|
1
1
|
module Permissify
|
2
2
|
module ModelClass
|
3
|
-
|
4
|
-
|
5
|
-
end
|
6
|
-
|
7
|
-
def create_seeds(table_name, seed_specifications)
|
8
|
-
@model_class_seed_specifications = seed_specifications
|
3
|
+
|
4
|
+
def create_seeds(seed_specifications)
|
9
5
|
seed_specifications.each do |id, name|
|
10
6
|
permissions_model = locate(id, name)
|
11
|
-
permissions_model.permissions = send("#{underscored_name_symbol(name)}_permissions")
|
7
|
+
permissions_model.permissions = send("#{underscored_name_symbol(name)}_permissions") # interface methods needed for each seeded model
|
12
8
|
permissions_model.save
|
13
9
|
end
|
14
|
-
ActiveRecord::Base.connection.execute "ALTER TABLE #{table_name} AUTO_INCREMENT = 101;"
|
15
10
|
end
|
16
11
|
|
17
12
|
def create_with_id(table, id, name)
|
@@ -20,17 +15,18 @@ module Permissify
|
|
20
15
|
permissions_model.name = name
|
21
16
|
permissions_model.permissions = permissions
|
22
17
|
permissions_model.save
|
23
|
-
|
18
|
+
force_seed_id(table, permissions_model, id) # interface method : force_seed_id
|
24
19
|
find(id)
|
25
20
|
end
|
26
21
|
|
27
22
|
def locate(id, name)
|
28
|
-
model_with_id = find_by_id(id)
|
29
|
-
model_with_id ||= send("create_#{underscored_name_symbol(name)}")
|
23
|
+
model_with_id = find_by_id(id) # interface method : ActiveRecord::Base.find_by_id
|
24
|
+
model_with_id ||= send("create_#{underscored_name_symbol(name)}") # interface methods needed for each seeded model
|
30
25
|
end
|
31
26
|
|
32
27
|
def underscored_name_symbol(name)
|
33
|
-
name.to_s.downcase.gsub('
|
28
|
+
name.to_s.downcase.gsub(':','').gsub('-','_').gsub(' ','_').gsub(/__*/,'_')
|
34
29
|
end
|
30
|
+
|
35
31
|
end
|
36
32
|
end
|
data/lib/permissify/roles.rb
CHANGED
@@ -1,24 +1,42 @@
|
|
1
1
|
module Permissify::Roles
|
2
2
|
include Permissify::Aggregate
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
u_role_names = sorted_role_names(u.roles)
|
17
|
-
! u_role_names.blank? && (role_names_that_this_user_can_manage & u_role_names) == u_role_names
|
3
|
+
|
4
|
+
# inclusion of this module necessitates that the app's roles implementation includes:
|
5
|
+
# 1. domain_type field
|
6
|
+
# 2. define DOMAIN_TYPES as a ranked list of strings in implementation of Role/Permissify::Model-including class
|
7
|
+
|
8
|
+
# NOTE: in example app, helper methods enforce only assigning domain_type-specific roles to users
|
9
|
+
# (an brand user can only be asigned roles that have a domain type of Brand).
|
10
|
+
def primary_domain_type
|
11
|
+
return nil if roles.empty?
|
12
|
+
domain_types = roles.collect(&:domain_type)
|
13
|
+
ranked_domain_types = roles.first.class::DOMAIN_TYPES
|
14
|
+
ranked_domain_types.each do |ranked_domain_type|
|
15
|
+
return ranked_domain_type if domain_types.include?(ranked_domain_type)
|
18
16
|
end
|
19
|
-
|
20
|
-
return users
|
17
|
+
nil # unrecognized domain_type value(s)
|
21
18
|
end
|
22
19
|
|
23
|
-
|
20
|
+
# uncomment/reimplement methods as needed for example app/as more light shines...
|
21
|
+
|
22
|
+
# def primary_domain_type; sorted_domain_types.first; end
|
23
|
+
# def primary_role_name; role_list(:description).sort.first; end
|
24
|
+
# def sorted_domain_types; role_list(:domain_type).sort; end
|
25
|
+
# def manages_roles; role_list(:manages_roles); end
|
26
|
+
# def manages_role_names; sorted_role_names(manages_roles); end
|
27
|
+
# def role_list(collection_method); roles.collect(&collection_method).flatten.uniq; end
|
28
|
+
#
|
29
|
+
# def can_create_and_modify(users, app_instance) # TODO : unit test for this
|
30
|
+
# role_names_that_this_user_can_manage = manages_role_names
|
31
|
+
# # 2 ways to go here : must be able to manage *all* or *any* of a user's roles.
|
32
|
+
# # Chose *all* to prevent lower ranking users from demoting higher ranking users
|
33
|
+
# users.select do |u|
|
34
|
+
# u_role_names = sorted_role_names(u.roles)
|
35
|
+
# ! u_role_names.blank? && (role_names_that_this_user_can_manage & u_role_names) == u_role_names
|
36
|
+
# end
|
37
|
+
# users.delete_if{|u| !u.instances.include?(app_instance)}
|
38
|
+
# return users
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# def sorted_role_names(roles); roles.collect(&:name).sort; end
|
24
42
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Permissify::Aggregate do
|
4
|
+
|
5
|
+
describe 'permissions_union' do
|
6
|
+
before(:each) { new_aggregate; @union = @a.permissions_union}
|
7
|
+
|
8
|
+
it 'should include keys for permissions specified (true or false) in any permissified model' do
|
9
|
+
@union.keys.to_set.should == @pms.collect(&:permissions).collect(&:keys).flatten.uniq.to_set
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should indicate permission for a key is true if permission set to true in any permissified object permission set' do
|
13
|
+
%w(p_1 p_2 p_3 p_4 p_5).each{ |permission| @union[permission]['0'].should be_true }
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should indicate permission for a key is false if permission not set to true in any permissified object permission set' do
|
17
|
+
%w(p_6 p_7 p_8).each{ |permission| @union[permission]['0'].should be_false }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'allowed_to?' do
|
22
|
+
before(:each) { new_aggregate }
|
23
|
+
|
24
|
+
it 'should return true when permission is set in a permissified model permission set' do
|
25
|
+
(1..5).each{ |action| @a.allowed_to?(action.to_s, 'p').should be_true }
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return false when permission is set to false in all permissified model permission sets where it is present or not present in any permission set' do
|
29
|
+
(6..9).each{ |action| @a.allowed_to?(action.to_s, 'p').should be_false }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
[ %w(subscribed_to? product1_on product1),
|
34
|
+
%w(viewable? thing_view thing),
|
35
|
+
%w(createable? thing_create thing),
|
36
|
+
%w(updateable? thing_update thing),
|
37
|
+
%w(deleteable? thing_delete thing),
|
38
|
+
].each do |method_name, permission_key, method_arg|
|
39
|
+
describe "#{method_name}" do
|
40
|
+
it "should be true when permission for '#{permission_key}' is specified as true" do
|
41
|
+
method_should(be_true, {permission_key => {'0' => '1'}}, method_name, method_arg)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be false when permission for '#{permission_key}' specified as false" do
|
45
|
+
method_should(be_false, {permission_key => {'0' => '0'}}, method_name, method_arg)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should be false when permission for '#{permission_key}' not specified" do
|
49
|
+
method_should(be_false, {}, method_name, method_arg)
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_should(be_true_or_false, permissions, method_name, method_arg)
|
53
|
+
new_aggregate( [new_permissified_model( permissions )] )
|
54
|
+
@a.send(method_name, method_arg).should be_true_or_false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# TODO : work out intersection specs in corp/brand/business products phase
|
60
|
+
# describe 'permissions_intersection' do
|
61
|
+
# it 'should ...' do
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
|
65
|
+
def new_aggregate(permissified_models = default_permissified_models)
|
66
|
+
@a = Userish.new
|
67
|
+
@pms = permissified_models
|
68
|
+
@a.roles = @pms
|
69
|
+
end
|
70
|
+
|
71
|
+
def default_permissified_models
|
72
|
+
[ new_permissified_model( {'p_1' => {'0' => '0'}, 'p_2' => {'0' => '1'}, 'p_3' => {'0' => '1'}, 'p_6' => {'0' => '0'}} ),
|
73
|
+
new_permissified_model( {'p_1' => {'0' => '1'}, 'p_2' => {'0' => '0'}, 'p_4' => {'0' => '1'}, 'p_7' => {'0' => '0'}} ),
|
74
|
+
new_permissified_model( {'p_1' => {'0' => '0'}, 'p_2' => {'0' => '0'}, 'p_5' => {'0' => '1'}, 'p_8' => {'0' => '0'}} )
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
def new_permissified_model(permissions)
|
79
|
+
pm = PermissifiedModel.new
|
80
|
+
pm.permissions = permissions
|
81
|
+
pm
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Permissify::Controller do
|
4
|
+
before(:each) { @controller = PermissifiedController.new }
|
5
|
+
|
6
|
+
describe 'allowed_to?' do
|
7
|
+
describe 'and no current entity' do
|
8
|
+
before(:each) { @controller.should_receive(:current_entity).and_return(nil) }
|
9
|
+
|
10
|
+
it 'should return false when no current user' do
|
11
|
+
@controller.should_receive(:current_user).and_return(nil)
|
12
|
+
allowed_to_should be_false
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'and current user is not nil' do
|
16
|
+
before(:each) do
|
17
|
+
@user = Userish.new
|
18
|
+
@controller.should_receive(:current_user).and_return(@user)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return true when current user has permission for category action' do
|
22
|
+
category_action_permission_causes_allowed_to_be true, be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return false when current user does not have permission for category action' do
|
26
|
+
category_action_permission_causes_allowed_to_be false, be_false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'and current entity exists' do
|
32
|
+
describe 'and no current user' do
|
33
|
+
it 'should return true when current entity has permission for category action' do
|
34
|
+
pending('products phase')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return false when current entity does not have permission for category action' do
|
38
|
+
pending('products phase')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'and current user is not nil' do
|
43
|
+
describe 'and current entity has permission for category action' do
|
44
|
+
it 'should return true when current user has permission for category action' do
|
45
|
+
pending('products phase')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should return false when current user does not have permission for category action' do
|
49
|
+
pending('products phase')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'and current entity does not have permission for category action' do
|
54
|
+
it 'should return false when current user has permission for category action' do
|
55
|
+
pending('products phase')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should return false when current user does not have permission for category action' do
|
59
|
+
pending('products phase')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def category_action_permission_causes_allowed_to_be(permission_true_or_false, be_true_or_false, action = :view, category = :something)
|
66
|
+
@user.should_receive(:permissions_union).and_return( {"#{category}_#{action}" => {'0' => permission_true_or_false} })
|
67
|
+
allowed_to_should be_true_or_false, action, category
|
68
|
+
end
|
69
|
+
|
70
|
+
def allowed_to_should(be_true_or_false, action = :view, category = :something)
|
71
|
+
@controller.allowed_to?(:view, :something).should be_true_or_false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Permissify::ModelClass do
|
4
|
+
describe 'create_seeds' do
|
5
|
+
it 'should locate, set permissions and save each specified seed' do
|
6
|
+
(seed_specifications = [ [21, 'seeded model name1'], [81, 'seeded model name 2'] ]).each do |id, name|
|
7
|
+
PermissifiedModel.should_receive(:locate).with(id, name).and_return(located_model = mock)
|
8
|
+
app_implemented_permissions_method = "#{name.gsub(' ','_')}_permissions"
|
9
|
+
PermissifiedModel.should_receive(app_implemented_permissions_method).and_return(:name_permissions)
|
10
|
+
located_model.should_receive(:permissions=).with(:name_permissions)
|
11
|
+
located_model.should_receive(:save)
|
12
|
+
end
|
13
|
+
PermissifiedModel.create_seeds seed_specifications
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'create_with_id' do
|
18
|
+
it 'should create a new object, set its name, permissions, save it, force its id and then find it' do
|
19
|
+
PermissifiedModel.should_receive(:name_permissions).and_return(:permissions_for_name)
|
20
|
+
PermissifiedModel.should_receive(:new).and_return(mocked_permissions_model = mock())
|
21
|
+
mocked_permissions_model.should_receive(:name=).with(:name)
|
22
|
+
mocked_permissions_model.should_receive(:permissions=).with(:permissions_for_name)
|
23
|
+
mocked_permissions_model.should_receive(:save)
|
24
|
+
PermissifiedModel.should_receive(:force_seed_id).with(:table, mocked_permissions_model, :id)
|
25
|
+
PermissifiedModel.should_receive(:find).with(:id).and_return(:model_returned_from_find)
|
26
|
+
PermissifiedModel.create_with_id(:table, :id, :name).should == :model_returned_from_find
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'locate' do
|
31
|
+
it 'should return model corresponding to input id when model with id exists' do
|
32
|
+
mock_find_by_id :model_from_find_by_id
|
33
|
+
PermissifiedModel.locate(:input_model_id, :input_model_id_name).should == :model_from_find_by_id
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return response from app-implemented "create_input_model_id_name"' do
|
37
|
+
mock_find_by_id nil
|
38
|
+
PermissifiedModel.should_receive(:create_input_model_id_name).and_return(:model_from_create_input_model_id_name)
|
39
|
+
PermissifiedModel.locate(:input_model_id, :input_model_id_name).should == :model_from_create_input_model_id_name
|
40
|
+
end
|
41
|
+
|
42
|
+
def mock_find_by_id(mocked_return)
|
43
|
+
PermissifiedModel.should_receive(:find_by_id).with(:input_model_id).and_return(mocked_return)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'underscored_name_symbol' do
|
48
|
+
it 'should return a string' do
|
49
|
+
PermissifiedModel.underscored_name_symbol(:symbol).class.name.should == 'String'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should return a downcased version of input' do
|
53
|
+
PermissifiedModel.underscored_name_symbol(:SYMBOL).should == 'symbol'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should squish whitespace into a single underscore' do
|
57
|
+
PermissifiedModel.underscored_name_symbol(' squish it ').should == '_squish_it_'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should convert dashes to underscores' do
|
61
|
+
PermissifiedModel.underscored_name_symbol('-dash--to---underscore----').should == '_dash_to_underscore_'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should remove colons' do
|
65
|
+
PermissifiedModel.underscored_name_symbol(':colons:::be:gone:::').should == 'colonsbegone'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Permissify::Model do
|
4
|
+
describe 'establish_from_permissions_model' do
|
5
|
+
it 'should set from_permissions_model to nil when from is nil' do
|
6
|
+
from_permissions_model_should_be nil
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should set from_permissions_model to find response when from is set' do
|
10
|
+
PermissifiedModel.should_receive(:find).with(:with_from_value).and_return(:find_response)
|
11
|
+
from_permissions_model_should_be(:find_response, :with_from_value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def from_permissions_model_should_be(expected_from_permissions_model, from_value = nil)
|
15
|
+
new_model
|
16
|
+
@pm.from = from_value
|
17
|
+
@pm.establish_from_permissions_model
|
18
|
+
@pm.from_permissions_model.should == expected_from_permissions_model
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'initialize_permissions' do
|
23
|
+
before(:each) { new_model }
|
24
|
+
|
25
|
+
it 'should set permissions to empty hash when from is not set' do
|
26
|
+
permissions_should_be({}, nil)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should set permissions from model that can be found with from value' do
|
30
|
+
other_permissions_model = mock(:permissions => :other_permissions)
|
31
|
+
@pm.should_receive(:establish_from_permissions_model).and_return(other_permissions_model)
|
32
|
+
permissions_should_be(:other_permissions, :with_from_value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def permissions_should_be(expected_permissions, from_value = nil)
|
36
|
+
@pm.from = from_value
|
37
|
+
@pm.initialize_permissions
|
38
|
+
@pm.permissions.should == expected_permissions
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'allows?' do
|
43
|
+
it 'should return false when ability key is not present in permissions' do
|
44
|
+
expect_allows({}, be_false)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should return false when ability key is present in permissions but does not have a value corresponding to key \'0\'' do
|
48
|
+
expect_allows({'permission' => {'1' => 'notzero'}}, be_false)
|
49
|
+
end
|
50
|
+
|
51
|
+
[nil, 0, '0', 1].each do |value_that_evaluates_to_false|
|
52
|
+
it "should return false when ability key is present in permissions, and value corresponding to key '0' is #{value_that_evaluates_to_false} (#{value_that_evaluates_to_false.class.name})" do
|
53
|
+
expect_allows({'permission' => {'0' => value_that_evaluates_to_false}}, be_false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return true when ability key is present in permissions, and value corresponding to key '0' is '1'" do
|
58
|
+
expect_allows({'permission' => {'0' => '1'}}, be_true)
|
59
|
+
end
|
60
|
+
|
61
|
+
def expect_allows(permission_hash_value, be_true_or_false)
|
62
|
+
new_model
|
63
|
+
@pm.permissions = permission_hash_value
|
64
|
+
@pm.allows?('permission').should be_true_or_false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'remove_permissions' do
|
69
|
+
it 'should set permissions value associated with input key(s) to nil' do
|
70
|
+
new_model
|
71
|
+
@pm.permissions = {:key1 => 1, :key2 => 1}
|
72
|
+
@pm.should_receive(:save)
|
73
|
+
@pm.remove_permissions(:key1)
|
74
|
+
@pm.permissions.should == {:key1 => nil, :key2 => 1}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'update_permissions' do
|
79
|
+
before(:each) { new_model }
|
80
|
+
it 'should save merged permissions' do
|
81
|
+
@pm.should_receive(:permissions).and_return(current_permissions = {})
|
82
|
+
current_permissions.should_receive(:merge).with(:new_permissions).and_return(:merged_permissions)
|
83
|
+
@pm.should_receive(:permissions=).with(:merged_permissions)
|
84
|
+
@pm.should_receive(:save)
|
85
|
+
@pm.update_permissions(:new_permissions)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'underscored_name_symbol' do
|
90
|
+
before(:each) { new_model }
|
91
|
+
|
92
|
+
it 'should invoke class underscored_name_symbol method with model name' do
|
93
|
+
PermissifiedModel.should_receive(:underscored_name_symbol).with(@pm.name).and_return(:response_from_class_underscored_name_symbol_method)
|
94
|
+
@pm.underscored_name_symbol.should == :response_from_class_underscored_name_symbol_method
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def new_model
|
99
|
+
@pm = PermissifiedModel.new
|
100
|
+
@pm.name = 'model name'
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Permissify::Roles do
|
4
|
+
|
5
|
+
describe 'primary_domain_type' do
|
6
|
+
ranked_domain_types = Roleish::DOMAIN_TYPES
|
7
|
+
n = ranked_domain_types.length - 1
|
8
|
+
(0..n).each do |i|
|
9
|
+
subset_of_ranked_domain_types = ranked_domain_types[i..n]
|
10
|
+
expected_primary_domain_type = subset_of_ranked_domain_types[0]
|
11
|
+
it "should return '#{expected_primary_domain_type}' when represented domain types are #{subset_of_ranked_domain_types.join(',')}" do
|
12
|
+
new_user_with_roles( subset_of_ranked_domain_types.collect{|dt| new_role(dt) }.reverse )
|
13
|
+
@u.primary_domain_type.should == expected_primary_domain_type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def new_user_with_roles(roles)
|
19
|
+
@u = UserishWithRoles.new
|
20
|
+
@roles = roles
|
21
|
+
@u.roles = @roles
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_role(domain_type)
|
25
|
+
pm = Roleish.new
|
26
|
+
pm.domain_type = domain_type
|
27
|
+
pm
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
-
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
-
# Require this file using `require "spec_helper.rb"` to ensure that it is only
|
4
|
-
# loaded once.
|
5
|
-
#
|
6
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
1
|
require 'rubygems'
|
8
2
|
require 'bundler/setup'
|
9
3
|
|
@@ -38,3 +32,32 @@ class NoSeedAbility
|
|
38
32
|
include Permissify::AbilityClass
|
39
33
|
end
|
40
34
|
end
|
35
|
+
|
36
|
+
class PermissifiedModel
|
37
|
+
include Permissify::Model
|
38
|
+
attr_accessor :name, :permissions
|
39
|
+
class << self
|
40
|
+
include Permissify::ModelClass
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Roleish < PermissifiedModel
|
45
|
+
DOMAIN_TYPES = %w(Admin Dealer Corporate Brand Merchant)
|
46
|
+
attr_accessor :domain_type
|
47
|
+
end
|
48
|
+
|
49
|
+
class Userish
|
50
|
+
include Permissify::Aggregate
|
51
|
+
PERMISSIFIED_ASSOCIATION = :roles
|
52
|
+
attr_accessor :roles
|
53
|
+
end
|
54
|
+
|
55
|
+
class UserishWithRoles
|
56
|
+
include Permissify::Roles
|
57
|
+
PERMISSIFIED_ASSOCIATION = :roles
|
58
|
+
attr_accessor :roles
|
59
|
+
end
|
60
|
+
|
61
|
+
class PermissifiedController
|
62
|
+
include Permissify::Controller
|
63
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: permissify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 61
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 17
|
10
|
+
version: 0.0.17
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Frederick Fix
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-06-
|
18
|
+
date: 2012-06-11 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rspec
|
@@ -109,6 +109,11 @@ files:
|
|
109
109
|
- lib/permissify/roles.rb
|
110
110
|
- lib/permissify.rb
|
111
111
|
- spec/permissify/ability_class_spec.rb
|
112
|
+
- spec/permissify/aggregate_spec.rb
|
113
|
+
- spec/permissify/controller_spec.rb
|
114
|
+
- spec/permissify/model_class_spec.rb
|
115
|
+
- spec/permissify/model_spec.rb
|
116
|
+
- spec/permissify/roles_spec.rb
|
112
117
|
- spec/spec.opts
|
113
118
|
- spec/spec_helper.rb
|
114
119
|
- CHANGELOG.rdoc
|