mongoid_ability 0.0.6 → 0.0.7

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: 4350f8ee2aa6783ba0bd4790264aae87341062fa
4
- data.tar.gz: 7f58c17ff7e7e441fb761d0ed33f48ab298c3ec3
3
+ metadata.gz: 3fbc4ee9c2161070d8e1a2f9d79f53318239fe61
4
+ data.tar.gz: 5356a70dcb98c19d3744dea5eea22c28b6d4b2a3
5
5
  SHA512:
6
- metadata.gz: 701fa1fee1c99245b7c6dada06da608352bfe4e153ac728334d54d1394516ea1ac0707f24550ff7ab88b7e7aa96eb18db396aeeaa814e29933af2217b2e6a2ee
7
- data.tar.gz: ac018c43208f7089fe308504fec8188c5fece9cdccccc6ec76447a2ce9917740c6ef4aa5984183625ff9f3b4d3db23c04e5e5472c842ee025c83e7581017690e
6
+ metadata.gz: c1bab6862b3fb65d502b87982a4181eb6a2054ac78d7dced498732a7aaf194ed843f35ff0df8c13f10580ae1523dfeb760dc4c643c024d8b99b0ccd351f6592f
7
+ data.tar.gz: f3fc6a6559d09bc54233b60b5efabfd037ec68a32af7b2416e65bb295d981c6c53715e0a85dd15f0efe78f12bdef9fa659dc937be0423a94f253c30d20737f19
@@ -2,6 +2,7 @@ require "mongoid_ability/version"
2
2
 
3
3
  require "mongoid_ability/ability"
4
4
  require "mongoid_ability/ability_resolver"
5
+ require "mongoid_ability/accessible_query_builder"
5
6
  require "mongoid_ability/lock"
6
7
  require "mongoid_ability/owner"
7
8
  require "mongoid_ability/subject"
@@ -14,4 +15,4 @@ if defined?(Rails)
14
15
  @current_ability ||= MongoidAbility::Ability.new(current_user)
15
16
  end
16
17
  end
17
- end
18
+ end
@@ -0,0 +1,113 @@
1
+ module MongoidAbility
2
+ class AccessibleQueryBuilder < Struct.new(:base_class, :ability, :action)
3
+
4
+ def self.call *args
5
+ new(*args).call
6
+ end
7
+
8
+ # =====================================================================
9
+
10
+ def call
11
+ criteria = base_criteria
12
+
13
+ base_class_and_descendants.each do |cls|
14
+ criteria = criteria.merge(criteria_for_class(cls))
15
+ end
16
+
17
+ criteria
18
+ end
19
+
20
+ private # =============================================================
21
+
22
+ def base_criteria
23
+ @base_criteria ||= base_class.criteria
24
+ end
25
+
26
+ # ---------------------------------------------------------------------
27
+
28
+ def base_class_superclass
29
+ @base_class_superclass ||= (base_class.ancestors_with_default_locks.last || base_class)
30
+ end
31
+
32
+ def base_class_descendants
33
+ @base_class_descendants ||= ObjectSpace.each_object(Class).select{ |cls| cls < base_class_superclass }
34
+ end
35
+
36
+ def base_class_and_descendants
37
+ [base_class].concat(base_class_descendants)
38
+ end
39
+
40
+ def hereditary?
41
+ base_class_and_descendants.count > 1
42
+ end
43
+
44
+ # ---------------------------------------------------------------------
45
+
46
+ def user
47
+ ability.user
48
+ end
49
+
50
+ def roles
51
+ user.roles_relation
52
+ end
53
+
54
+ # ---------------------------------------------------------------------
55
+
56
+ def user_id_locks_for_subject_type cls
57
+ user.locks_relation.id_locks.for_action(action).for_subject_type(cls.to_s)
58
+ end
59
+
60
+ def roles_ids_locks_for_subject_type cls
61
+ roles.collect { |role| role.locks_relation.id_locks.for_action(action).for_subject_type(cls.to_s) }.flatten
62
+ end
63
+
64
+ # ---------------------------------------------------------------------
65
+
66
+ def role_has_open_id_lock? cls, subject_id
67
+ roles_ids_locks_for_subject_type(cls).
68
+ select(&:open?).
69
+ map(&:subject_id).
70
+ include?(subject_id)
71
+ end
72
+
73
+ def user_has_open_id_lock? cls, subject_id
74
+ user_id_locks_for_subject_type(cls).
75
+ select(&:open?).
76
+ map(&:subject_id).
77
+ include?(subject_id)
78
+ end
79
+
80
+ # ---------------------------------------------------------------------
81
+
82
+ def criteria_for_class cls
83
+ ability.can?(action, cls) ? exclude_criteria(cls) : include_criteria(cls)
84
+ end
85
+
86
+ def exclude_criteria cls
87
+ id_locks = roles_ids_locks_for_subject_type(cls).select(&:closed?)
88
+ id_locks = id_locks.reject{ |lock| role_has_open_id_lock?(cls, lock.subject_id) }
89
+ id_locks = id_locks.reject{ |lock| user_has_open_id_lock?(cls, lock.subject_id) }
90
+ id_locks += user_id_locks_for_subject_type(cls).select(&:closed?)
91
+
92
+ excluded_ids = id_locks.map(&:subject_id).flatten
93
+
94
+ conditions = { :_id.nin => excluded_ids }
95
+ conditions = conditions.merge(_type: cls.to_s) if hereditary?
96
+
97
+ base_criteria.or(conditions)
98
+ end
99
+
100
+ def include_criteria cls
101
+ id_locks = roles_ids_locks_for_subject_type(cls).select(&:open?)
102
+ id_locks += user_id_locks_for_subject_type(cls).select(&:open?)
103
+
104
+ included_ids = id_locks.map(&:subject_id).flatten
105
+
106
+ conditions = { :_id.in => included_ids }
107
+ conditions = conditions.merge(_type: cls.to_s) if hereditary?
108
+
109
+ base_criteria.or(conditions)
110
+ end
111
+
112
+ end
113
+ end
@@ -27,7 +27,9 @@ module MongoidAbility
27
27
  # override if needed
