mongoid_ability 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f40f0a70a06a2ef26a9e545cd18a940cd46e4be5
4
- data.tar.gz: 0f105daba66547732f737fb1928ab7615d2e9162
3
+ metadata.gz: 75dab60ffb6d4f20fcf4f7eedbf2c9e1768fde5b
4
+ data.tar.gz: 60f054142c90df34356e269c0cd5209181077da7
5
5
  SHA512:
6
- metadata.gz: c74b4310a0a87557bd113f71b067116137a3b9f6f09d0804ed3fb4757f6c090887520c2cedaac882c60e96cfbc76ee96e7e29193cf08d32a13952a55c3bd1215
7
- data.tar.gz: 999a48cd89887c46366621f781a359208db66cd50fc512aeee4c812c52556d20abf6c4628852a59274fd83c4782f4f46c792b7efe157d03da2a0e73c4c0702e3
6
+ metadata.gz: f2c5bd37edba18e8ed18a133267810c0f99674c28de0269d5cec2bfc3c2637d2317d84031cf02f3ee3dcf2572f25c61715820420f839ae1b22f5d1fe783cba26
7
+ data.tar.gz: bc0373e909e72bee1afb5dbbfd0b3715c1e7581baf8e50527fbf859268d20165b3eb2d20b46fcb4cdab9c80642c65c7a42de6e52b565e3c0363a11cc348e184b
@@ -24,8 +24,8 @@ module MongoidAbility
24
24
  scope :for_subject_id, -> subject_id { where(subject_id: subject_id) }
25
25
  scope :for_subject, -> subject { where(subject_type: subject.class.model_name, subject_id: subject.id) }
26
26
 
27
- scope :class_locks, -> { ne(subject_type: nil).where(subject_id: nil) }
28
- scope :id_locks, -> { ne(subject_type: nil, subject_id: nil) }
27
+ scope :class_locks, -> { where(subject_id: nil) }
28
+ scope :id_locks, -> { ne(subject_id: nil) }
29
29
  end
30
30
  end
31
31
 
@@ -60,5 +60,14 @@ module MongoidAbility
60
60
  self.subject_id.present?
61
61
  end
62
62
 
63
+ # ---------------------------------------------------------------------
64
+
65
+ def conditions
66
+ res = { _type: subject_type }
67
+ res = res.merge(_id: subject_id) if subject_id.present?
68
+ res = { '$not' => res } if calculated_outcome == false
69
+ res
70
+ end
71
+
63
72
  end
64
73
  end
@@ -23,7 +23,7 @@ module MongoidAbility
23
23
  end
24
24
 
25
25
  # ---------------------------------------------------------------------
26
-
26
+
27
27
  # override if needed
28
28
  # return for example 'MyLock'
29
29
  def lock_class_name
@@ -31,7 +31,7 @@ module MongoidAbility
31
31
  end
32
32
 
33
33
  # ---------------------------------------------------------------------
34
-
34
+
35
35
  def self_and_ancestors_with_default_locks
36
36
  self.ancestors.select{ |a| a.is_a?(Class) && a.respond_to?(:default_locks) }
37
37
  end
@@ -41,40 +41,54 @@ module MongoidAbility
41
41
  end
42
42
 
43
43
  # ---------------------------------------------------------------------
44
-
44
+
45
+ # TODO: obviously this could be cleaner
45
46
  def accessible_by ability, action=:read
46
47
  cr = self.criteria
47
48
 
48
49
  return cr unless ability.user.present?
49
50
 
