mongoid_ability 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|