28
28
  # return for example 'MyLock'
29
29
  def lock_class_name
30
- @lock_class_name ||= Object.descendants.detect{ |cls| cls < MongoidAbility::Lock }.name
30
+ lock_classes = ObjectSpace.each_object(Class).select{ |cls| cls < MongoidAbility::Lock }
31
+ lock_superclasses = lock_classes.reject{ |cls| lock_classes.any?{ |c| cls < c } }
32
+ @lock_class_name ||= lock_superclasses.first.name
31
33
  end
32
34
  end
33
35
 
@@ -27,7 +27,9 @@ module MongoidAbility
27
27
  # override if needed
28
28
  # return for example 'MyLock'
29
29
  def lock_class_name
30
- @lock_class_name ||= Object.descendants.detect{ |cls| cls < MongoidAbility::Lock }.name
30
+ lock_classes = ObjectSpace.each_object(Class).select{ |cls| cls < MongoidAbility::Lock }
31
+ lock_superclasses = lock_classes.reject{ |cls| lock_classes.any?{ |c| cls < c } }
32
+ @lock_class_name ||= lock_superclasses.first.name
31
33
  end
32
34
 
33
35
  # ---------------------------------------------------------------------
@@ -42,59 +44,8 @@ module MongoidAbility
42
44
 
43
45
  # ---------------------------------------------------------------------
44
46
 
45
- # TODO: obviously this could be cleaner
46
47
  def accessible_by ability, action=:read
47
- cr = self.criteria
48
-
49
- return cr unless ability.user.present?
50
-
51
- supercls = self.ancestors_with_default_locks.last || self
52
- subject_classes = [supercls].concat(supercls.descendants)
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
- if subject_classes.count == 1
77
- cr = cr.or(:_id.nin => excluded_ids.flatten)
78
- else
79
- cr = cr.or(_type: cls.to_s, :_id.nin => excluded_ids.flatten)
80
- end
81
- else
82
- included_ids = []
83
-
84
- id_locks = open_roles_id_locks
85
- id_locks += open_user_id_locks
86
-
87
- included_ids << id_locks.map(&:subject_id)
88
-
89
- if subject_classes.count == 1
90
- cr = cr.or(:_id.in => included_ids.flatten)
91
- else
92
- cr = cr.or(_type: cls.to_s, :_id.in => included_ids.flatten)
93
- end
94
- end
95
- end
96
-
97
- cr
48
+ AccessibleQueryBuilder.call(self, ability, action)
98
49
  end
99
50
  end
100
51
 