50
- id_locks = [
51
- ability.user,
52
- ability.user.roles_relation
53
- ].flatten.collect { |owner|
54
- owner.locks_relation.for_subject_type(self.to_s).id_locks.for_action(action).to_a
55
- }.flatten
56
-
57
- if ability.can?(action, self)
58
- cr.nin({
59
- _id: id_locks.map(&:subject_id).select do |subject_id|
60
- subject = self.new
61
- subject.id = subject_id
62
- ability.cannot?(action, subject)
63
- end
64
- })
65
- else
66
- cr.in({
67
- _id: id_locks.map(&:subject_id).select do |subject_id|
68
- subject = self.new
69
- subject.id = subject_id
70
- ability.can?(action, subject)
71
- end
72
- })
51
+ supercls = self.ancestors_with_default_locks.last || self
52
+ subject_classes = [supercls].concat(supercls.subclasses)
53
+
54
+ subject_classes.each do |cls|
55
+
56
+ roles_id_locks = ability.user.roles_relation.collect{ |role| role.locks_relation.for_subject_type(cls.to_s).id_locks.for_action(action) }.flatten
57
+ user_id_locks = ability.user.locks_relation.for_subject_type(cls.to_s).id_locks.for_action(action)
58
+
59
+ closed_roles_id_locks = roles_id_locks.to_a.select(&:closed?)
60
+ open_roles_id_locks = roles_id_locks.to_a.select(&:open?)
61
+
62
+ closed_user_id_locks = user_id_locks.to_a.select(&:closed?)
63
+ open_user_id_locks = user_id_locks.to_a.select(&:open?)
64
+
65
+ if ability.can?(action, cls)
66
+ excluded_ids = []
67
+
68
+ id_locks = closed_roles_id_locks.
69
+ reject{ |cl| open_roles_id_locks.any?{ |ol| ol.subject_id == cl.subject_id } }.
70
+ reject{ |cl| open_user_id_locks.any?{ |ol| ol.subject_id == cl.subject_id } }
71
+
72
+ id_locks += closed_user_id_locks
73
+
74
+ excluded_ids << id_locks.map(&:subject_id)
75
+
76
+ cr = cr.or(_type: cls.to_s, :_id.nin => excluded_ids.flatten)
77
+ else
78
+ included_ids = []
79
+
80
+ id_locks = open_roles_id_locks
81
+ id_locks += open_user_id_locks
82
+
83
+ included_ids << id_locks.map(&:subject_id)
84
+
85
+ cr = cr.or(_type: cls.to_s, :_id.in => included_ids.flatten)
86
+ end
73
87
  end
88
+
89
+ cr
74
90
  end
75
91
  end
76
92
 
77
- # =====================================================================
78
-
79
93
  end
80
94
  end
@@ -1,3 +1,3 @@
1
1
  module MongoidAbility
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -3,6 +3,7 @@ require 'test_helper'
3
3
  module MongoidAbility
4
4
  describe Lock do
5
5
 
6
+ let(:subject_test) { SubjectTest.new }
6
7
  subject { TestLock.new }
7
8
 
8
9
  # =====================================================================
@@ -51,6 +52,42 @@ module MongoidAbility
51
52
  it 'has #id_lock?' do
52
53
  subject.must_respond_to :id_lock?
53
54
  end
55
+
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) }
59
+
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) }
62
+
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
66
+
67
+ open_subject_lock.conditions.must_be_kind_of Hash
68
+ closed_subject_lock.conditions.must_be_kind_of Hash
69
+ end
70
+
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
75
+
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
79
+ end
80
+
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
85
+
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
89
+ end
90
+ end
54
91
  end
55
92
 
56
93
  end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  module MongoidAbility
4
4
  describe Subject do
5
5
 
6
- def default_lock subject_cls, outcome
6
+ def subject_type_lock subject_cls, outcome
7
7
  TestLock.new(subject_type: subject_cls.to_s, action: :read, outcome: outcome)
8
8
  end
9
9
 
@@ -13,18 +13,19 @@ module MongoidAbility
13
13
 
14
14
  # ---------------------------------------------------------------------
15
15
 
16
- subject { TestSubject.new }
16
+ subject { SubjectTest.new }
17
17
 
18
- let(:subject_test_1) { TestSubject.create! }
19
- let(:subject_test_2) { TestSubject.create! }
18
+ let(:subject_test_1) { SubjectTestOne.create! }
19
+ let(:subject_test_2) { SubjectTestTwo.create! }
20
20
 
21
- let(:subject_super) { TestSubjectSuper.new }
21
+ # let(:embedded_test_subject_1) { EmbeddedTestSubject.new }
22
+ # let(:embedded_test_subject_2) { EmbeddedTestSubjectTwo.new }
23
+ # let(:embedded_test_subject_owner) { EmbeddedTestSubjectOwner.new(embedded_test_subjects: [ embedded_test_subject_1, embedded_test_subject_2 ]) }
22
24
 
