right_on 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ module RightOn
2
+ class Rule
3
+ def self.rule_for(right)
4
+ self.new(right).call
5
+ end
6
+
7
+ def initialize(right)
8
+ @right = right
9
+ end
10
+
11
+ def call
12
+ validate!
13
+
14
+ CanCan::Rule.new(can?, action, subject, conditions, nil)
15
+ end
16
+
17
+ private
18
+
19
+ def validate!
20
+ fail RightOn::Error, 'must specify an action' unless @right.action.present?
21
+ end
22
+
23
+ def can?
24
+ @right.can
25
+ end
26
+
27
+ def action
28
+ @right.action.to_sym
29
+ end
30
+
31
+ def subject
32
+ model_class || @right.subject
33
+ end
34
+
35
+ def conditions
36
+ model_class ? @right.conditions : nil
37
+ end
38
+
39
+ def model_class
40
+ return nil unless @right.subject.present?
41
+
42
+ begin
43
+ model_class = self.class.const_get(@right.subject)
44
+ rescue NameError
45
+ model_class = Class
46
+ end
47
+
48
+ return model_class if model_class.ancestors.include?(ActiveRecord::Base)
49
+ end
50
+ end
51
+ end
@@ -1,3 +1,3 @@
1
1
  module RightOn
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'activerecord', '>= 3.2.0'
22
- spec.add_dependency 'activesupport', '>= 3.2.0'
21
+ spec.add_dependency 'cancancan'
22
+ spec.add_dependency 'activerecord', '>= 4.0.0'
23
+ spec.add_dependency 'activesupport', '>= 4.0.0'
23
24
  spec.add_dependency 'input_reader', '~> 0.0'
24
25
  spec.add_development_dependency 'bundler', '~> 1.3'
25
26
  spec.add_development_dependency 'rake'
@@ -27,6 +28,7 @@ Gem::Specification.new do |spec|
27
28
  spec.add_development_dependency 'coverage-kit'
28
29
  spec.add_development_dependency 'simplecov-rcov'
29
30
  spec.add_development_dependency 'coveralls'
31
+ spec.add_development_dependency 'rubocop'
30
32
  spec.add_development_dependency 'sqlite3'
31
33
  spec.add_development_dependency 'travis'
32
34
  end