@@ -1,3 +1,3 @@
1
1
  module MongoidAbility
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -0,0 +1,20 @@
1
+ require "test_helper"
2
+
3
+ module MongoidAbility
4
+ describe AccessibleQueryBuilder do
5
+
6
+ let(:base_class) { SubjectTest }
7
+
8
+ let(:user) { TestUser.new }
9
+ let(:ability) { Ability.new(user) }
10
+
11
+ let(:action) { :read }
12
+
13
+ subject { AccessibleQueryBuilder.call(base_class, ability, action) }
14
+
15
+ it 'returns Mongoid::Criteria' do
16
+ subject.must_be_kind_of Mongoid::Criteria
17
+ end
18
+
19
+ end
20
+ end
@@ -71,10 +71,6 @@ module MongoidAbility
71
71
  subject_single_test
72
72
  end
73
73
 
74
- it 'returns Mongoid::Criteria' do
75
- subject.class.accessible_by(ability).must_be_kind_of Mongoid::Criteria
76
- end
77
-
78
74
  # ---------------------------------------------------------------------
79
75
 
80
76
  describe 'default locks' do
@@ -0,0 +1,86 @@
1
+ class TestLock
2
+ include Mongoid::Document
3
+ include MongoidAbility::Lock
4
+
5
+ embedded_in :owner, polymorphic: true
6
+ end
7
+
8
+ class TestLockSub < TestLock
9
+ end
10
+
11
+ # ---------------------------------------------------------------------
12
+
13
+ class TestOwnerSuper
14
+ include Mongoid::Document
15
+ include MongoidAbility::Owner
16
+
17
+ embeds_many :test_locks, class_name: 'TestLock', as: :owner
18
+ end
19
+
20
+ class TestOwner < TestOwnerSuper
21
+ end
22
+
23
+ # ---------------------------------------------------------------------
24
+
25
+ class SubjectTest
26
+ include Mongoid::Document
27
+ include MongoidAbility::Subject
28
+
29
+ default_lock :read, true
30
+ end
31
+
32
+ class SubjectTestOne < SubjectTest
33
+ end
34
+
35
+ class SubjectTestTwo < SubjectTest
36
+ end
37
+
38
+ class SubjectSingleTest
39
+ include Mongoid::Document
40
+ include MongoidAbility::Subject
41
+
42
+ default_lock :read, true
43
+ end
44
+
45
+ # ---------------------------------------------------------------------
46
+
47
+ class TestAbilityResolverSubject
48
+ include Mongoid::Document
49
+ include MongoidAbility::Subject
50
+
51
+ default_lock :read, true
52
+ end
53
+
54
+ class TestAbilitySubjectSuper2
55
+ include Mongoid::Document
56
+ include MongoidAbility::Subject
57
+
58
+ default_lock :read, false
59
+ default_lock :update, true
60
+ end
61
+
62
+ class TestAbilitySubjectSuper1 < TestAbilitySubjectSuper2
63
+ end
64
+
65
+ class TestAbilitySubject < TestAbilitySubjectSuper1
66
+ end
67
+
68
+ # ---------------------------------------------------------------------
69
+
70
+ class TestRole
71
+ include Mongoid::Document
72
+ include MongoidAbility::Owner
73
+
74
+ field :name, type: String
75
+
76
+ embeds_many :test_locks, class_name: 'TestLock', as: :owner
77
+ has_and_belongs_to_many :users, class_name: 'TestUser'
78
+ end
79
+
80
+ class TestUser
81
+ include Mongoid::Document
82
+ include MongoidAbility::Owner
83
+
84
+ embeds_many :test_locks, class_name: 'TestLock', as: :owner
85
+ has_and_belongs_to_many :roles, class_name: 'TestRole'
86
+ end
data/test/test_helper.rb CHANGED
@@ -7,8 +7,8 @@ require 'mongoid'
7
7
 
8
8
  require 'mongoid_ability'
9
9
 
10
- # =====================================================================
11
-
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
11
+
12
12
  if ENV["CI"]
13
13
  require "coveralls"
14
14
  Coveralls.wear!
@@ -43,93 +43,4 @@ DatabaseCleaner.strategy = :truncation
43
43
  class MiniTest::Spec
44
44
  before(:each) { DatabaseCleaner.start }
45
45
  after(:each) { DatabaseCleaner.clean }
