mongoid_ability 0.0.3 → 0.0.4

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.
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