mongoid_ability 1.0.0 → 2.0.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +7 -0
  4. data/README.md +55 -23
  5. data/lib/cancancan/model_adapters/mongoid_adapter.rb +156 -0
  6. data/lib/cancancan/model_additions.rb +30 -0
  7. data/lib/mongoid_ability.rb +12 -12
  8. data/lib/mongoid_ability/ability.rb +67 -26
  9. data/lib/mongoid_ability/find_lock.rb +71 -0
  10. data/lib/mongoid_ability/lock.rb +25 -16
  11. data/lib/mongoid_ability/locks_decorator.rb +45 -0
  12. data/lib/mongoid_ability/owner.rb +23 -3
  13. data/lib/mongoid_ability/subject.rb +10 -22
  14. data/lib/mongoid_ability/version.rb +1 -1
  15. data/test/cancancan/model_adapters/mongoid_adapter_options_test.rb +102 -0
  16. data/test/cancancan/model_adapters/mongoid_adapter_test.rb +207 -0
  17. data/test/mongoid_ability/ability_basic_benchmark.rb +30 -0
  18. data/test/mongoid_ability/ability_basic_test.rb +44 -13
  19. data/test/mongoid_ability/ability_marshal_test.rb +17 -0
  20. data/test/mongoid_ability/ability_options_test.rb +93 -0
  21. data/test/mongoid_ability/ability_test.rb +87 -106
  22. data/test/mongoid_ability/find_lock_test.rb +67 -0
  23. data/test/mongoid_ability/lock_test.rb +32 -40
  24. data/test/mongoid_ability/owner_locks_test.rb +14 -21
  25. data/test/mongoid_ability/owner_test.rb +4 -14
  26. data/test/mongoid_ability/subject_test.rb +32 -58
  27. data/test/support/test_classes/my_lock.rb +8 -13
  28. data/test/support/test_classes/my_owner.rb +13 -15
  29. data/test/support/test_classes/my_role.rb +9 -11
  30. data/test/support/test_classes/my_subject.rb +16 -9
  31. data/test/test_helper.rb +12 -2
  32. metadata +18 -25
  33. data/lib/mongoid_ability/accessible_query_builder.rb +0 -64
  34. data/lib/mongoid_ability/resolve_default_locks.rb +0 -17
  35. data/lib/mongoid_ability/resolve_inherited_locks.rb +0 -35
  36. data/lib/mongoid_ability/resolve_locks.rb +0 -12
  37. data/lib/mongoid_ability/resolve_owner_locks.rb +0 -35
  38. data/lib/mongoid_ability/resolver.rb +0 -24
  39. data/lib/mongoid_ability/values_for_accessible_query.rb +0 -74
  40. data/test/mongoid_ability/ability_syntactic_sugar_test.rb +0 -32
  41. data/test/mongoid_ability/accessible_query_builder_test.rb +0 -119
  42. data/test/mongoid_ability/can_options_test.rb +0 -17
  43. data/test/mongoid_ability/resolve_default_locks_test.rb +0 -41
  44. data/test/mongoid_ability/resolve_inherited_locks_test.rb +0 -50
  45. data/test/mongoid_ability/resolve_owner_locks_test.rb +0 -56
  46. data/test/mongoid_ability/resolver_test.rb +0 -23
  47. data/test/mongoid_ability/subject_accessible_by_test.rb +0 -147