46
- end
47
-
48
- # =====================================================================
49
-
50
- class TestLock
51
- include Mongoid::Document
52
- include MongoidAbility::Lock
53
-
54
- embedded_in :owner, polymorphic: true
55
- end
56
-
57
- class TestLockSub < TestLock
58
- end
59
-
60
- # ---------------------------------------------------------------------
61
-
62
- class TestOwnerSuper
63
- include Mongoid::Document
64
- include MongoidAbility::Owner
65
-
66
- embeds_many :test_locks, class_name: 'TestLock', as: :owner
67
- end
68
-
69
- class TestOwner < TestOwnerSuper
70
- end
71
-
72
- # ---------------------------------------------------------------------
73
-
74
- class SubjectTest
75
- include Mongoid::Document
76
- include MongoidAbility::Subject
77
-
78
- default_lock :read, true
79
- end
80
-
81
- class SubjectTestOne < SubjectTest
82
- end
83
-
84
- class SubjectTestTwo < SubjectTest
85
- end
86
-
87
- class SubjectSingleTest
88
- include Mongoid::Document
89
- include MongoidAbility::Subject
90
-
91
- default_lock :read, true
92
- end
93
-
94
- # ---------------------------------------------------------------------
95
-
96
- class TestAbilityResolverSubject
97
- include Mongoid::Document
98
- include MongoidAbility::Subject
99
-
100
- default_lock :read, true
101
- end
102
-
103
- class TestAbilitySubjectSuper2
104
- include Mongoid::Document
105
- include MongoidAbility::Subject
106
-
107
- default_lock :read, false
108
- default_lock :update, true
109
- end
110
-
111
- class TestAbilitySubjectSuper1 < TestAbilitySubjectSuper2
112
- end
113
-
114
- class TestAbilitySubject < TestAbilitySubjectSuper1
115
- end
116
-
117
- # ---------------------------------------------------------------------
118
-
119
- class TestRole
120
- include Mongoid::Document
121
- include MongoidAbility::Owner
122
-
123
- field :name, type: String
124
-
125
- embeds_many :test_locks, class_name: 'TestLock', as: :owner
126
- has_and_belongs_to_many :users, class_name: 'TestUser'
127
- end
128
-
129
- class TestUser
130
- include Mongoid::Document
131
- include MongoidAbility::Owner
132
-
133
- embeds_many :test_locks, class_name: 'TestLock', as: :owner
134
- has_and_belongs_to_many :roles, class_name: 'TestRole'
135
46
  end
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.6
4
+ version: 0.0.7
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-09 00:00:00.000000000 Z
11
+ date: 2015-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cancancan
@@ -155,6 +155,7 @@ files:
155
155
  - lib/mongoid_ability.rb
156
156
  - lib/mongoid_ability/ability.rb
157
157
  - lib/mongoid_ability/ability_resolver.rb
158
+ - lib/mongoid_ability/accessible_query_builder.rb
158
159
  - lib/mongoid_ability/lock.rb
159
160
  - lib/mongoid_ability/owner.rb
160
161
  - lib/mongoid_ability/subject.rb
@@ -162,9 +163,11 @@ files:
162
163
  - mongoid_ability.gemspec
163
164
  - test/mongoid_ability/ability_resolver_test.rb
164
165
  - test/mongoid_ability/ability_test.rb
166
+ - test/mongoid_ability/accessible_query_builder_test.rb
165
167
  - test/mongoid_ability/lock_test.rb
166
168
  - test/mongoid_ability/owner_test.rb
167
169
  - test/mongoid_ability/subject_test.rb
170
+ - test/support/test_classes.rb
168
171
  - test/test_helper.rb
169
172
  homepage: https://github.com/tomasc/mongoid_ability
170
173
  licenses:
@@ -194,7 +197,9 @@ summary: Custom Ability class that allows CanCanCan authorization library store
194
197
  test_files:
195
198
  - test/mongoid_ability/ability_resolver_test.rb
196
199
  - test/mongoid_ability/ability_test.rb
200
+ - test/mongoid_ability/accessible_query_builder_test.rb
197
201
  - test/mongoid_ability/lock_test.rb
198
202
  - test/mongoid_ability/owner_test.rb
199
203
  - test/mongoid_ability/subject_test.rb
204
+ - test/support/test_classes.rb
200
205
  - test/test_helper.rb