mongoid_ability 0.0.11 → 0.1.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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -13
  3. data/lib/mongoid_ability.rb +8 -2
  4. data/lib/mongoid_ability/ability.rb +32 -30
  5. data/lib/mongoid_ability/accessible_query_builder.rb +61 -41
  6. data/lib/mongoid_ability/lock.rb +16 -29
  7. data/lib/mongoid_ability/owner.rb +6 -22
  8. data/lib/mongoid_ability/resolve_default_locks.rb +15 -0
  9. data/lib/mongoid_ability/resolve_inherited_locks.rb +32 -0
  10. data/lib/mongoid_ability/resolve_locks.rb +34 -0
  11. data/lib/mongoid_ability/resolve_owner_locks.rb +25 -0
  12. data/lib/mongoid_ability/subject.rb +28 -32
  13. data/lib/mongoid_ability/version.rb +1 -1
  14. data/test/mongoid_ability/ability_role_test.rb +11 -5
  15. data/test/mongoid_ability/ability_test.rb +67 -91
  16. data/test/mongoid_ability/accessible_query_builder_test.rb +9 -5
  17. data/test/mongoid_ability/can_options_test.rb +17 -0
  18. data/test/mongoid_ability/lock_test.rb +51 -70
  19. data/test/mongoid_ability/owner_locks_test.rb +42 -0
  20. data/test/mongoid_ability/owner_test.rb +12 -39
  21. data/test/mongoid_ability/resolve_default_locks_test.rb +27 -0
  22. data/test/mongoid_ability/resolve_inherited_locks_test.rb +49 -0
  23. data/test/mongoid_ability/resolve_locks_test.rb +25 -0
  24. data/test/mongoid_ability/resolve_owner_locks_test.rb +50 -0
  25. data/test/mongoid_ability/subject_accessible_by_test.rb +135 -0
  26. data/test/mongoid_ability/subject_test.rb +20 -201
  27. data/test/support/test_classes.rb +136 -61
  28. data/test/test_helper.rb +3 -2
  29. metadata +20 -5
  30. data/lib/mongoid_ability/ability_resolver.rb +0 -42
  31. data/test/mongoid_ability/ability_resolver_test.rb +0 -78
@@ -3,18 +3,22 @@ require "test_helper"
3
3
  module MongoidAbility
4
4
  describe AccessibleQueryBuilder do
5
5
 
6
- let(:base_class) { SubjectTest }
7
-
8
- let(:user) { TestUser.new }
9
- let(:ability) { Ability.new(user) }
6
+ let(:base_class) { MySubject }
7
+
8
+ let(:owner) { MyOwner.new }
9
+ let(:ability) { Ability.new(owner) }
10
10
 
11
11
  let(:action) { :read }
12
12
 
13
13
  subject { AccessibleQueryBuilder.call(base_class, ability, action) }
14
14
 
15
+ before do
16
+ MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: false) ]
17
+ end
18
+
15
19
  it 'returns Mongoid::Criteria' do
16
20
  subject.must_be_kind_of Mongoid::Criteria
17
21
  end
18
22
 
19
23
  end
20
- end
24
+ end
@@ -0,0 +1,17 @@
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
+ before do
9
+ MySubject.default_locks = [ MyLock1.new(action: :read, outcome: false) ]
10
+ end
11
+
12
+ it 'allows to pass options to a can? block' do
13
+ ability.can?(:read, MySubject, {}).must_equal false
14
+ ability.can?(:read, MySubject, { override: true }).must_equal true
15
+ end
16
+ end
17
+ end
@@ -3,92 +3,73 @@ require 'test_helper'
3
3
  module MongoidAbility
4
4
  describe Lock do
5
5
 
6
- let(:subject_test) { SubjectTest.new }
7
- subject { TestLock.new }
8
-
9
- # =====================================================================
10
-
11
- describe 'fields' do
12
- it 'has :action' do
13
- subject.must_respond_to :action
14
- subject.action.must_be_kind_of Symbol
15
- end
6
+ subject { MyLock.new }
7
+ let(:my_subject) { MySubject.new }
8
+ let(:inherited_lock) { MyLock1.new }
16
9
 
17
- it 'has :outcome' do
18
- subject.must_respond_to :outcome
19
- subject.outcome.must_equal false
20
- end
21
- end
10
+ # ---------------------------------------------------------------------
22
11
 
