permissify 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
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 :roles, SEED_SPECIFICATIONS
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
@@ -2,13 +2,34 @@ module Permissify
2
2
  module Aggregate
3
3
  attr_accessor :abilities
4
4
 
5
- def permissions_union # [integer values].max
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).collect(&:permissions).each do |permissions_hash|
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'] == '1' || descriptor['0'] == '1')
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; aggregation[key][is] = [aggregation[key][is].to_i, other_descriptor[is].to_i].send(min_or_max) # .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
- def null_permission; {'0' => false, '1' => 0}; end
77
-
78
- # # TODO : need to do this differently : specify in model? discern from
79
- # def permissions_association # kinda icky
80
- # klass = self.respond_to?(:products) ? self.class : Business
81
- # @permissions_association ||= {User => :roles, klass => :products}[self.class]
82
- # @permissions_association ||= :permission_objects
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
- return current_entity.permissions_union if current_user.nil? # public pages allow corp/brand/merchant product permissions
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 allowed_to?(action, permission_category)
11
- @permissions ||= domain_permissions
12
- (@permissions["#{permission_category}_#{action}"]['0'] == true rescue false)
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
@@ -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
- end
15
+ # allowed && allowed['0']
16
+ allowed && (allowed['0'] == '1')
17
+ end
18
+
17
19
  def remove_permissions(keys)
18
- keys = [keys] if keys.class == String
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
- def underscored_name_symbol; self.class.underscored_name_symbol(self.name); end
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
- def retire_permissions_objects(retire_sql)
4
- ActiveRecord::Base.connection.execute retire_sql
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
- ActiveRecord::Base.connection.execute "UPDATE #{table}s SET id=#{id} WHERE id=#{permissions_model.id};"
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('-','_').gsub(':','').gsub(' ',' ').gsub(' ','_')
28
+ name.to_s.downcase.gsub(':','').gsub('-','_').gsub(' ','_').gsub(/__*/,'_')
34
29
  end
30
+
35
31
  end
36
32
  end
@@ -1,24 +1,42 @@
1
1
  module Permissify::Roles
2
2
  include Permissify::Aggregate
3
-
4
- def primary_domain_type; sorted_domain_types.first; end
5
- def primary_role_name; role_list(:description).sort.first; end
6
- def sorted_domain_types; role_list(:domain_type).sort; end
7
- def manages_roles; role_list(:manages_roles); end
8
- def manages_role_names; sorted_role_names(manages_roles); end
9
- def role_list(collection_method); roles.collect(&collection_method).flatten.uniq; end
10
-
11
- def can_create_and_modify(users, app_instance) # TODO : unit test for this
12
- role_names_that_this_user_can_manage = manages_role_names
13
- # 2 ways to go here : must be able to manage *all* or *any* of a user's roles.
14
- # Chose *all* to prevent lower ranking users from demoting higher ranking users
15
- users.select do |u|
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
- users.delete_if{|u| !u.instances.include?(app_instance)}
20
- return users
17
+ nil # unrecognized domain_type value(s)
21
18
  end
22
19
 
23
- def sorted_role_names(roles); roles.collect(&:name).sort; end
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: 63
4
+ hash: 61
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 16
10
- version: 0.0.16
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-06 00:00:00 Z
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