23
- let(:embedded_test_subject_1) { EmbeddedTestSubject.new }
24
- let(:embedded_test_subject_2) { EmbeddedTestSubject.new }
25
- let(:embedded_test_subject_owner) { EmbeddedTestSubjectOwner.new(embedded_test_subjects: [ embedded_test_subject_1, embedded_test_subject_2 ]) }
25
+ let(:role_1) { TestRole.new }
26
+ let(:role_2) { TestRole.new }
26
27
 
27
- let(:user) { TestUser.new }
28
+ let(:user) { TestUser.new(roles: [role_1, role_2]) }
28
29
  let(:ability) { Ability.new(user) }
29
30
 
30
31
  # =====================================================================
@@ -53,131 +54,143 @@ module MongoidAbility
53
54
 
54
55
  describe '.ancestors_with_default_locks' do
55
56
  it 'lists ancestors with default locks' do
56
- subject.class.ancestors_with_default_locks.must_equal [TestSubjectSuper]
57
+ subject_test_1.class.ancestors_with_default_locks.must_equal [subject.class]
57
58
  end
58
59
  end
59
60
 
60
61
  describe '.self_and_ancestors_with_default_locks' do
61
62
  it 'lists self and ancestors with default locks' do
62
- subject.class.self_and_ancestors_with_default_locks.must_equal [TestSubject, TestSubjectSuper]
63
+ subject_test_1.class.self_and_ancestors_with_default_locks.must_equal [subject_test_1.class, subject.class]
63
64
  end
64
65
  end
65
66
 
66
67
  # =====================================================================
67
68
 
68
69
  describe '.accessible_by' do
70
+ before do
71
+ subject_test_1
72
+ subject_test_2
73
+ end
69
74
 
70
75
  it 'returns Mongoid::Criteria' do
71
76
  subject.class.accessible_by(ability).must_be_kind_of Mongoid::Criteria
72
- embedded_test_subject_1.class.accessible_by(ability).must_be_kind_of Mongoid::Criteria
77
+ # embedded_test_subject_1.class.accessible_by(ability).must_be_kind_of Mongoid::Criteria
73
78
  end
74
79
 
75
- describe 'embedded relations' do
76
- it 'returns correct criteria type' do
77
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).embedded?.must_equal true
78
- end
79
- end
80
+ # describe 'embedded relations' do
81
+ # it 'returns correct criteria type' do
82
+ # embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).embedded?.must_equal true
83
+ # end
84
+ # end
80
85
 
81
86
  # ---------------------------------------------------------------------
82
87
 
83
88
  describe 'default locks' do
84
89
  describe 'referenced relations' do
85
90
  it 'returns everything when open' do
86
- subject_test_1
87
- subject_test_2
88
-
89
- subject.class.stub(:default_locks, [ default_lock(subject_test_1.class, true) ]) do
91
+ subject.class.stub(:default_locks, [ subject_type_lock(subject.class, true) ]) do
90
92
  subject.class.accessible_by(ability).must_include subject_test_1
91
93
  subject.class.accessible_by(ability).must_include subject_test_2
92
94
  end
93
95
  end
94
96
 
95
97
  it 'returns nothing when closed' do
96
- subject.class.stub(:default_locks, [ default_lock(subject_test_1.class, false) ]) do
98
+ subject.class.stub(:default_locks, [ subject_type_lock(subject.class, false) ]) do
97
99
  subject.class.accessible_by(ability).must_be :empty?
98
100
  end
99
101
  end
100
102
  end
101
-
102
- describe 'embedded relations' do
103
- it 'returns everything when open' do
104
- subject.class.stub(:default_locks, [ default_lock(embedded_test_subject_1.class, true) ]) do
105
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_1
106
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_2
107
- end
108
- end
109
-
110
- it 'returns nothing when closed' do
111
- subject.class.stub(:default_locks, [ default_lock(embedded_test_subject_1.class, false) ]) do
112
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_be :empty?
113
- end
114
- end
115
- end
116
103
  end
117
104
 
118
105
  # ---------------------------------------------------------------------
119
106
 