23
- # =====================================================================
24
-
25
- describe 'associations' do
26
- it 'embedded in :owner' do
27
- subject.must_respond_to :owner
28
- subject.relations['owner'].macro.must_equal :embedded_in
29
- end
12
+ it { subject.must_respond_to :action }
13
+ it { subject.must_respond_to :outcome }
14
+ it { subject.must_respond_to :subject }
15
+ it { subject.must_respond_to :subject_id }
16
+ it { subject.must_respond_to :subject_type }
17
+ it { subject.must_respond_to :owner }
30
18
 
31
- it 'belongs to :subject' do
32
- subject.must_respond_to :subject
33
- subject.must_respond_to :subject_type
34
- subject.must_respond_to :subject_id
35
- end
19
+ # ---------------------------------------------------------------------
20
+
21
+ it '#open?' do
22
+ subject.must_respond_to :open?
23
+ subject.open?.must_equal false
24
+ end
25
+ it '#closed?' do
26
+ subject.must_respond_to :closed?
27
+ subject.closed?.must_equal true
28
+ end
29
+ it '#class_lock?' do
30
+ subject.must_respond_to :class_lock?
31
+ end
32
+ it '#id_lock?' do
33
+ subject.must_respond_to :id_lock?
36
34
  end
37
-
38
- # =====================================================================
39
35
 
40
- describe 'instance methods' do
41
- it 'has #open?' do
42
- subject.must_respond_to :open?
43
- subject.open?.must_equal false
44
- end
45
- it 'has #closed?' do
46
- subject.must_respond_to :closed?
47
- subject.closed?.must_equal true
48
- end
49
- it 'has #class_lock?' do
50
- subject.must_respond_to :class_lock?
51
- end
52
- it 'has #id_lock?' do
53
- subject.must_respond_to :id_lock?
54
- end
36
+ # ---------------------------------------------------------------------
55
37
 
56
- describe '#criteria' do
57
- let(:open_subject_type_lock) { TestLock.new(subject_type: subject_test.class.to_s, action: :read, outcome: true) }
58
- let(:closed_subject_type_lock) { TestLock.new(subject_type: subject_test.class.to_s, action: :read, outcome: false) }
38
+ describe '#criteria' do
39
+ let(:open_subject_type_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
40
+ let(:closed_subject_type_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
59
41
 
60
- let(:open_subject_lock) { TestLock.new(subject: subject_test, action: :read, outcome: true) }
61
- let(:closed_subject_lock) { TestLock.new(subject: subject_test, action: :read, outcome: false) }
42
+ let(:open_subject_lock) { MyLock.new(subject: my_subject, action: :read, outcome: true) }
43
+ let(:closed_subject_lock) { MyLock.new(subject: my_subject, action: :read, outcome: false) }
62
44
 
63
- it 'returns conditions Hash' do
64
- open_subject_type_lock.conditions.must_be_kind_of Hash
65
- closed_subject_type_lock.conditions.must_be_kind_of Hash
45
+ it 'returns conditions Hash' do
46
+ open_subject_type_lock.conditions.must_be_kind_of Hash
47
+ closed_subject_type_lock.conditions.must_be_kind_of Hash
66
48
 
67
- open_subject_lock.conditions.must_be_kind_of Hash
68
- closed_subject_lock.conditions.must_be_kind_of Hash
69
- end
49
+ open_subject_lock.conditions.must_be_kind_of Hash
50
+ closed_subject_lock.conditions.must_be_kind_of Hash
51
+ end
70
52
 
71
- describe 'when open' do
72
- it 'includes subject_type' do
73
- open_subject_type_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type })
74
- end
53
+ describe 'when open' do
54
+ it 'includes subject_type' do
55
+ open_subject_type_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type })
56
+ end
75
57
 
76
- it 'includes id' do
77
- open_subject_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id })
78
- end
58
+ it 'includes id' do
59
+ open_subject_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id })
79
60
  end
61
+ end
80
62
 
81
- describe 'when closed' do
82
- it 'excludes subject_type' do
83
- closed_subject_type_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type }})
84
- end
63
+ describe 'when closed' do
64
+ it 'excludes subject_type' do
65
+ closed_subject_type_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type }})
66
+ end
85
67
 
86
- it 'includes id' do
87
- closed_subject_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id }})
88
- end
68
+ it 'includes id' do
69
+ closed_subject_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id }})
89
70
  end
90
71
  end
91
72
  end
92
73
 
93
74
  end