@@ -0,0 +1,29 @@
1
+ require 'active_support/all'
2
+ require 'cancan/ability'
3
+ require 'right_on/error'
4
+ require 'right_on/rule'
5
+ require 'right_on/ability'
6
+ require 'spec_helper'
7
+
8
+ describe RightOn::Ability do
9
+ describe 'private #add_rule_for' do
10
+ subject(:ability) {
11
+ class TestAbility
12
+ include RightOn::Ability
13
+ end
14
+
15
+ TestAbility.new
16
+ }
17
+ let(:right) {
18
+ double(name: 'Do Something', can: true, action: 'action', subject: 'subject', conditions: {})
19
+ }
20
+
21
+ before do
22
+ ability.send(:add_rule_for, right)
23
+ end
24
+
25
+ it 'should add a rule to the ability' do
26
+ expect(ability.send(:rules).count).to eq(1)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ RightOn.rights_yaml 'db/rights_roles.yml'
4
+
5
+ describe RightOn::ByGroup do
6
+ let(:rights) { Bootstrap.various_rights_with_actions }
7
+
8
+ it 'should identify correct groups' do
9
+ rights # load rights
10
+ expect(RightOn::ByGroup.rights).to eq(
11
+ 'general' => [
12
+ rights[:models],
13
+ rights[:models_index],
14
+ rights[:models_view],
15
+ rights[:models_change]
16
+ ],
17
+ 'admin' => [
18
+ rights[:users]
19
+ ]
20
+ )
21
+ end
22
+ end
@@ -0,0 +1,134 @@
1
+ require 'active_support/all'
2
+ require 'action_controller'
3
+ require 'cancan/ability'
4
+ require 'cancan/controller_additions'
5
+ require 'cancan/exceptions'
6
+ require 'cancan/rule'
7
+ require 'right_on/ability'
8
+ require 'right_on/controller_additions'
9
+ require 'right_on/error'
10
+ require 'right_on/rule'
11
+ require 'active_record'
12
+ require 'spec_helper'
13
+
14
+ # Mock this so we don't need to include active record
15
+ module RightOn
16
+ class Right
17
+ def self.where(args)
18
+ end
19
+ end
20
+ end
21
+
22
+ describe RightOn::ControllerAdditions do
23
+ let(:rule_override) { false }
24
+ before do
25
+ allow(RightOn::Right).to receive(:where).and_return(double(exists?: rule_override))
26
+ end
27
+
28
+ subject(:controller) {
29
+ class Ability
30
+ include RightOn::Ability
31
+
32
+ def initialize(user)
33
+
34
+ end
35
+ end
36
+
37
+ class Controller < ActionController::Base
38
+ include RightOn::ControllerAdditions
39
+
40
+ def rights_from
41
+ nil
42
+ end
43
+
44
+ private
45
+
46
+ def params
47
+ { controller: 'controller', action: 'action' }
48
+ end
49
+
50
+ def current_user
51
+ nil
52
+ end
53
+ end
54
+
55
+ Controller.new
56
+ }
57
+
58
+ describe 'private #authorize_action!' do
59
+ context 'when the ability has a matching rule' do
60
+ let(:right) {
61
+ double(name: 'Do Something', can: true, action: 'access', subject: 'controller#action', conditions: {})
62
+ }
63
+
64
+ before do
65
+ controller.send(:current_ability).send(:add_rule_for, right)
66
+ end
67
+
68
+ it 'should grant access to controller#action' do
69
+ expect{controller.send(:authorize_action!)}.to_not(
70
+ raise_error(CanCan::AccessDenied, 'You are not authorized to access this page.'))
71
+ end
72
+ end
73
+
74
+ context 'when the ability does not have a matching rule' do
75
+ let(:right) {
76
+ double(name: 'Do Something', can: true, action: 'access', subject: 'controller#other_action', conditions: {})
77
+ }
78
+
79
+ before do
80
+ controller.send(:current_ability).send(:add_rule_for, right)
81
+ end
82
+
83
+ it 'should grant access to controller#action' do
84
+ expect{controller.send(:authorize_action!)}.to(
85
+ raise_error(CanCan::AccessDenied, 'You are not authorized to access this page.'))
86
+ end
87
+ end
88
+
89
+ context 'when the ability has a specific rule overriding the general rule' do
90
+ let(:rule_override) { true }
91
+ let(:right) {
92
+ double(name: 'Generic', can: true, action: 'access', subject: 'controller', conditions: {})
93
+ }
94
+
95
+ before do
96
+ controller.send(:current_ability).send(:add_rule_for, right)
97
+ end
98
+
99
+ it 'should not grant access to controller#action' do
100
+ expect{controller.send(:authorize_action!)}.to(
101
+ raise_error(CanCan::AccessDenied, 'You are not authorized to access this page.'))
102
+ end
103
+ end
104
+ end
105
+
106
+ describe 'private #authorize_action!' do
107
+ let(:controller) {
108
+ class Controller < ActionController::Base
109
+ def rights_from
110
+ :other_controller
111
+ end
112
+
113
+ private
114
+
115
+ def params
116
+ { controller: 'controller', action: 'action' }
117
+ end
118
+
119
+ def current_user
120
+ nil
121
+ end
122
+ end
123
+
124
+ Controller.new
125
+ }
126
+
127
+ context 'when rights from is a symbol' do
128
+ specify do
129
+ expect{controller.send(:authorize_action!)}.to(
130
+ raise_error(CanCan::AccessDenied, 'You are not authorized to access this page.'))
131
+ end
132
+ end
133
+ end
134
+ end
@@ -5,9 +5,8 @@ describe RightOn::PermissionDeniedResponse do
5
5
  let(:params) { { controller: 'users' } }