120
- describe 'id locks' do
121
- describe 'referenced relations' do
122
- it 'excludes subject when closed' do
123
- user.test_locks = [ subject_lock(subject_test_1, true), subject_lock(subject_test_2, false) ]
107
+ describe 'subject_type lock' do
108
+ describe 'on roles' do
109
+ it 'overrides default lock' do
110
+ role_1.test_locks = [ subject_type_lock(subject.class, false) ]
111
+ subject.class.accessible_by(ability).must_be :empty?
112
+ end
113
+ it 'takes the most permissive of roles' do
114
+ role_1.test_locks = [ subject_type_lock(subject.class, false) ]
115
+ role_2.test_locks = [ subject_type_lock(subject.class, true) ]
124
116
  subject.class.accessible_by(ability).must_include subject_test_1
125
- subject.class.accessible_by(ability).wont_include subject_test_2
117
+ subject.class.accessible_by(ability).must_include subject_test_2
126
118
  end
127
119
  end
128
120
 
129
- describe 'embedded relations' do
130
- it 'excludes subject when closed' do
131
- user.test_locks = [ subject_lock(embedded_test_subject_1, true), subject_lock(embedded_test_subject_2, false) ]
132
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_1
133
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).wont_include embedded_test_subject_2
121
+ describe 'on user' do
122
+ it 'overrides default lock' do
123
+ user.test_locks = [ subject_type_lock(subject.class, false) ]
124
+ subject.class.accessible_by(ability).must_be :empty?
125
+ end
126
+ it 'overrides role locks' do
127
+ role_1.test_locks = [ subject_type_lock(subject.class, false) ]
128
+ user.test_locks = [ subject_type_lock(subject.class, true) ]
129
+ subject.class.accessible_by(ability).must_include subject_test_1
130
+ subject.class.accessible_by(ability).must_include subject_test_2
134
131
  end
135
132
  end
136
133
  end
137
134
 
138
135
  # ---------------------------------------------------------------------
139
136
 
140
- describe 'default locks & id locks' do
141
- describe 'referenced relations' do
142
- describe 'default open' do
143
- it 'excludes subject when id lock closed' do
144
- subject.class.stub(:default_locks, [ default_lock(subject_test_1.class, true) ]) do
145
- user.test_locks = [ subject_lock(subject_test_2, false) ]
146
- subject.class.accessible_by(ability).must_include subject_test_1
147
- subject.class.accessible_by(ability).wont_include subject_test_2
148
- end
137
+ describe 'subject_id lock' do
138
+ describe 'on roles' do
139
+ it 'overrides default lock' do
140
+ role_1.test_locks = [ subject_lock(subject_test_1, false) ]
141
+ subject.class.accessible_by(ability).wont_include subject_test_1
142
+ end
143
+
144
+ it 'overrides default negative lock' do
145
+ subject.class.stub(:default_locks, [ subject_type_lock(subject_test_1.class, false) ]) do
146
+ role_1.test_locks = [ subject_lock(subject_test_1, true) ]
147
+ subject.class.accessible_by(ability).must_include subject_test_1
149
148
  end
150
149
  end
151
150
 
152
- describe 'default closed' do
153
- it 'includes subject when id lock open' do
154
- subject.class.stub(:default_locks, [ default_lock(subject_test_1.class, false) ]) do
155
- user.test_locks = [ subject_lock(subject_test_2, true) ]
156
- subject.class.accessible_by(ability).wont_include subject_test_1
157
- subject.class.accessible_by(ability).must_include subject_test_2
158
- end
151
+ it 'overrides subject_type lock' do
152
+ role_1.test_locks = [ subject_type_lock(subject_test_2.class, false) ]
153
+ role_2.test_locks = [ subject_lock(subject_test_2, true) ]
154
+ subject.class.accessible_by(ability).must_include subject_test_2
155
+ end
156
+
157
+ it 'overrides default negative lock' do
158
+ subject.class.stub(:default_locks, [ subject_type_lock(subject_test_2.class, false) ]) do
159
+ role_2.test_locks = [ subject_lock(subject_test_2, true) ]
160
+ subject.class.accessible_by(ability).wont_include subject_test_1
161
+ subject.class.accessible_by(ability).must_include subject_test_2
159
162
  end
160
163
  end
164
+
165
+ it 'takes the most permissive of roles' do
166
+ role_1.test_locks = [ subject_lock(subject_test_2, false) ]
167
+ role_2.test_locks = [ subject_lock(subject_test_2, true) ]
168
+ subject.class.accessible_by(ability).must_include subject_test_2
169
+ end
161
170
  end
