mongoid_ability 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/README.md +0 -7
- data/lib/mongoid_ability/accessible_query_builder.rb +35 -78
- data/lib/mongoid_ability/lock.rb +40 -42
- data/lib/mongoid_ability/resolve_owner_locks.rb +4 -6
- data/lib/mongoid_ability/subject.rb +9 -17
- data/lib/mongoid_ability/version.rb +1 -1
- data/mongoid_ability.gemspec +1 -1
- data/test/mongoid_ability/accessible_query_builder_test.rb +5 -8
- data/test/mongoid_ability/lock_test.rb +6 -42
- data/test/mongoid_ability/owner_locks_test.rb +3 -4
- data/test/mongoid_ability/owner_test.rb +0 -1
- data/test/mongoid_ability/subject_accessible_by_test.rb +105 -101
- data/test/mongoid_ability/subject_test.rb +4 -17
- data/test/support/expectations.rb +4 -0
- data/test/support/test_classes/my_lock.rb +15 -0
- data/test/support/test_classes/my_owner.rb +21 -0
- data/test/support/test_classes/my_role.rb +16 -0
- data/test/support/test_classes/my_subject.rb +16 -0
- data/test/test_helper.rb +6 -2
- metadata +17 -9
- data/test/support/test_classes.rb +0 -161
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f894c51e60acf940ca8b92ec9f7402df3b852bf9
|
4
|
+
data.tar.gz: d923b2dfee15aee43d0aab8535adbd4ad44ff6f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a004c82655f15430cbb9421a3180a35d72375687f5301bb0fffd8b373055b87dd15ee9e187db4cd321ef7bede86c525f7a600030d088fdb31b019c654c51098
|
7
|
+
data.tar.gz: d8336fcfbb6a4f1ca8ede3e970dae45406b9cd575c83a78e5c48fda2ef02d6274ab06d218839ebe13b8a5c7ba71a121e40e2b2875ae074b5ee8d5f63a1d080c2
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -81,13 +81,6 @@ end
|
|
81
81
|
|
82
82
|
The subject classes can be subclassed. Subclasses inherit the default locks (unless they override them), the resulting outcome being correctly calculated bottom-up the superclass chain.
|
83
83
|
|
84
|
-
The subject also acquires a convenience `Mongoid::Criteria` named `.accessible_by`. This criteria can be used to query for subject based on the user's ability:
|
85
|
-
|
86
|
-
```ruby
|
87
|
-
ability = MongoidAbility::Ability.new(current_user)
|
88
|
-
MySubject.accessible_by(ability, :read, options={})
|
89
|
-
```
|
90
|
-
|
91
84
|
### Owner
|
92
85
|
|
93
86
|
This `Ability` class supports two levels of inheritance (for example User and its Roles). The locks can be either embedded (via `.embeds_many`) or associated (via `.has_many`). Make sure to include the `as: :owner` option.
|
@@ -1,16 +1,35 @@
|
|
1
|
-
# FIXME: this is extremely slow and not suitable for use, yet
|
2
|
-
|
3
1
|
module MongoidAbility
|
4
2
|
class AccessibleQueryBuilder < Struct.new(:base_class, :ability, :action, :options)
|
5
|
-
|
6
|
-
def self.call *args
|
3
|
+
def self.call(*args)
|
7
4
|
new(*args).call
|
8
5
|
end
|
9
6
|
|
10
7
|
# =====================================================================
|
11
8
|
|
9
|
+
# TODO: cleanup
|
12
10
|
def call
|
13
|
-
|
11
|
+
closed_classes = [] # [cls]
|
12
|
+
open_ids = [] # [cls, id]
|
13
|
+
closed_ids = [] # [id]
|
14
|
+
|
15
|
+
base_class_and_descendants.each do |cls|
|
16
|
+
closed_classes << cls.to_s if ability.cannot?(action, cls, options)
|
17
|
+
|
18
|
+
id_locks(cls).each do |lock|
|
19
|
+
if ability.can?(action, cls.new(_id: lock.subject_id), options)
|
20
|
+
open_ids << [cls.to_s, lock.subject_id]
|
21
|
+
else
|
22
|
+
closed_ids << lock.subject_id
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
closed_classes_condition = { :_type.nin => closed_classes }
|
28
|
+
open_ids_condition = { :_type.in => open_ids.map(&:first), :_id.in => open_ids.map(&:last) }
|
29
|
+
closed_ids_condition = { :_id.nin => closed_ids }
|
30
|
+
or_conditions = [ closed_classes_condition, open_ids_condition ].reject(&:blank?)
|
31
|
+
|
32
|
+
base_criteria.where( :$and => [ { :$or => or_conditions }, closed_ids_condition ])
|
14
33
|
end
|
15
34
|
|
16
35
|
private # =============================================================
|
@@ -25,16 +44,12 @@ module MongoidAbility
|
|
25
44
|
@base_class_superclass ||= (base_class.ancestors_with_default_locks.last || base_class)
|
26
45
|
end
|
27
46
|
|
28
|
-
def
|
29
|
-
|
47
|
+
def default_lock(_cls, action)
|
48
|
+
base_class_superclass.default_locks.detect { |l| l.action.to_s == action.to_s }
|
30
49
|
end
|
31
50
|
|
32
51
|
def base_class_and_descendants
|
33
|
-
@base_class_and_descendants ||= [base_class].concat(
|
34
|
-
end
|
35
|
-
|
36
|
-
def hereditary?
|
37
|
-
base_class_and_descendants.count > 1
|
52
|
+
@base_class_and_descendants ||= [base_class].concat(base_class.descendants)
|
38
53
|
end
|
39
54
|
|
40
55
|
# ---------------------------------------------------------------------
|
@@ -50,79 +65,21 @@ module MongoidAbility
|
|
50
65
|
|
51
66
|
# ---------------------------------------------------------------------
|
52
67
|
|
53
|
-
def
|
68
|
+
def id_locks(cls)
|
69
|
+
(Array(owner_id_locks_for_subject_type(cls)) + Array(inherited_from_relation_ids_locks_for_subject_type(cls))).flatten
|
70
|
+
end
|
71
|
+
|
72
|
+
def owner_id_locks_for_subject_type(cls)
|
54
73
|
@owner_id_locks_for_subject_type ||= {}
|
55
74
|
@owner_id_locks_for_subject_type[cls] ||= owner.locks_relation.id_locks.for_action(action).for_subject_type(cls.to_s)
|
56
75
|
end
|
57
76
|
|
58
|
-
def inherited_from_relation_ids_locks_for_subject_type
|
77
|
+
def inherited_from_relation_ids_locks_for_subject_type(cls)
|
59
78
|
return [] unless inherited_from_relation
|
60
79
|
@inherited_from_relation_ids_locks_for_subject_type ||= {}
|
61
|
-
@inherited_from_relation_ids_locks_for_subject_type[cls] ||= inherited_from_relation.collect
|
80
|
+
@inherited_from_relation_ids_locks_for_subject_type[cls] ||= inherited_from_relation.collect do |o|
|
62
81
|
o.locks_relation.id_locks.for_action(action).for_subject_type(cls.to_s)
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
# ---------------------------------------------------------------------
|
67
|
-
|
68
|
-
def role_has_open_id_lock? cls, subject_id
|
69
|
-
@role_has_open_id_lock ||= {}
|
70
|
-
@role_has_open_id_lock["#{cls}_#{subject_id}"] ||= begin
|
71
|
-
inherited_from_relation_ids_locks_for_subject_type(cls).
|
72
|
-
select{ |l| l.open?(options) }.
|
73
|
-
map(&:subject_id).
|
74
|
-
include?(subject_id)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def owner_has_open_id_lock? cls, subject_id
|
79
|
-
@owner_has_open_id_lock ||= {}
|
80
|
-
@owner_has_open_id_lock["#{cls}_#{subject_id}"] ||= begin
|
81
|
-
owner_id_locks_for_subject_type(cls).
|
82
|
-
select{ |l| l.open?(options) }.
|
83
|
-
map(&:subject_id).
|
84
|
-
include?(subject_id)
|
85
|
-
end
|
82
|
+
end.flatten
|
86
83
|
end
|
87
|
-
|
88
|
-
# ---------------------------------------------------------------------
|
89
|
-
|
90
|
-
def criteria_for_class cls
|
91
|
-
@criteria_for_class ||= {}
|
92
|
-
@criteria_for_class[cls] ||= ability.can?(action, cls, options) ? exclude_criteria(cls) : include_criteria(cls)
|
93
|
-
end
|
94
|
-
|
95
|
-
def exclude_criteria cls
|
96
|
-
@exclude_criteria ||= {}
|
97
|
-
@exclude_criteria[cls] ||= begin
|
98
|
-
id_locks = inherited_from_relation_ids_locks_for_subject_type(cls).select{ |l| l.closed?(options) }
|
99
|
-
id_locks = id_locks.reject{ |lock| role_has_open_id_lock?(cls, lock.subject_id) }
|
100
|
-
id_locks = id_locks.reject{ |lock| owner_has_open_id_lock?(cls, lock.subject_id) }
|
101
|
-
id_locks += owner_id_locks_for_subject_type(cls).select{ |l| l.closed?(options) }
|
102
|
-
|
103
|
-
excluded_ids = id_locks.map(&:subject_id).flatten
|
104
|
-
|
105
|
-
conditions = { :_id.nin => excluded_ids }
|
106
|
-
conditions = conditions.merge(_type: cls.to_s) if hereditary?
|
107
|
-
|
108
|
-
base_criteria.or(conditions)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def include_criteria cls
|
113
|
-
@include_criteria ||= {}
|
114
|
-
@include_criteria[cls] ||= begin
|
115
|
-
id_locks = inherited_from_relation_ids_locks_for_subject_type(cls).select{ |l| l.open?(options) }
|
116
|
-
id_locks += owner_id_locks_for_subject_type(cls).select{ |l| l.open?(options) }
|
117
|
-
|
118
|
-
included_ids = id_locks.map(&:subject_id).flatten
|
119
|
-
|
120
|
-
conditions = { :_id.in => included_ids }
|
121
|
-
conditions = conditions.merge(_type: cls.to_s) if hereditary?
|
122
|
-
|
123
|
-
base_criteria.or(conditions)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
84
|
end
|
128
85
|
end
|
data/lib/mongoid_ability/lock.rb
CHANGED
@@ -2,7 +2,7 @@ require 'mongoid'
|
|
2
2
|
|
3
3
|
module MongoidAbility
|
4
4
|
module Lock
|
5
|
-
def self.included
|
5
|
+
def self.included(base)
|
6
6
|
base.extend ClassMethods
|
7
7
|
base.class_eval do
|
8
8
|
field :action, type: Symbol, default: :read
|
@@ -12,14 +12,14 @@ module MongoidAbility
|
|
12
12
|
belongs_to :subject, polymorphic: true, touch: true
|
13
13
|
|
14
14
|
# TODO: validate that action is defined on subject or its superclasses
|
15
|
-
validates :action, presence: true, uniqueness: { scope: [
|
15
|
+
validates :action, presence: true, uniqueness: { scope: [:subject_type, :subject_id, :outcome] }
|
16
16
|
validates :outcome, presence: true
|
17
17
|
|
18
|
-
scope :for_action, -> action { where(action: action.to_sym) }
|
18
|
+
scope :for_action, -> (action) { where(action: action.to_sym) }
|
19
19
|
|
20
|
-
scope :for_subject_type, -> subject_type { where(subject_type: subject_type.to_s) }
|
21
|
-
scope :for_subject_id, -> subject_id { where(subject_id: subject_id.presence) }
|
22
|
-
scope :for_subject, -> subject { where(subject_type: subject.class.model_name, subject_id: subject.id) }
|
20
|
+
scope :for_subject_type, -> (subject_type) { where(subject_type: subject_type.to_s) }
|
21
|
+
scope :for_subject_id, -> (subject_id) { where(subject_id: subject_id.presence) }
|
22
|
+
scope :for_subject, -> (subject) { where(subject_type: subject.class.model_name, subject_id: subject.id) }
|
23
23
|
|
24
24
|
scope :class_locks, -> { where(subject_id: nil) }
|
25
25
|
scope :id_locks, -> { ne(subject_id: nil) }
|
@@ -28,52 +28,50 @@ module MongoidAbility
|
|
28
28
|
|
29
29
|
# =====================================================================
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
# NOTE: override for more complicated results
|
37
|
-
def conditions
|
38
|
-
res = { _type: subject_type }
|
39
|
-
res = res.merge(_id: subject_id) if subject_id.present?
|
40
|
-
res = { '$not' => res } if calculated_outcome == false
|
41
|
-
res
|
42
|
-
end
|
43
|
-
|
44
|
-
# calculates outcome as if this lock is not present
|
45
|
-
def inherited_outcome options=default_options
|
46
|
-
return calculated_outcome(options) unless owner.present?
|
47
|
-
cloned_owner = owner.clone
|
48
|
-
cloned_owner.locks_relation = cloned_owner.locks_relation - [self]
|
49
|
-
MongoidAbility::Ability.new(cloned_owner).can? action, (subject.present? ? subject : subject_class), options
|
50
|
-
end
|
31
|
+
concerning :LockType do
|
32
|
+
def class_lock?
|
33
|
+
!id_lock?
|
34
|
+
end
|
51
35
|
|
52
|
-
|
53
|
-
|
54
|
-
|
36
|
+
def id_lock?
|
37
|
+
subject_id.present?
|
38
|
+
end
|
55
39
|
end
|
56
40
|
|
57
|
-
|
41
|
+
concerning :Outcome do
|
42
|
+
# NOTE: override for more complicated results
|
43
|
+
def calculated_outcome(_options = {})
|
44
|
+
outcome
|
45
|
+
end
|
58
46
|
|
59
|
-
|
60
|
-
|
61
|
-
|
47
|
+
def open?(options = {})
|
48
|
+
calculated_outcome(options) == true
|
49
|
+
end
|
62
50
|
|
63
|
-
|
64
|
-
|
51
|
+
def closed?(options = {})
|
52
|
+
!open?(options)
|
53
|
+
end
|
65
54
|
end
|
66
55
|
|
67
|
-
|
68
|
-
|
69
|
-
|
56
|
+
concerning :InheritedOutcome do
|
57
|
+
# calculates outcome as if this lock is not present
|
58
|
+
def inherited_outcome(options = default_options)
|
59
|
+
return calculated_outcome(options) unless owner.present?
|
60
|
+
cloned_owner = owner.clone
|
61
|
+
cloned_owner.locks_relation = cloned_owner.locks_relation - [self]
|
62
|
+
MongoidAbility::Ability.new(cloned_owner).can? action, (subject.present? ? subject : subject_class), options
|
63
|
+
end
|
70
64
|
|
71
|
-
|
72
|
-
|
65
|
+
# used when calculating inherited outcome
|
66
|
+
def default_options
|
67
|
+
{}
|
68
|
+
end
|
73
69
|
end
|
74
70
|
|
75
|
-
|
76
|
-
|
71
|
+
concerning :Subject do
|
72
|
+
def subject_class
|
73
|
+
subject_type.constantize
|
74
|
+
end
|
77
75
|
end
|
78
76
|
end
|
79
77
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module MongoidAbility
|
2
2
|
class ResolveOwnerLocks < ResolveLocks
|
3
|
-
|
4
3
|
def call
|
5
4
|
# FIXME: this is not a very nice fix
|
6
5
|
return unless owner.respond_to?(:locks_relation)
|
@@ -12,17 +11,16 @@ module MongoidAbility
|
|
12
11
|
# return outcome if owner defines lock for id
|
13
12
|
if subject.present?
|
14
13
|
id_locks = locks_for_subject_type.id_locks.for_subject_id(subject_id)
|
15
|
-
return false if id_locks.any?{ |l| l.closed?(options) }
|
16
|
-
return true if id_locks.any?{ |l| l.open?(options) }
|
14
|
+
return false if id_locks.any? { |l| l.closed?(options) }
|
15
|
+
return true if id_locks.any? { |l| l.open?(options) }
|
17
16
|
end
|
18
17
|
|
19
18
|
# return outcome if owner defines lock for subject_type
|
20
19
|
class_locks = locks_for_subject_type.class_locks
|
21
|
-
return false if class_locks.class_locks.any?{ |l| l.closed?(options) }
|
22
|
-
return true if class_locks.class_locks.any?{ |l| l.open?(options) }
|
20
|
+
return false if class_locks.class_locks.any? { |l| l.closed?(options) }
|
21
|
+
return true if class_locks.class_locks.any? { |l| l.open?(options) }
|
23
22
|
|
24
23
|
nil
|
25
24
|
end
|
26
|
-
|
27
25
|
end
|
28
26
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module MongoidAbility
|
2
2
|
module Subject
|
3
|
-
|
4
|
-
def self.included base
|
3
|
+
def self.included(base)
|
5
4
|
base.extend ClassMethods
|
6
5
|
base.class_eval do
|
7
6
|
end
|
@@ -12,21 +11,15 @@ module MongoidAbility
|
|
12
11
|
@default_locks ||= []
|
13
12
|
end
|
14
13
|
|
15
|
-
def default_locks=
|
14
|
+
def default_locks=(locks)
|
16
15
|
@default_locks = locks
|
17
16
|
end
|
18
17
|
|
19
|
-
def default_lock
|
20
|
-
|
21
|
-
# unless root_class.has_default_lock_for_action?(action)
|
22
|
-
# raise StandardError, "action is not defined on root class (#{root_class})"
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
|
26
|
-
lock = lock_cls.new( subject_type: self.to_s, action: action, outcome: outcome, options: options )
|
18
|
+
def default_lock(lock_cls, action, outcome, options = {})
|
19
|
+
lock = lock_cls.new(subject_type: to_s, action: action, outcome: outcome, options: options)
|
27
20
|
|
28
21
|
# remove any existing locks
|
29
|
-
if existing_lock = default_locks.detect{ |l| l.action == lock.action }
|
22
|
+
if existing_lock = default_locks.detect { |l| l.action == lock.action }
|
30
23
|
default_locks.delete(existing_lock)
|
31
24
|
end
|
32
25
|
|
@@ -54,20 +47,19 @@ module MongoidAbility
|
|
54
47
|
|
55
48
|
# ---------------------------------------------------------------------
|
56
49
|
|
57
|
-
def default_lock_for_action
|
58
|
-
default_locks.detect{ |lock| lock.action == action.to_sym }
|
50
|
+
def default_lock_for_action(action)
|
51
|
+
default_locks.detect { |lock| lock.action == action.to_sym }
|
59
52
|
end
|
60
53
|
|
61
|
-
def has_default_lock_for_action?
|
54
|
+
def has_default_lock_for_action?(action)
|
62
55
|
default_lock_for_action(action).present?
|
63
56
|
end
|
64
57
|
|
65
58
|
# ---------------------------------------------------------------------
|
66
59
|
|
67
|
-
def accessible_by
|
60
|
+
def accessible_by(ability, action = :read, options = {})
|
68
61
|
AccessibleQueryBuilder.call(self, ability, action, options)
|
69
62
|
end
|
70
63
|
end
|
71
|
-
|
72
64
|
end
|
73
65
|
end
|
data/mongoid_ability.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency "cancancan", "~> 1.9"
|
22
22
|
spec.add_dependency "mongoid", "~> 5.0"
|
23
23
|
|
24
|
-
spec.add_development_dependency "bundler"
|
24
|
+
spec.add_development_dependency "bundler"
|
25
25
|
spec.add_development_dependency "coveralls"
|
26
26
|
spec.add_development_dependency "database_cleaner", ">= 1.5.1"
|
27
27
|
spec.add_development_dependency "guard"
|
@@ -1,24 +1,21 @@
|
|
1
|
-
require
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
module MongoidAbility
|
4
4
|
describe AccessibleQueryBuilder do
|
5
|
-
|
6
5
|
let(:base_class) { MySubject }
|
7
|
-
|
8
6
|
let(:owner) { MyOwner.new }
|
9
7
|
let(:ability) { Ability.new(owner) }
|
10
|
-
|
11
8
|
let(:action) { :read }
|
12
|
-
|
13
|
-
subject { AccessibleQueryBuilder.call(base_class, ability, action) }
|
9
|
+
let(:options) { Hash.new }
|
14
10
|
|
15
11
|
before do
|
16
|
-
MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome:
|
12
|
+
MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: true) ]
|
17
13
|
end
|
18
14
|
|
15
|
+
subject { AccessibleQueryBuilder.call(base_class, ability, action, options) }
|
16
|
+
|
19
17
|
it 'returns Mongoid::Criteria' do
|
20
18
|
subject.must_be_kind_of Mongoid::Criteria
|
21
19
|
end
|
22
|
-
|
23
20
|
end
|
24
21
|
end
|
@@ -2,14 +2,14 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
module MongoidAbility
|
4
4
|
describe Lock do
|
5
|
-
|
6
5
|
subject { MyLock.new }
|
7
6
|
let(:my_subject) { MySubject.new }
|
8
7
|
let(:inherited_lock) { MyLock1.new }
|
8
|
+
|
9
9
|
# ---------------------------------------------------------------------
|
10
10
|
|
11
11
|
before do
|
12
|
-
MySubject.default_locks = [
|
12
|
+
MySubject.default_locks = [MyLock.new(action: :read, outcome: true), MyLock.new(action: :update, outcome: false)]
|
13
13
|
end
|
14
14
|
|
15
15
|
# ---------------------------------------------------------------------
|
@@ -27,13 +27,16 @@ module MongoidAbility
|
|
27
27
|
subject.must_respond_to :open?
|
28
28
|
subject.open?.must_equal false
|
29
29
|
end
|
30
|
+
|
30
31
|
it '#closed?' do
|
31
32
|
subject.must_respond_to :closed?
|
32
33
|
subject.closed?.must_equal true
|
33
34
|
end
|
35
|
+
|
34
36
|
it '#class_lock?' do
|
35
37
|
subject.must_respond_to :class_lock?
|
36
38
|
end
|
39
|
+
|
37
40
|
it '#id_lock?' do
|
38
41
|
subject.must_respond_to :id_lock?
|
39
42
|
end
|
@@ -74,48 +77,9 @@ module MongoidAbility
|
|
74
77
|
end
|
75
78
|
|
76
79
|
it 'returns calculated_outcome for default locks' do
|
77
|
-
lock = MySubject.default_locks.detect{ |l| l.action == :read }
|
80
|
+
lock = MySubject.default_locks.detect { |l| l.action == :read }
|
78
81
|
lock.inherited_outcome.must_equal true
|
79
82
|
end
|
80
83
|
end
|
81
|
-
|
82
|
-
# ---------------------------------------------------------------------
|
83
|
-
|
84
|
-
describe '#criteria' do
|
85
|
-
let(:open_subject_type_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: true) }
|
86
|
-
let(:closed_subject_type_lock) { MyLock.new(subject_type: MySubject, action: :read, outcome: false) }
|
87
|
-
|
88
|
-
let(:open_subject_lock) { MyLock.new(subject: my_subject, action: :read, outcome: true) }
|
89
|
-
let(:closed_subject_lock) { MyLock.new(subject: my_subject, action: :read, outcome: false) }
|
90
|
-
|
91
|
-
it 'returns conditions Hash' do
|
92
|
-
open_subject_type_lock.conditions.must_be_kind_of Hash
|
93
|
-
closed_subject_type_lock.conditions.must_be_kind_of Hash
|
94
|
-
|
95
|
-
open_subject_lock.conditions.must_be_kind_of Hash
|
96
|
-
closed_subject_lock.conditions.must_be_kind_of Hash
|
97
|
-
end
|
98
|
-
|
99
|
-
describe 'when open' do
|
100
|
-
it 'includes subject_type' do
|
101
|
-
open_subject_type_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type })
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'includes id' do
|
105
|
-
open_subject_lock.conditions.must_equal({ _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id })
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
describe 'when closed' do
|
110
|
-
it 'excludes subject_type' do
|
111
|
-
closed_subject_type_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type }})
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'includes id' do
|
115
|
-
closed_subject_lock.conditions.must_equal({ '$not' => { _type: open_subject_type_lock.subject_type, _id: open_subject_lock.subject_id }})
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
84
|
end
|
121
85
|
end
|
@@ -13,13 +13,13 @@ module MongoidAbility
|
|
13
13
|
# ---------------------------------------------------------------------
|
14
14
|
|
15
15
|
before do
|
16
|
-
MySubject.default_locks = [
|
16
|
+
MySubject.default_locks = [MyLock.new(subject_type: MySubject, action: :read, outcome: true)]
|
17
17
|
end
|
18
18
|
|
19
19
|
# ---------------------------------------------------------------------
|
20
20
|
|
21
21
|
describe 'when lock for subject' do
|
22
|
-
before { owner.my_locks = [
|
22
|
+
before { owner.my_locks = [subject_lock] }
|
23
23
|
|
24
24
|
it 'applies it' do
|
25
25
|
ability.can?(:read, subject.class).must_equal true
|
@@ -30,13 +30,12 @@ module MongoidAbility
|
|
30
30
|
# ---------------------------------------------------------------------
|
31
31
|
|
32
32
|
describe 'when lock for subject type' do
|
33
|
-
before { owner.my_locks = [
|
33
|
+
before { owner.my_locks = [subject_type_lock] }
|
34
34
|
|
35
35
|
it 'applies it' do
|
36
36
|
ability.can?(:read, subject.class).must_equal false
|
37
37
|
ability.can?(:read, subject).must_equal false
|
38
38
|
end
|
39
39
|
end
|
40
|
-
|
41
40
|
end
|
42
41
|
end
|
@@ -2,134 +2,138 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
module MongoidAbility
|
4
4
|
describe '.accessible_by' do
|
5
|
+
let(:my_subject) { MySubject.create! }
|
6
|
+
let(:my_subject1) { MySubject1.create! }
|
7
|
+
let(:my_subject2) { MySubject2.create! }
|
5
8
|
|
6
9
|
let(:role_1) { MyRole.new }
|
7
10
|
let(:role_2) { MyRole.new }
|
8
|
-
let(:owner) { MyOwner.new(my_roles: [
|
11
|
+
let(:owner) { MyOwner.new(my_roles: [role_1, role_2]) }
|
9
12
|
let(:ability) { Ability.new(owner) }
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
# =====================================================================
|
15
|
+
|
16
|
+
describe 'default open locks' do
|
17
|
+
before do
|
18
|
+
# NOTE: we might need to use the .default_lock macro in case we propagate down directly
|
19
|
+
MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :update, outcome: true) ]
|
20
|
+
MySubject1.default_locks = []
|
21
|
+
MySubject2.default_locks = []
|
22
|
+
|
23
|
+
my_subject
|
24
|
+
my_subject1
|
25
|
+
my_subject2
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'propagates from superclass to all subclasses' do
|
29
|
+
MySubject.accessible_by(ability, :update).to_a.must_include my_subject
|
30
|
+
MySubject.accessible_by(ability, :update).to_a.must_include my_subject1
|
31
|
+
MySubject.accessible_by(ability, :update).to_a.must_include my_subject2
|
14
32
|
|
15
|
-
|
16
|
-
|
33
|
+
MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject
|
34
|
+
MySubject1.accessible_by(ability, :update).to_a.must_include my_subject1
|
35
|
+
MySubject1.accessible_by(ability, :update).to_a.must_include my_subject2
|
36
|
+
|
37
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject
|
38
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject1
|
39
|
+
MySubject2.accessible_by(ability, :update).to_a.must_include my_subject2
|
40
|
+
end
|
17
41
|
end
|
18
42
|
|
19
|
-
|
43
|
+
describe 'default closed locks' do
|
44
|
+
before do
|
45
|
+
# NOTE: we might need to use the .default_lock macro in case we propagate down directly
|
46
|
+
MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :update, outcome: false) ]
|
47
|
+
MySubject1.default_locks = []
|
48
|
+
MySubject2.default_locks = []
|
20
49
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject
|
25
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject_1
|
26
|
-
end
|
50
|
+
my_subject
|
51
|
+
my_subject1
|
52
|
+
my_subject2
|
27
53
|
end
|
28
54
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
55
|
+
it 'propagates from superclass to all subclasses' do
|
56
|
+
MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
|
57
|
+
MySubject.accessible_by(ability, :update).to_a.wont_include my_subject1
|
58
|
+
MySubject.accessible_by(ability, :update).to_a.wont_include my_subject2
|
34
59
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
60
|
+
MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject
|
61
|
+
MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject1
|
62
|
+
MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject2
|
63
|
+
|
64
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject
|
65
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject1
|
66
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject2
|
39
67
|
end
|
40
68
|
end
|
41
69
|
|
42
|
-
|
70
|
+
describe 'default combined locks' do
|
71
|
+
before do
|
72
|
+
# NOTE: we might need to use the .default_lock macro in case we propagate down directly
|
73
|
+
MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :update, outcome: false) ]
|
74
|
+
MySubject1.default_locks = [ MyLock.new(subject_type: MySubject, action: :update, outcome: true) ]
|
75
|
+
MySubject2.default_locks = [ MyLock.new(subject_type: MySubject, action: :update, outcome: false) ]
|
43
76
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
role_1.my_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: false) ]
|
48
|
-
MySubject.accessible_by(ability, :read).to_a.must_be :empty?
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'takes the most permissive of roles' do
|
52
|
-
role_1.my_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: false) ]
|
53
|
-
role_2.my_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: true) ]
|
54
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject
|
55
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject_1
|
56
|
-
end
|
77
|
+
my_subject
|
78
|
+
my_subject1
|
79
|
+
my_subject2
|
57
80
|
end
|
58
81
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
82
|
+
it 'propagates from superclass to all subclasses' do
|
83
|
+
MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
|
84
|
+
MySubject.accessible_by(ability, :update).to_a.must_include my_subject1
|
85
|
+
MySubject.accessible_by(ability, :update).to_a.wont_include my_subject2
|
86
|
+
|
87
|
+
MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject
|
88
|
+
MySubject1.accessible_by(ability, :update).to_a.must_include my_subject1
|
89
|
+
MySubject1.accessible_by(ability, :update).to_a.wont_include my_subject2
|
90
|
+
|
91
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject
|
92
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject1
|
93
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject2
|
71
94
|
end
|
72
95
|
end
|
73
96
|
|
74
97
|
# ---------------------------------------------------------------------
|
75
98
|
|
76
|
-
describe '
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'overrides subject_type lock' do
|
90
|
-
role_1.my_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: false) ]
|
91
|
-
role_2.my_locks = [ MyLock.new(subject: @my_subject, action: :read, outcome: true) ]
|
92
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'takes the most permissive of roles' do
|
96
|
-
role_1.my_locks = [ MyLock.new(subject: @my_subject, action: :read, outcome: true) ]
|
97
|
-
role_2.my_locks = [ MyLock.new(subject: @my_subject, action: :read, outcome: false) ]
|
98
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject
|
99
|
-
end
|
100
|
-
|
101
|
-
describe 'for subclasses' do
|
102
|
-
it 'overrides default negative lock' do
|
103
|
-
MySubject.default_locks = [ MyLock.new(subject_type: MySubject1, action: :read, outcome: false) ]
|
104
|
-
role_1.my_locks = [ MyLock.new(subject: @my_subject_1, action: :read, outcome: true) ]
|
105
|
-
MySubject.accessible_by(ability, :read).to_a.wont_include @my_subject
|
106
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject_1
|
107
|
-
end
|
108
|
-
end
|
99
|
+
describe 'closed id locks' do
|
100
|
+
let(:role_1) { MyRole.new(my_locks: [ MyLock.new(subject: my_subject, action: :update, outcome: false) ]) }
|
101
|
+
|
102
|
+
before do
|
103
|
+
MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :update, outcome: true) ]
|
104
|
+
MySubject1.default_locks = []
|
105
|
+
MySubject2.default_locks = []
|
106
|
+
|
107
|
+
my_subject
|
108
|
+
my_subject1
|
109
|
+
my_subject2
|
109
110
|
end
|
110
111
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'overrides subject_type lock' do
|
118
|
-
owner.my_locks = [
|
119
|
-
MyLock.new(subject_type: MySubject, action: :read, outcome: false),
|
120
|
-
MyLock.new(subject_type: MySubject1, action: :read, outcome: true)
|
121
|
-
]
|
122
|
-
MySubject.accessible_by(ability, :read).to_a.wont_include @my_subject
|
123
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject_1
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'overrides role locks' do
|
127
|
-
role_1.my_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: false) ]
|
128
|
-
owner.my_locks = [ MyLock.new(subject_type: MySubject, action: :read, outcome: true) ]
|
129
|
-
MySubject.accessible_by(ability, :read).to_a.must_include @my_subject
|
130
|
-
end
|
112
|
+
it 'applies id locks' do
|
113
|
+
MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
|
114
|
+
MySubject.accessible_by(ability, :update).to_a.must_include my_subject1
|
115
|
+
MySubject.accessible_by(ability, :update).to_a.must_include my_subject2
|
131
116
|
end
|
132
117
|
end
|
133
118
|
|
119
|
+
describe 'open id locks' do
|
120
|
+
let(:role_1) { MyRole.new(my_locks: [ MyLock.new(subject: my_subject1, action: :update, outcome: true) ]) }
|
121
|
+
|
122
|
+
before do
|
123
|
+
MySubject.default_locks = [ MyLock.new(subject_type: MySubject, action: :update, outcome: false) ]
|
124
|
+
MySubject1.default_locks = []
|
125
|
+
MySubject2.default_locks = []
|
126
|
+
|
127
|
+
my_subject
|
128
|
+
my_subject1
|
129
|
+
my_subject2
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'applies id locks' do
|
133
|
+
MySubject.accessible_by(ability, :update).to_a.wont_include my_subject
|
134
|
+
MySubject1.accessible_by(ability, :update).to_a.must_include my_subject1
|
135
|
+
MySubject2.accessible_by(ability, :update).to_a.wont_include my_subject2
|
136
|
+
end
|
137
|
+
end
|
134
138
|
end
|
135
139
|
end
|
@@ -2,7 +2,6 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
module MongoidAbility
|
4
4
|
describe Subject do
|
5
|
-
|
6
5
|
describe '.default_lock' do
|
7
6
|
before do
|
8
7
|
MySubject.default_locks = []
|
@@ -20,17 +19,6 @@ module MongoidAbility
|
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
# describe 'when lock not defined on superclass' do
|
24
|
-
# before do
|
25
|
-
# MySubject.default_locks = []
|
26
|
-
# MySubject1.default_locks = []
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# it 'must raise error' do
|
30
|
-
# -> { MySubject1.default_lock MyLock, :test, true }.must_raise StandardError
|
31
|
-
# end
|
32
|
-
# end
|
33
|
-
|
34
22
|
describe 'prevents conflicts' do
|
35
23
|
before do
|
36
24
|
MySubject.default_locks = []
|
@@ -39,15 +27,15 @@ module MongoidAbility
|
|
39
27
|
end
|
40
28
|
|
41
29
|
it 'does not allow multiple locks for same action' do
|
42
|
-
MySubject.default_locks.
|
30
|
+
MySubject.default_locks.count { |l| l.action == :read }.must_equal 1
|
43
31
|
end
|
44
32
|
|
45
33
|
it 'replace existing locks with new attributes' do
|
46
|
-
MySubject.default_locks.detect{ |l| l.action == :read }.outcome.must_equal false
|
34
|
+
MySubject.default_locks.detect { |l| l.action == :read }.outcome.must_equal false
|
47
35
|
end
|
48
36
|
|
49
37
|
it 'replaces existing locks with new one' do
|
50
|
-
MySubject.default_locks.detect{ |l| l.action == :read }.class.must_equal MyLock1
|
38
|
+
MySubject.default_locks.detect { |l| l.action == :read }.class.must_equal MyLock1
|
51
39
|
end
|
52
40
|
end
|
53
41
|
|
@@ -57,11 +45,10 @@ module MongoidAbility
|
|
57
45
|
it { MySubject2.is_root_class?.must_equal false }
|
58
46
|
end
|
59
47
|
|
60
|
-
describe
|
48
|
+
describe '.root_class' do
|
61
49
|
it { MySubject.root_class.must_equal MySubject }
|
62
50
|
it { MySubject1.root_class.must_equal MySubject }
|
63
51
|
it { MySubject2.root_class.must_equal MySubject }
|
64
52
|
end
|
65
|
-
|
66
53
|
end
|
67
54
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module MongoidAbility
|
2
|
+
class MyLock
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
include MongoidAbility::Lock
|
6
|
+
|
7
|
+
embedded_in :owner, polymorphic: true, touch: true
|
8
|
+
end
|
9
|
+
|
10
|
+
class MyLock1 < MyLock
|
11
|
+
def calculated_outcome(opts = {})
|
12
|
+
opts.fetch(:override, outcome)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MongoidAbility
|
2
|
+
class MyOwner
|
3
|
+
include Mongoid::Document
|
4
|
+
include Mongoid::Timestamps
|
5
|
+
include MongoidAbility::Owner
|
6
|
+
|
7
|
+
embeds_many :my_locks, class_name: 'MongoidAbility::MyLock', as: :owner
|
8
|
+
has_and_belongs_to_many :my_roles
|
9
|
+
|
10
|
+
def self.locks_relation_name
|
11
|
+
:my_locks
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.inherit_from_relation_name
|
15
|
+
:my_roles
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class MyOwner1 < MyOwner
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MongoidAbility
|
2
|
+
class MyRole
|
3
|
+
include Mongoid::Document
|
4
|
+
include MongoidAbility::Owner
|
5
|
+
|
6
|
+
embeds_many :my_locks, class_name: 'MongoidAbility::MyLock', as: :owner
|
7
|
+
has_and_belongs_to_many :my_owners
|
8
|
+
|
9
|
+
def self.locks_relation_name
|
10
|
+
:my_locks
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class MyRole1 < MyRole
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MongoidAbility
|
2
|
+
class MySubject
|
3
|
+
include Mongoid::Document
|
4
|
+
include MongoidAbility::Subject
|
5
|
+
|
6
|
+
default_lock MyLock, :read, true
|
7
|
+
default_lock MyLock1, :update, false
|
8
|
+
end
|
9
|
+
|
10
|
+
class MySubject1 < MySubject
|
11
|
+
default_lock MyLock, :read, false
|
12
|
+
end
|
13
|
+
|
14
|
+
class MySubject2 < MySubject1
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -9,8 +9,8 @@ require 'mongoid_ability'
|
|
9
9
|
|
10
10
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
11
11
|
|
12
|
-
if ENV[
|
13
|
-
require
|
12
|
+
if ENV['CI']
|
13
|
+
require 'coveralls'
|
14
14
|
Coveralls.wear!
|
15
15
|
end
|
16
16
|
|
@@ -28,3 +28,7 @@ class MiniTest::Spec
|
|
28
28
|
before(:each) { DatabaseCleaner.start }
|
29
29
|
after(:each) { DatabaseCleaner.clean }
|
30
30
|
end
|
31
|
+
|
32
|
+
class Object
|
33
|
+
include MongoidAbility::Expectations
|
34
|
+
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomáš Celizna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cancancan
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: coveralls
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,7 +177,11 @@ files:
|
|
177
177
|
- test/mongoid_ability/resolve_owner_locks_test.rb
|
178
178
|
- test/mongoid_ability/subject_accessible_by_test.rb
|
179
179
|
- test/mongoid_ability/subject_test.rb
|
180
|
-
- test/support/
|
180
|
+
- test/support/expectations.rb
|
181
|
+
- test/support/test_classes/my_lock.rb
|
182
|
+
- test/support/test_classes/my_owner.rb
|
183
|
+
- test/support/test_classes/my_role.rb
|
184
|
+
- test/support/test_classes/my_subject.rb
|
181
185
|
- test/test_helper.rb
|
182
186
|
homepage: https://github.com/tomasc/mongoid_ability
|
183
187
|
licenses:
|
@@ -199,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
199
203
|
version: '0'
|
200
204
|
requirements: []
|
201
205
|
rubyforge_project:
|
202
|
-
rubygems_version: 2.4.
|
206
|
+
rubygems_version: 2.4.6
|
203
207
|
signing_key:
|
204
208
|
specification_version: 4
|
205
209
|
summary: Custom Ability class that allows CanCanCan authorization library store permissions
|
@@ -218,5 +222,9 @@ test_files:
|
|
218
222
|
- test/mongoid_ability/resolve_owner_locks_test.rb
|
219
223
|
- test/mongoid_ability/subject_accessible_by_test.rb
|
220
224
|
- test/mongoid_ability/subject_test.rb
|
221
|
-
- test/support/
|
225
|
+
- test/support/expectations.rb
|
226
|
+
- test/support/test_classes/my_lock.rb
|
227
|
+
- test/support/test_classes/my_owner.rb
|
228
|
+
- test/support/test_classes/my_role.rb
|
229
|
+
- test/support/test_classes/my_subject.rb
|
222
230
|
- test/test_helper.rb
|
@@ -1,161 +0,0 @@
|
|
1
|
-
module MongoidAbility
|
2
|
-
class MyLock
|
3
|
-
include Mongoid::Document
|
4
|
-
include MongoidAbility::Lock
|
5
|
-
embedded_in :owner, polymorphic: true
|
6
|
-
end
|
7
|
-
|
8
|
-
class MyLock1 < MyLock
|
9
|
-
def calculated_outcome opts={}
|
10
|
-
opts.fetch(:override, outcome)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# ---------------------------------------------------------------------
|
15
|
-
|
16
|
-
class MySubject
|
17
|
-
include Mongoid::Document
|
18
|
-
include MongoidAbility::Subject
|
19
|
-
|
20
|
-
default_lock MyLock, :read, true
|
21
|
-
default_lock MyLock1, :update, false
|
22
|
-
end
|
23
|
-
|
24
|
-
class MySubject1 < MySubject
|
25
|
-
default_lock MyLock, :read, false
|
26
|
-
end
|
27
|
-
|
28
|
-
class MySubject2 < MySubject1
|
29
|
-
end
|
30
|
-
|
31
|
-
# ---------------------------------------------------------------------
|
32
|
-
|
33
|
-
class MyOwner
|
34
|
-
include Mongoid::Document
|
35
|
-
include MongoidAbility::Owner
|
36
|
-
|
37
|
-
embeds_many :my_locks, class_name: 'MongoidAbility::MyLock', as: :owner
|
38
|
-
has_and_belongs_to_many :my_roles
|
39
|
-
|
40
|
-
def self.locks_relation_name
|
41
|
-
:my_locks
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.inherit_from_relation_name
|
45
|
-
:my_roles
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class MyOwner1 < MyOwner
|
50
|
-
end
|
51
|
-
|
52
|
-
# ---------------------------------------------------------------------
|
53
|
-
|
54
|
-
class MyRole
|
55
|
-
include Mongoid::Document
|
56
|
-
include MongoidAbility::Owner
|
57
|
-
|
58
|
-
embeds_many :my_locks, class_name: 'MongoidAbility::MyLock', as: :owner
|
59
|
-
has_and_belongs_to_many :my_owners
|
60
|
-
|
61
|
-
def self.locks_relation_name
|
62
|
-
:my_locks
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class MyRole1 < MyRole
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# class TestLock
|
77
|
-
# include Mongoid::Document
|
78
|
-
# include MongoidAbility::Lock
|
79
|
-
#
|
80
|
-
# embedded_in :owner, polymorphic: true
|
81
|
-
# end
|
82
|
-
#
|
83
|
-
# class TestLockSub < TestLock
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# # ---------------------------------------------------------------------
|
87
|
-
#
|
88
|
-
# class TestOwnerSuper
|
89
|
-
# include Mongoid::Document
|
90
|
-
# include MongoidAbility::Owner
|
91
|
-
#
|
92
|
-
# embeds_many :test_locks, class_name: 'TestLock', as: :owner
|
93
|
-
# end
|
94
|
-
#
|
95
|
-
# class TestOwner < TestOwnerSuper
|
96
|
-
# end
|
97
|
-
#
|
98
|
-
# # ---------------------------------------------------------------------
|
99
|
-
#
|
100
|
-
# class SubjectTest
|
101
|
-
# include Mongoid::Document
|
102
|
-
# include MongoidAbility::Subject
|
103
|
-
#
|
104
|
-
# default_lock :read, true
|
105
|
-
# end
|
106
|
-
#
|
107
|
-
# class SubjectTestOne < SubjectTest
|
108
|
-
# end
|
109
|
-
#
|
110
|
-
# class SubjectTestTwo < SubjectTest
|
111
|
-
# end
|
112
|
-
#
|
113
|
-
# class SubjectSingleTest
|
114
|
-
# include Mongoid::Document
|
115
|
-
# include MongoidAbility::Subject
|
116
|
-
#
|
117
|
-
# default_lock :read, true
|
118
|
-
# end
|
119
|
-
#
|
120
|
-
# # ---------------------------------------------------------------------
|
121
|
-
#
|
122
|
-
# class TestAbilityResolverSubject
|
123
|
-
# include Mongoid::Document
|
124
|
-
# include MongoidAbility::Subject
|
125
|
-
#
|
126
|
-
# default_lock :read, true
|
127
|
-
# end
|
128
|
-
#
|
129
|
-
# class TestAbilitySubjectSuper2
|
130
|
-
# include Mongoid::Document
|
131
|
-
# include MongoidAbility::Subject
|
132
|
-
#
|
133
|
-
# default_lock :read, false
|
134
|
-
# default_lock :update, true
|
135
|
-
# end
|
136
|
-
#
|
137
|
-
# class TestAbilitySubjectSuper1 < TestAbilitySubjectSuper2
|
138
|
-
# end
|
139
|
-
#
|
140
|
-
# class TestAbilitySubject < TestAbilitySubjectSuper1
|
141
|
-
# end
|
142
|
-
#
|
143
|
-
# # ---------------------------------------------------------------------
|
144
|
-
#
|
145
|
-
# class TestRole
|
146
|
-
# include Mongoid::Document
|
147
|
-
# include MongoidAbility::Owner
|
148
|
-
#
|
149
|
-
# field :name, type: String
|
150
|
-
#
|
151
|
-
# embeds_many :test_locks, class_name: 'TestLock', as: :owner
|
152
|
-
# has_and_belongs_to_many :users, class_name: 'TestUser'
|
153
|
-
# end
|
154
|
-
#
|
155
|
-
# class TestUser
|
156
|
-
# include Mongoid::Document
|
157
|
-
# include MongoidAbility::Owner
|
158
|
-
#
|
159
|
-
# embeds_many :test_locks, class_name: 'TestLock', as: :owner
|
160
|
-
# has_and_belongs_to_many :roles, class_name: 'TestRole'
|
161
|
-
# end
|