94
- end
75
+ end
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+
3
+ module MongoidAbility
4
+ describe 'owner locks test' do
5
+ subject { MySubject.new }
6
+
7
+ let(:subject_lock) { MyLock.new(action: :read, subject: subject, outcome: false) }
8
+ let(:subject_type_lock) { MyLock.new(action: :read, subject_type: subject.class, outcome: false) }
9
+
10
+ let(:owner) { MyOwner.new }
11
+ let(:ability) { Ability.new(owner) }
12
+
13
+ # ---------------------------------------------------------------------
14
+
15
+ before do
16
+ MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: true) ]
17
+ end
18
+
19
+ # ---------------------------------------------------------------------
20
+
21
+ describe 'when lock for subject' do
22
+ before { owner.my_locks = [ subject_lock ] }
23
+
24
+ it 'applies it' do
25
+ ability.can?(:read, subject.class).must_equal true
26
+ ability.can?(:read, subject).must_equal false
27
+ end
28
+ end
29
+
30
+ # ---------------------------------------------------------------------
31
+
32
+ describe 'when lock for subject type' do
33
+ before { owner.my_locks = [ subject_type_lock ] }
34
+
35
+ it 'applies it' do
36
+ ability.can?(:read, subject.class).must_equal false
37
+ ability.can?(:read, subject).must_equal false
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -2,52 +2,25 @@ require 'test_helper'
2
2
 
3
3
  module MongoidAbility
4
4
  describe Owner do
5
+ subject { MyOwner.new }
5
6
 
6
- subject { TestOwner.new }
7
+ describe '#cleanup_locks' do
8
+ let(:closed_lock) { MyLock.new(action: :read, outcome: false, subject_type: Object.to_s) }
9
+ let(:open_lock) { MyLock1.new(action: :read, outcome: true, subject_type: Object.to_s) }
7
10
 
8
- # =====================================================================
9
-
10
- describe 'fields' do
11
- end
12
-
13
- # =====================================================================
14
-
15
- describe 'associations' do
16
- end
17
-
18
- # =====================================================================
19
-
20
- describe 'class methods' do
21
- describe 'lock_class_name' do
22
- it 'finds class that includes the MongoidAbility::Lock module' do
23
- TestOwner.lock_class_name.must_equal 'TestLock'
24
- end
11
+ before do
12
+ subject.my_locks = [open_lock, closed_lock].shuffle
13
+ subject.run_callbacks(:save)
25
14
  end
26
15
 
27
- describe 'locks_relation_name' do
28
- it 'finds the name of relation that contains locks' do
29
- TestOwner.locks_relation_name.must_equal :test_locks
30
- end
16
+ it 'prefers closed locks' do
17
+ subject.my_locks.sort.must_equal [closed_lock].sort
31
18
  end
32
- end
33
-
34
- # =====================================================================
35
19
 
36
- describe 'instance methods' do
37
- describe 'cleanup_locks' do
38
- let(:closed_lock) { TestLock.new(action: :read, outcome: false, subject_type: Object.to_s) }
39
- let(:open_lock) { TestLock.new(action: :read, outcome: true, subject_type: Object.to_s) }
40
-
41
- before do
42
- subject.test_locks = [open_lock, closed_lock].shuffle
43
- subject.run_callbacks(:save)
44
- end
45
-
46
- it 'prefers closed locks' do
47
- subject.test_locks.sort.must_equal [closed_lock].sort
48
- end
20
+ describe 'locks relation' do
21
+ it { subject.class.locks_relation_name.must_equal :my_locks }
22
+ it { subject.locks_relation.metadata[:name].must_equal :my_locks }
49
23
  end
50
24
  end
51
-
52
25
  end
53
26
  end
