mongoid_ability 0.0.6 → 0.0.7

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