@@ -1,17 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MongoidAbility
4
- describe 'can options test' do
5
- let(:owner) { MyOwner.new }
6
- let(:ability) { Ability.new(owner) }
7
-
8
- let(:default_locks) { [MyLock1.new(action: :read, outcome: false)] }
9
-
10
- it 'allows to pass options to a can? block' do
11
- MySubject.stub :default_locks, default_locks do
12
- ability.can?(:read, MySubject, {}).must_equal false
13
- ability.can?(:read, MySubject, override: true).must_equal true
14
- end
15
- end
16
- end
17
- end
@@ -1,41 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MongoidAbility
4
- describe ResolveDefaultLocks do
5
- describe '.call' do
6
- let(:options) { {} }
7
-
8
- let(:my_subject_default_locks) do
9
- [
10
- MyLock.new(subject_type: MySubject, action: :read, outcome: true),
11
- MyLock.new(subject_type: MySubject, action: :update, outcome: false)
12
- ]
13
- end
14
-
15
- let(:my_subject_1_default_locks) do
16
- [
17
- MyLock.new(subject_type: MySubject1, action: :read, outcome: false),
18
- MyLock.new(subject_type: MySubject1, action: :update, outcome: true)
19
- ]
20
- end
21
-
22
- it 'resolves on self' do
23
- MySubject.stub :default_locks, my_subject_default_locks do
24
- MySubject1.stub :default_locks, my_subject_1_default_locks do
25
- ResolveDefaultLocks.call(nil, :read, MySubject, nil, options).must_equal MySubject.default_locks.first
26
- ResolveDefaultLocks.call(nil, :update, MySubject, nil, options).must_equal MySubject.default_locks.last
27
- end
28
- end
29
- end
30
-
31
- it 'resolves on subclass' do
32
- MySubject.stub :default_locks, my_subject_default_locks do
33
- MySubject1.stub :default_locks, my_subject_1_default_locks do
34
- ResolveDefaultLocks.call(nil, :read, MySubject1, nil, options).must_equal MySubject1.default_locks.first
35
- ResolveDefaultLocks.call(nil, :update, MySubject1, nil, options).must_equal MySubject1.default_locks.last
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,50 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MongoidAbility
4
- describe ResolveInheritedLocks do
5
- describe 'when defined on class' do
6
- let(:owner) { MyOwner.new }
7
- let(:my_subject) { MySubject.new }
8
-
9
- let(:default_locks) { [MyLock.new(subject_type: MySubject, action: :my_read, outcome: true)] }
10
-
11
- it 'returns it' do
12
- MySubject.stub :default_locks, default_locks do
13
- ResolveInheritedLocks.call(owner, :my_read, MySubject, nil).calculated_outcome.must_equal true
14
- ResolveInheritedLocks.call(owner, :my_read, MySubject, my_subject).calculated_outcome.must_equal true
15
- end
16
- end
17
-
18
- describe 'when defined on one of the inherited owners' do
19
- let(:inherited_owner_1) { MyOwner.new }
20
- let(:inherited_owner_2) { MyOwner.new }
21
- let(:owner) { MyOwner.new(my_roles: [inherited_owner_1, inherited_owner_2]) }
22
- let(:my_subject) { MySubject.new }
23
-
24
- let(:lock) { MyLock.new(action: :my_read, subject_type: MySubject, outcome: false) }
25
-
26
- before { inherited_owner_1.my_locks = [lock] }
27
-
28
- it 'returns it' do
29
- MySubject.stub :default_locks, default_locks do
30
- ResolveInheritedLocks.call(owner, :my_read, MySubject, nil).must_equal lock
31
- ResolveInheritedLocks.call(owner, :my_read, MySubject, my_subject.id).must_equal lock
32
- end
33
- end
34
-
35
- describe 'when defined on user' do
36
- let(:lock) { MyLock.new(action: :my_read, subject_type: MySubject, outcome: false) }
37
-
38
- before { owner.my_locks = [lock] }
39
-
40
- it 'returns it' do
41
- MySubject.stub :default_locks, default_locks do
42
- ResolveInheritedLocks.call(owner, :my_read, MySubject, nil).must_equal lock
43
- ResolveInheritedLocks.call(owner, :my_read, MySubject, my_subject.id).must_equal lock
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
50
- end
@@ -1,56 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MongoidAbility
4
- describe ResolveOwnerLocks do
5
- let(:owner) { MyOwner.new }
6
- let(:my_subject) { MySubject.new }
7
-
8
- subject { ResolveOwnerLocks.call(owner, :read, MySubject, nil) }
9
- let(:resolver_for_subject_id) { ResolveOwnerLocks.call(owner, :read, MySubject, my_subject.id) }
10
- let(:default_locks) { [MyLock.new(subject_type: MySubject, action: :read, outcome: false)] }
11
-
12
- describe '#lock' do
13
- describe 'no locks' do
14
- it 'must be nil' do
15
- MySubject.stub :default_locks, default_locks do
16
- subject.must_be_nil
17
- end
18
- end
19
- end
20
-
21
- describe 'id locks' do
22
- it 'returns outcome' do
23
- MySubject.stub :default_locks, default_locks do
24
- owner.my_locks = [MyLock.new(action: :read, subject: my_subject, outcome: true)]
25
- resolver_for_subject_id.calculated_outcome.must_equal true
26
- end
27
- end
28
-
29
- it 'prefers negative outcome' do
30
- MySubject.stub :default_locks, default_locks do
31
- owner.my_locks = [MyLock.new(action: :read, subject: my_subject, outcome: true),
32
- MyLock.new(action: :read, subject: my_subject, outcome: false)]
33
- resolver_for_subject_id.calculated_outcome.must_equal false
34
- end
35
- end
36
- end
37
-
38
- describe 'class locks' do
39
- it 'returns outcome' do
40
- MySubject.stub :default_locks, default_locks do
41
- owner.my_locks = [MyLock.new(action: :read, subject_type: MySubject, outcome: true)]
42
- subject.calculated_outcome.must_equal true
43
- end
44
- end
45
-
46
- it 'prefers negative outcome' do
47
- MySubject.stub :default_locks, default_locks do
48
- owner.my_locks = [MyLock.new(action: :read, subject_type: MySubject, outcome: true),
49
- MyLock.new(action: :read, subject_type: MySubject, outcome: false)]
50
- subject.calculated_outcome.must_equal false
51
- end
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,23 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MongoidAbility
4
- describe Resolver do
5
- let(:owner) { MyOwner.new }
6
-
7
- describe 'errors' do
8
- it 'raises NameError for invalid subject_type' do
9
- -> { Resolver.call(owner, :read, 'Foo') }.must_raise NameError
10
- end
11
-
12
- it 'raises StandardError when subject_type does not have default_locks' do
13
- -> { Resolver.call(owner, :read, Object) }.must_raise StandardError
14
- end
15
-
16
- it 'raises StandardError when subject_type class or its ancestors does not have default_lock' do
17
- MySubject.stub(:default_locks, []) do
18
- -> { Resolver.call(owner, :read, MySubject) }.must_raise StandardError
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,147 +0,0 @@
1
- require 'test_helper'
2
-
3
- module MongoidAbility
4
- describe '.accessible_by' do
5
- let(:my_subject) { MySubject.create! }
6
- let(:my_subject1) { MySubject1.create! }
7
- let(:my_subject2) { MySubject2.create! }
8
-
9
- let(:role_1) { MyRole.new }
10
- let(:role_2) { MyRole.new }
11
- let(:owner) { MyOwner.new(my_roles: [role_1, role_2]) }
12
- let(:ability) { Ability.new(owner) }
13
-
14
- let(:my_subject_default_locks) { [] }
15
- let(:my_subject_1_default_locks) { [] }
16
- let(:my_subject_2_default_locks) { [] }
17
-
18
- before { my_subject; my_subject1; my_subject2 }
19
-
20
- describe 'default open locks' do
21
- # NOTE: we might need to use the .default_lock macro in case we propagate down directly
22
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: true)] }
23
-
24
- it 'propagates from superclass to all subclasses' do
25
- MySubject.stub :default_locks, my_subject_default_locks do
26
- MySubject1.stub :default_locks, my_subject_1_default_locks do
27
- MySubject2.stub :default_locks, my_subject_2_default_locks do
28
- MySubject.accessible_by(ability, :update).to_a.must_include my_subject
29
- MySubject.accessible_by(ability, :update).to_a.must_include my_subject1
30
- MySubject.accessible_by(ability, :update).to_a.must_include my_subject2
31
-
32
- MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject
33
- MySubject1.accessible_by(ability, :update).to_a.must_include my_subject1
34
- MySubject1.accessible_by(ability, :update).to_a.must_include my_subject2
35
-
36
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject
37
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject1
38
- MySubject2.accessible_by(ability, :update).to_a.must_include my_subject2
39
- end
40
- end
41
- end
42
- end
43
- end
44
-
45
- describe 'default closed locks' do
46
- # NOTE: we might need to use the .default_lock macro in case we propagate down directly
47
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: false)] }
48
-
49
- it 'propagates from superclass to all subclasses' do
50
- MySubject.stub :default_locks, my_subject_default_locks do
51
- MySubject1.stub :default_locks, my_subject_1_default_locks do
52
- MySubject2.stub :default_locks, my_subject_2_default_locks do
53
- MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
54
- MySubject.accessible_by(ability, :update).to_a.wont_include my_subject1
55
- MySubject.accessible_by(ability, :update).to_a.wont_include my_subject2
56
-
57
- MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject
58
- MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject1
59
- MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject2
60
-
61
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject
62
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject1
63
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject2
64
- end
65
- end
66
- end
67
- end
68
- end
69
-
70
- describe 'default combined locks' do
71
- # NOTE: we might need to use the .default_lock macro in case we propagate down directly
72
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: false)] }
73
- let(:my_subject_1_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: true)] }
74
- let(:my_subject_2_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: false)] }
75
-
76
- it 'propagates from superclass to all subclasses' do
77
- MySubject.stub :default_locks, my_subject_default_locks do
78
- MySubject1.stub :default_locks, my_subject_1_default_locks do
79
- MySubject2.stub :default_locks, my_subject_2_default_locks do
80
- MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
81
- MySubject.accessible_by(ability, :update).to_a.must_include my_subject1
82
- MySubject.accessible_by(ability, :update).to_a.wont_include my_subject2
83
-
84
- MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject
85
- MySubject1.accessible_by(ability, :update).to_a.must_include my_subject1
86
- MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject2
87
-
88
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject
89
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject1
90
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject2
91
- end
92
- end
93
- end
94
- end
95
- end
96
-
97
- describe 'closed id locks' do
98
- let(:role_1) { MyRole.new(my_locks: [MyLock.new(subject: my_subject, action: :update, outcome: false)]) }
99
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: true)] }
100
-
101
- it 'applies id locks' do
102
- MySubject.stub :default_locks, my_subject_default_locks do
103
- MySubject1.stub :default_locks, my_subject_1_default_locks do
104
- MySubject2.stub :default_locks, my_subject_2_default_locks do
105
- MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
106
- MySubject.accessible_by(ability, :update).to_a.must_include my_subject1
107
- MySubject.accessible_by(ability, :update).to_a.must_include my_subject2
108
- end
109
- end
110
- end
111
- end
112
- end
113
-
114
- describe 'open id locks' do
115
- let(:role_1) { MyRole.new(my_locks: [MyLock.new(subject: my_subject1, action: :update, outcome: true)]) }
116
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: false)] }
117
-
118
- it 'applies id locks' do
119
- MySubject.stub :default_locks, my_subject_default_locks do
120
- MySubject1.stub :default_locks, my_subject_1_default_locks do
121
- MySubject2.stub :default_locks, my_subject_2_default_locks do
122
- MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
123
- MySubject1.accessible_by(ability, :update).to_a.must_include my_subject1
124
- MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject2
125
- end
126
- end
127
- end
128
- end
129
- end
130
-
131
- describe 'prefix' do
132
- let(:prefix) { :subject }
133
- let(:my_subject_default_locks) { [MyLock.new(subject_type: MySubject, action: :update, outcome: true)] }
134
-
135
- it 'allows to pass prefix' do
136
- MySubject.stub :default_locks, my_subject_default_locks do
137
- MySubject1.stub :default_locks, my_subject_1_default_locks do
138
- MySubject2.stub :default_locks, my_subject_2_default_locks do
139
- selector = MySubject.accessible_by(ability, :update, prefix: prefix).selector
140
- selector.must_equal('$and' => [{ '$or' => [{ "#{prefix}_type" => { '$nin' => [] } }, { "#{prefix}_type" => { '$in' => [] }, "#{prefix}_id" => { '$in' => [] } }] }, { "#{prefix}_id" => { '$nin' => [] } }])
141
- end
142
- end
143
- end
144
- end
145
- end
146
- end
147
- end