162
171
 
163
- describe 'embedded relations' do
164
- describe 'default open' do
165
- it 'excludes subject when id lock closed' do
166
- subject.class.stub(:default_locks, [ default_lock(embedded_test_subject_1.class, true) ]) do
167
- user.test_locks = [ subject_lock(embedded_test_subject_2, false) ]
168
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_1
169
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).wont_include embedded_test_subject_2
170
- end
171
- end
172
+ describe 'on user' do
173
+ it 'overrides default lock' do
174
+ user.test_locks = [ subject_lock(subject_test_1, false) ]
175
+ subject.class.accessible_by(ability).wont_include subject_test_1
176
+ subject.class.accessible_by(ability).must_include subject_test_2
177
+ end
178
+
179
+ it 'overrides subject_type lock' do
180
+ user.test_locks = [ subject_type_lock(subject_test_1.class, true), subject_lock(subject_test_1, false) ]
181
+ subject.class.accessible_by(ability).wont_include subject_test_1
182
+ end
183
+
184
+ it 'overrides role locks' do
185
+ role_1.test_locks = [ subject_lock(subject_test_2, false) ]
186
+ user.test_locks = [ subject_lock(subject_test_2, true) ]
187
+ subject.class.accessible_by(ability).must_include subject_test_2
172
188
  end
173
189
 
174
- describe 'default closed' do
175
- it 'includes subject when id lock open' do
176
- subject.class.stub(:default_locks, [ default_lock(embedded_test_subject_1.class, false) ]) do
177
- user.test_locks = [ subject_lock(embedded_test_subject_2, true) ]
178
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).wont_include embedded_test_subject_1
179
- embedded_test_subject_owner.embedded_test_subjects.accessible_by(ability).must_include embedded_test_subject_2
180
- end
190
+ it 'overrides default negative lock' do
191
+ subject.class.stub(:default_locks, [ subject_type_lock(subject_test_2.class, false) ]) do
192
+ user.test_locks = [ subject_lock(subject_test_2, true) ]
193
+ subject.class.accessible_by(ability).must_include subject_test_2
181
194
  end
182
195
  end
183
196
  end
@@ -187,4 +200,4 @@ module MongoidAbility
187
200
  end
188
201
  end
189
202
 
190
- end
203
+ end
@@ -71,26 +71,36 @@ end
71
71
 
72
72
  # ---------------------------------------------------------------------
73
73
 
74
- class TestSubjectSuper
74
+ class SubjectTest
75
75
  include Mongoid::Document
76
76
  include MongoidAbility::Subject
77
- end
78
77
 
79
- class TestSubject < TestSubjectSuper
80
78
  default_lock :read, true
81
79
  end
82
80
 
83
- class EmbeddedTestSubjectOwner
84
- include Mongoid::Document
85
- include MongoidAbility::Subject
86
-
87
- embeds_many :embedded_test_subjects
81
+ class SubjectTestOne < SubjectTest
88
82
  end
89
83
 
90
- class EmbeddedTestSubject < TestSubject
91
- embedded_in :embedded_test_subject_owner
84
+ class SubjectTestTwo < SubjectTest
92
85
  end
93
86
 
87
+
88
+
89
+ # class EmbeddedTestSubjectOwner
90
+ # include Mongoid::Document
91
+ # include MongoidAbility::Subject
92
+
93
+ # embeds_many :embedded_test_subjects
94
+ # end
95
+
96
+ # class EmbeddedTestSubject < TestSubject
97
+ # embedded_in :embedded_test_subject_owner
98
+ # end
99
+
100
+ # class EmbeddedTestSubjectTwo < TestSubject
101
+ # embedded_in :embedded_test_subject_owner
102
+ # end
103
+
94
104
  # ---------------------------------------------------------------------
95
105
 
96
106
  class TestAbilityResolverSubject
@@ -114,6 +124,8 @@ end
114
124
  class TestAbilitySubject < TestAbilitySubjectSuper1
115
125
  end
116
126
 
127
+ # ---------------------------------------------------------------------
128
+
117
129
  class TestRole
118
130
  include Mongoid::Document
119
131
  include MongoidAbility::Owner
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_ability
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomas Celizna
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-08 00:00:00.000000000 Z
11
+ date: 2015-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cancancan