6
6
  subject { RightOn::PermissionDeniedResponse.new(params, controller_action_options) }
7
7
 
8
- let(:allowed) {
9
- double(name: 'create_user', allowed?: true, roles: [double(title: 'Users')])
10
- }
8
+ let(:create_user_right) { double(name: 'create_user', allowed?: true, roles: [double(title: 'Users')]) }
9
+ let(:allowed) { double(allowed?: true) }
11
10
  let(:denied) { double(allowed?: false) }
12
11
 
13
12
  let(:no_right_for_page) {
@@ -17,12 +16,13 @@ describe RightOn::PermissionDeniedResponse do
17
16
  let(:no_roles_for_page) { 'N/A (as no right is assigned for this action)' }
18
17
 
19
18
  before do
20
- stub_const 'RightOn::Right', double(all: [right])
19
+ stub_const 'RightOn::RightAllowed', double(new: right_allowed)
20
+ stub_const 'RightOn::Right', double(all: [create_user_right])
21
21
  end
22
22
 
23
23
  context '#text_message' do
24
24
  context 'when right exists' do
25
- let(:right) { allowed }
25
+ let(:right_allowed) { allowed }
26
26
 
27
27
  specify {
28
28
  expect(subject.text_message).to eq(
@@ -35,14 +35,14 @@ describe RightOn::PermissionDeniedResponse do
35
35
  end
36
36
 
37
37
  context 'when right not allowed' do
38
- let(:right) { denied }
38
+ let(:right_allowed) { denied }
39
39
  specify { expect(subject.text_message).to eq no_right_for_page }
40
40
  end
41
41
  end
42
42
 
43
43
  context '#to_json' do
44
44
  context 'when right exists' do
45
- let(:right) { allowed }
45
+ let(:right_allowed) { allowed }
46
46
  specify {
47
47
  expect(subject.to_json).to eq(
48
48
  error: 'Permission Denied',
@@ -53,7 +53,7 @@ describe RightOn::PermissionDeniedResponse do
53
53
  end
54
54
 
55
55
  context 'when right allowed' do
56
- let(:right) { denied }
56
+ let(:right_allowed) { denied }
57
57
  specify {
58
58
  expect(subject.to_json).to eq(
59
59
  error: 'Permission Denied',
@@ -0,0 +1,89 @@
1
+ require 'active_record'
2
+ require 'active_support/cache/memory_store'
3
+ require 'right_on/right'
4
+ require 'right_on/right_allowed'
5
+ require 'spec_helper'
6
+ require 'support/bootstrap'
7
+
8
+ describe RightOn::RightAllowed do
9
+ def right_double(name)
10
+ default_attrs = { id: rand(1_000_000), action: nil }
11
+ double default_attrs.merge(Bootstrap.build_right_attrs(name))
12
+ end
13
+
14
+ let(:cache) { ActiveSupport::Cache::MemoryStore.new }
15
+
16
+ before do
17
+ stub_const 'Rails', double(cache: cache)
18
+ RightOn::RightAllowed.clear_cache
19
+ stub_const 'RightOn::Right', double(all: all)
20
+ end
21
+
22
+ context 'for simple case with one controller right' do
23
+ let(:all) { [users] }
24
+ let(:users) { right_double('users') }
25
+
26
+ subject { RightOn::RightAllowed.new('users', action).allowed?(users) }
27
+
28
+ context 'index action' do
29
+ let(:action) { 'index' }
30
+ it { is_expected.to be true }
31
+ end
32
+
33
+ context 'edit action' do
34
+ let(:action) { 'edit' }
35
+ it { is_expected.to be true }
36
+ end
37
+
38
+ context 'hello action' do
39
+ let(:action) { 'hello' }
40
+ it { is_expected.to be true }
41
+ end
42
+ end
43
+
44
+ context 'for complex rights' do
45
+ let(:all) { [other, index, change, view] }
46
+
47
+ let(:index_action) { RightOn::RightAllowed.new('models', 'index') }
48
+ let(:edit_action) { RightOn::RightAllowed.new('models', 'edit') }
49
+ let(:hello_action) { RightOn::RightAllowed.new('models', 'hello') }
50
+
51
+ let(:other) { right_double('models') }
52
+ let(:index) { right_double('models#index') }
53
+ let(:change) { right_double('models#change') }
54
+ let(:view) { right_double('models#view') }
55
+
56
+ context 'index action' do
57
+ specify do
58
+ # as specific action exists
59
+ expect(index_action.allowed?(other)).to eq false
60
+
61
+ expect(index_action.allowed?(index)).to eq true
62
+ expect(index_action.allowed?(view)).to eq true
63
+ expect(index_action.allowed?(change)).to eq true
64
+ end
65
+ end
66
+
67
+ context 'edit action' do
68
+ specify do
69
+ # as specific action exists
70
+ expect(edit_action.allowed?(other)).to eq false
71
+
72
+ expect(edit_action.allowed?(index)).to eq false
73
+ expect(edit_action.allowed?(view)).to eq false
74
+ expect(edit_action.allowed?(change)).to eq true
75
+ end
76
+ end
77
+
78
+ context 'hello action' do
79
+ specify do
80
+ # as hello isn't defined
81
+ expect(hello_action.allowed?(other)).to eq true
82
+
83
+ expect(hello_action.allowed?(index)).to eq false
84
+ expect(hello_action.allowed?(view)).to eq false
85
+ expect(hello_action.allowed?(change)).to eq false
86
+ end
87
+ end
88
+ end
89
+ end
@@ -1,139 +1,86 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe User do
4
- let(:basic_user) { User.where(name: 'basic').first }
5
- let(:admin_user) { User.where(name: 'admin').first }
6
-
7
- before do
8
- Bootstrap.reset_database
9
- end
10
-
11
- it 'should compare privileges' do
12
- expect(admin_user.has_privileges_of?(basic_user)).to eq true
13
- expect(basic_user.has_privileges_of?(admin_user)).to eq false
14
- end
15
- end
16
-
17
3
  describe RightOn::Right do
18
- before do
19
- RightOn::Right.delete_all
20
- Model.delete_all
21
-
22
- @model = Model.create!(:name => 'Test')
23
-
24
- @users = RightOn::Right.create!(:name => 'users', :controller => 'users')
25
- @other = RightOn::Right.create!(:name => 'models', :controller => 'models')
26
- @index = RightOn::Right.create!(:name => 'models#index', :controller => 'models', :action => 'index')
27
- @change = RightOn::Right.create!(:name => 'models#change', :controller => 'models', :action => 'change')
28
- @view = RightOn::Right.create!(:name => 'models#view', :controller => 'models', :action => 'view')
29
- end
4
+ let(:rights) { Bootstrap.various_rights_with_actions }
5
+ let(:users) { rights[:users] }
6
+ let(:other) { rights[:models] }
7
+ let(:index) { rights[:models_index] }
8
+ let(:change) { rights[:models_change] }
9
+ let(:view) { rights[:models_view] }
30
10
 
31
11
  it 'should display nicely with sensible_name and to_s' do
32
- expect(@other.to_s).to eq 'models'
33
- expect(@index.to_s).to eq 'models#index'
34
-
35
- expect(@other.sensible_name).to eq 'Models'
36
- expect(@index.sensible_name).to eq 'Models - Index'
37
- end
12
+ expect(other.to_s).to eq 'models'
13
+ expect(index.to_s).to eq 'models#index'
38
14
 
39
- it 'should identify correct groups' do
40
- expect(RightOn::Right.by_groups).to eq(
41
- 'general' => [@other, @index, @view, @change],
42
- 'admin' => [@users]
43
- )
44
- end
45
-
46
- it 'should determine if it is allowed based on context' do
47
- index_action = {:controller => 'models', :action => 'index'}
48
- edit_action = {:controller => 'models', :action => 'edit'}
49
- hello_action = {:controller => 'models', :action => 'hello'}
50
-
51
- expect(@users.allowed?(:controller => 'users', :action => 'index')).to eq true
52
- expect(@users.allowed?(:controller => 'users', :action => 'edit' )).to eq true
53
- expect(@users.allowed?(:controller => 'users', :action => 'hello')).to eq true
54
-
55
- expect(@other.allowed?(index_action)).to eq false # as specific action exists
56
- expect(@other.allowed?(edit_action )).to eq false # as specific action exists
57
- expect(@other.allowed?(hello_action)).to eq true # as hello isn't defined
58
-
59
- expect(@index.allowed?(index_action)).to eq true
60
- expect(@index.allowed?(edit_action )).to eq false
61
- expect(@index.allowed?(hello_action)).to eq false
62
-
63
- expect(@view.allowed?(index_action)).to eq true
64
- expect(@view.allowed?(edit_action )).to eq false
65
- expect(@view.allowed?(hello_action)).to eq false
66
-
67
- expect(@change.allowed?(index_action)).to eq true
68
- expect(@change.allowed?(edit_action )).to eq true
69
- expect(@change.allowed?(hello_action)).to eq false
15
+ expect(other.sensible_name).to eq 'Models'
16
+ expect(index.sensible_name).to eq 'Models - Index'
70
17
  end
71
18
  end
72
19
 
73
- describe RightOn::Right, "when created" do
74
- it "should validate presence of name" do
20
+ describe RightOn::Right, 'when created' do
21
+ it 'should validate presence of name' do
75
22
  subject.valid?
76
23
  expect(subject.errors[:name]).to_not be_blank
77
24
  end
78
25
  end
79
26
 
80
- describe RightOn::Right, "with a name and controller" do
27
+ describe RightOn::Right, 'with a name and controller' do
81
28
  before do
82
- @new_right = RightOn::Right.new(:name => "tickets", :controller => "tickets")
29
+ @new_right = RightOn::Right.new(name: 'tickets', controller: 'tickets')
83
30
  @new_right.save!
84
31
  end
85
32
 
86
- it "should create a new right" do
87
- expect(@new_right.name).to eq "tickets"
88
- expect(@new_right.controller).to eq "tickets"
33
+ it 'should create a new right' do
34
+ expect(@new_right.name).to eq 'tickets'
35
+ expect(@new_right.controller).to eq 'tickets'
89
36
  expect(@new_right.save).to eq true
90
37
  end
91
38
 
92
39
  end
93
40
 
94
- describe RightOn::Right, "with a name, controller and action" do
41
+ describe RightOn::Right, 'with a name, controller and action' do
95
42
  before do
96
- @new_right = RightOn::Right.new(:name => "tickets@destroy", :controller => "tickets", :action => "destroy")
43
+ @new_right = RightOn::Right.new(name: 'tickets@destroy', controller: 'tickets', action: 'destroy')
97
44
  end
98
45
 
99
- it "should create a new right" do
100
- expect(@new_right.name).to eq "tickets@destroy"
101
- expect(@new_right.controller).to eq "tickets"
102
- expect(@new_right.action).to eq "destroy"
46
+ it 'should create a new right' do
47
+ expect(@new_right.name).to eq 'tickets@destroy'
48
+ expect(@new_right.controller).to eq 'tickets'
49
+ expect(@new_right.action).to eq 'destroy'
103
50
  expect(@new_right.save).to eq true
104
51
  end
105
52
  end
106
53
 
107
- describe RightOn::Right, "with only a name" do
54
+ describe RightOn::Right, 'with only a name' do
108
55
  before do
109
- @new_right = RightOn::Right.new(:name => "tickets2")
56
+ @new_right = RightOn::Right.new(name: 'tickets2')
110
57
  end
111
58
 
112
- it "should create a new right" do
59
+ it 'should create a new right' do
113
60
  expect(@new_right.save).to eq true
114
61
  end
115
62
  end
116
63
 
117
- describe RightOn::Right, "with the same name" do
64
+ describe RightOn::Right, 'with the same name' do
118
65
  before do
119
- @old_right = RightOn::Right.new(:name => "tickets3", :controller => "tickets")
66
+ @old_right = RightOn::Right.new(name: 'tickets3', controller: 'tickets')
120
67
  @old_right.save!
121
- @new_right = RightOn::Right.new(:name => "tickets3", :controller => "tickets")
68
+ @new_right = RightOn::Right.new(name: 'tickets3', controller: 'tickets')
122
69
  end
123
70
 
124
- it "should not create a new right" do
71
+ it 'should not create a new right' do
125
72
  expect(@new_right.save).to eq false
126
73
  end
127
74
  end
128
75
 
129
- describe RightOn::Role, "can have many rights" do
130
- let(:role1) { RightOn::Role.new(:title => 'role 1') }
76
+ describe RightOn::Role, 'can have many rights' do
77
+ let(:role1) { RightOn::Role.new(title: 'role 1') }
131
78
 
132
79
  specify { expect(role1.to_s).to eq 'Role 1' }
133
80
 
134
81
  context 'when assigned rights' do
135
- let(:right1) { RightOn::Right.create!(:name => 'right 1') }
136
- let(:right2) { RightOn::Right.create!(:name => 'right 2') }
82
+ let(:right1) { RightOn::Right.create!(name: 'right 1') }
83
+ let(:right2) { RightOn::Right.create!(name: 'right 2') }
137
84
 
138
85
  before do
139
86
  role1.save!
@@ -146,45 +93,10 @@ describe RightOn::Role, "can have many rights" do
146
93
  right2.destroy
147
94
  end
148
95
 
149
- it "should have and belong to many" do
96
+ it 'should have and belong to many' do
150
97
  expect(role1.rights.size).to eq 2
151
98
  expect(right1.roles.size).to eq 1
152
99
  expect(right2.roles.size).to eq 1
153
100
  end
154
101
  end
155
102
  end
156
-
157
- describe 'when checking accessibility to a controller' do
158
-
159
- let(:test_controller_right) { RightOn::Right.new(name: 'test', controller: 'test') }
160
- let(:user) { double(rights: [test_controller_right]) }
161
- let(:controller) { 'test' }
162
- let(:action) { 'index' }
163
- let(:params) { {controller: 'test', action: 'index'} }
164
-
165
- before do
166
- stub_const 'TestController', double(current_user: user, params: params)
167
- TestController.extend RightOn::ActionControllerExtensions
168
- allow(TestController).to receive(:rights_from).and_return(nil)
169
- end
170
-
171
- specify { expect(TestController.access_allowed?(controller)).to be_truthy }
172
- specify { expect(TestController.access_allowed?('other')).to be_falsey }
173
- specify { expect(TestController.access_allowed_to_controller?(controller)).to be_truthy }
174
- specify { expect(TestController.access_allowed_to_controller?('other')).to be_falsey }
175
-
176
- describe 'when inheriting rights' do
177
- let(:controller) { 'test_inherited' }
178
-
179
- before do
180
- stub_const 'TestInheritedController', double(current_user: user, params: params)
181
- TestInheritedController.extend RightOn::ActionControllerExtensions
182
- allow(TestInheritedController).to receive(:rights_from).and_return(:test)
183
- end
184
-
185
- specify { expect(TestInheritedController.access_allowed?(controller)).to be_falsey }
186
- specify { expect(TestInheritedController.access_allowed?('other')).to be_falsey }
187
- specify { expect(TestInheritedController.access_allowed_to_controller?(controller)).to be_truthy }
188
- specify { expect(TestInheritedController.access_allowed_to_controller?('other')).to be_falsey }
189
- end
190
- end