@@ -0,0 +1,27 @@
1
+ require "test_helper"
2
+
3
+ module MongoidAbility
4
+ describe ResolveDefaultLocks do
5
+
6
+ describe '.call' do
7
+ before do
8
+ MySubject.default_locks = [
9
+ MyLock.new(subject_type: MySubject, action: :read, outcome: true),
10
+ MyLock.new(subject_type: MySubject, action: :update, outcome: false)
11
+ ]
12
+
13
+ MySubject1.default_locks = [
14
+ MyLock.new(subject_type: MySubject1, action: :read, outcome: false),
15
+ MyLock.new(subject_type: MySubject1, action: :update, outcome: true)
16
+ ]
17
+ end
18
+
19
+ it { ResolveDefaultLocks.call(nil, :read, MySubject, nil, {}).must_equal true }
20
+ it { ResolveDefaultLocks.call(nil, :update, MySubject, nil, {}).must_equal false }
21
+
22
+ it { ResolveDefaultLocks.call(nil, :read, MySubject1, nil, {}).must_equal false }
23
+ it { ResolveDefaultLocks.call(nil, :update, MySubject1, nil, {}).must_equal true }
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,49 @@
1
+ require "test_helper"
2
+
3
+ module MongoidAbility
4
+ describe ResolveInheritedLocks do
5
+
6
+ describe 'when defined on class' do
7
+ let(:owner) { MyOwner.new }
8
+ let(:my_subject) { MySubject.new }
9
+
10
+ before { MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :my_read, outcome: true) ] }
11
+
12
+ # ---------------------------------------------------------------------
13
+
14
+ it 'returns it' do
15
+ ResolveInheritedLocks.call(owner, :my_read, MySubject, nil).must_equal true
16
+ ResolveInheritedLocks.call(owner, :my_read, MySubject, my_subject).must_equal true
17
+ end
18
+
19
+ # ---------------------------------------------------------------------
20
+
21
+ describe 'when defined on one of the inherited owners' do
22
+ let(:inherited_owner_1) { MyOwner.new }
23
+ let(:inherited_owner_2) { MyOwner.new }
24
+ let(:owner) { MyOwner.new(my_roles: [inherited_owner_1, inherited_owner_2]) }
25
+ let(:my_subject) { MySubject.new }
26
+
27
+ before { inherited_owner_1.my_locks = [ MyLock.new(action: :my_read, subject_type: MySubject, outcome: false) ] }
28
+
29
+ it 'returns it' do
30
+ ResolveInheritedLocks.call(owner, :my_read, MySubject, nil).must_equal false
31
+ ResolveInheritedLocks.call(owner, :my_read, MySubject, my_subject).must_equal false
32
+ end
33
+
34
+ # ---------------------------------------------------------------------
35
+
36
+ describe 'when defined on user' do
37
+ before { owner.my_locks = [ MyLock.new(action: :my_read, subject_type: MySubject, outcome: true) ] }
38
+
39
+ it 'returns it' do
40
+ ResolveInheritedLocks.call(owner, :my_read, MySubject, nil).must_equal true
41
+ ResolveInheritedLocks.call(owner, :my_read, MySubject, my_subject).must_equal true
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ module MongoidAbility
4
+ describe ResolveLocks do
5
+
6
+ let(:owner) { MyOwner.new }
7
+
8
+ describe 'errors' do
9
+ it 'raises NameError for invalid subject_type' do
10
+ -> { ResolveLocks.call(owner, :read, 'Foo') }.must_raise NameError
11
+ end
12
+
13
+ it 'raises StandardError when subject_type does not have default_locks' do
14
+ -> { ResolveLocks.call(owner, :read, Object) }.must_raise StandardError
15
+ end
16
+
17
+ it 'raises StandardError when subject_type class or its ancestors does not have default_lock' do
18
+ MySubject.stub(:default_locks, []) do
19
+ -> { ResolveLocks.call(owner, :read, MySubject) }.must_raise StandardError
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,50 @@
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) }
10
+
11
+ # =====================================================================
12
+
13
+ describe '#outcome' do
14
+ before do
15
+ MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: false) ]
16
+ end
17
+
18
+ describe 'no locks' do
19
+ it { subject.must_be_nil }
20
+ end
21
+
22
+ describe 'id locks' do
23
+ it 'returns outcome' do
24
+ owner.my_locks = [ MyLock.new(action: :read, subject: my_subject, outcome: true) ]
25
+ resolver_for_subject_id.must_equal true
26
+ end
27
+
28
+ it 'prefers negative outcome' do
29
+ owner.my_locks = [ MyLock.new(action: :read, subject: my_subject, outcome: true),
30
+ MyLock.new(action: :read, subject: my_subject, outcome: false) ]
31
+ resolver_for_subject_id.must_equal false
32
+ end
33
+ end
34
+
35
+ describe 'class locks' do
36
+ it 'returns outcome' do
37
+ owner.my_locks = [ MyLock.new(action: :read, subject_type: MySubject, outcome: true) ]
38
+ subject.must_equal true
39
+ end
40
+
41
+ it 'prefers negative outcome' do
42
+ owner.my_locks = [ MyLock.new(action: :read, subject_type: MySubject, outcome: true),
43
+ MyLock.new(action: :read, subject_type: MySubject, outcome: false) ]
44
+ subject.must_equal false
45
+ end
46
+ end
47
+ end
48
+
49
+ end
50
+ end