toni 0.0.2 → 0.1.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/lib/toni.rb +8 -0
- data/lib/toni/in_model.rb +50 -0
- data/lib/toni/permission.rb +7 -3
- data/lib/toni/permission_filter.rb +81 -0
- data/lib/toni/permission_matcher.rb +4 -54
- data/lib/toni/permission_matcher/base.rb +31 -0
- data/lib/toni/permission_matcher/has_matcher.rb +41 -0
- data/lib/toni/permission_matcher/not_matcher.rb +37 -0
- data/lib/toni/permission_matcher/permitted_to_matcher.rb +15 -0
- data/lib/toni/role.rb +8 -0
- data/lib/toni/version.rb +1 -1
- data/spec/toni/in_model_spec.rb +135 -0
- data/spec/toni/permission_filter_spec.rb +69 -0
- data/spec/toni/permission_matcher_spec.rb +45 -4
- data/spec/toni/permission_spec.rb +19 -11
- data/spec/toni/role_spec.rb +20 -0
- data/spec/toni_spec.rb +13 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14722f9cb78336b60a87caf4ab45e8b7d17c37d1
|
4
|
+
data.tar.gz: dd9abb810b120478e41d070d04efe88dc1bd3b80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ba6677c52e0da7577d75865e2f4484b1b353809dfa0b96b081e32ba9faf877fbe70447d05a85e936863275287ff74b1ee0dce03da490b4d55a4f8d9a4507fb2
|
7
|
+
data.tar.gz: 267549c89b11bd2c3a9c2a9364c318fdc5e2df5294bb3cb50b6c813224e409677ba74b6c3f23f49b7c90f53bf07485dd5f3cb87087ff9aa4a13868ddad00acbb
|
data/lib/toni.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "toni/version"
|
2
2
|
require "toni/anonymous_user"
|
3
|
+
require "toni/permission_filter"
|
3
4
|
require "toni/builder"
|
4
5
|
|
5
6
|
module Toni
|
@@ -10,6 +11,7 @@ module Toni
|
|
10
11
|
class NoMethodForMatcherError < StandardError; end
|
11
12
|
class NotAuthorizedError < StandardError; end
|
12
13
|
class MissingMatcherError < StandardError; end
|
14
|
+
class MissingPermissionFilterError < StandardError; end
|
13
15
|
|
14
16
|
class << self
|
15
17
|
def current_user
|
@@ -40,6 +42,12 @@ module Toni
|
|
40
42
|
roles.select { |role_symbol, r| current_user.role_symbols.include?(role_symbol) }.values
|
41
43
|
end
|
42
44
|
|
45
|
+
def current_permissions_for(activity, resource_or_name)
|
46
|
+
current_roles.map do |r|
|
47
|
+
r.permissions_for(activity, resource_or_name)
|
48
|
+
end.flatten
|
49
|
+
end
|
50
|
+
|
43
51
|
def without_authorization(&block)
|
44
52
|
@without_authorization = true
|
45
53
|
result = block_given? ? yield : nil
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Toni
|
2
|
+
module InModel
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
|
6
|
+
[:create, :update, :destroy].each do |action|
|
7
|
+
base.send(:"before_#{action}") do |object|
|
8
|
+
activity = action == :destroy ? :delete : action
|
9
|
+
Toni.permitted_to?(activity, object, bang: true)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
base.send(:after_find) do |object|
|
14
|
+
Toni.permitted_to?(:read, object, bang: true)
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: Should be active record only
|
18
|
+
base.scope :permitted_to, -> {
|
19
|
+
base.send(:filter_by_permissions)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def filter_by_permissions
|
28
|
+
where(*scope_for_filter_permissions)
|
29
|
+
end
|
30
|
+
|
31
|
+
def scope_for_filter_permissions
|
32
|
+
permissions = Toni.current_permissions_for(:read, authorization_context)
|
33
|
+
return ["0 = 1"] if permissions.empty?
|
34
|
+
permissions.inject([""]) do |cond, p|
|
35
|
+
conditions = p.matchers.map(&:filter_condition).compact.inject([""]) do |cond2, filter_cond|
|
36
|
+
concat_filters(cond2, filter_cond)
|
37
|
+
end
|
38
|
+
concat_filters(cond, conditions, " OR ")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def concat_filters(cond, conditions, separator=" AND ")
|
43
|
+
return cond if conditions[0] == ""
|
44
|
+
cond[0] = "#{cond[0]}#{separator unless cond[0].empty?}(#{conditions[0]})"
|
45
|
+
cond.push(*conditions[1..-1])
|
46
|
+
cond
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/toni/permission.rb
CHANGED
@@ -12,12 +12,16 @@ module Toni
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def add_matcher(method_name, matcher, is_attr = false)
|
15
|
-
@matchers << PermissionMatcher.new(method_name, matcher, is_attr)
|
15
|
+
@matchers << PermissionMatcher::Base.new(method_name, matcher, is_attr)
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
18
|
+
def permission_for?(activity, res)
|
19
19
|
resource_name == (res.is_a?(Symbol) ? res : res.class.authorization_context) &&
|
20
|
-
activities.include?(activity)
|
20
|
+
activities.include?(activity)
|
21
|
+
end
|
22
|
+
|
23
|
+
def permitted_to?(activity, res, options={})
|
24
|
+
permission_for?(activity, res) && matches?(res)
|
21
25
|
end
|
22
26
|
|
23
27
|
private
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Toni
|
2
|
+
class PermissionFilter
|
3
|
+
attr_reader :permission_matcher
|
4
|
+
|
5
|
+
def self.permission_filters
|
6
|
+
@filterable_matchers ||= constants.select do |c|
|
7
|
+
const_get(c).is_a?(Class)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(permission_matcher)
|
12
|
+
@permission_matcher = permission_matcher
|
13
|
+
end
|
14
|
+
|
15
|
+
def filter_condition
|
16
|
+
raise "implement me"
|
17
|
+
end
|
18
|
+
|
19
|
+
def matcher
|
20
|
+
permission_matcher.matcher
|
21
|
+
end
|
22
|
+
|
23
|
+
def attr_name
|
24
|
+
permission_matcher.method_name
|
25
|
+
end
|
26
|
+
|
27
|
+
class Eq < PermissionFilter
|
28
|
+
def filter_condition
|
29
|
+
["#{attr_name} = ?", matcher.expected]
|
30
|
+
end
|
31
|
+
|
32
|
+
def filter_condition_inverse
|
33
|
+
["#{attr_name} != ?", matcher.expected]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class BeNil < PermissionFilter
|
38
|
+
def filter_condition
|
39
|
+
["#{attr_name} IS NULL"]
|
40
|
+
end
|
41
|
+
|
42
|
+
def filter_condition_inverse
|
43
|
+
["#{attr_name} IS NOT NULL"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class BeTruthy < PermissionFilter
|
48
|
+
def filter_condition
|
49
|
+
["#{attr_name} IS NOT NULL AND #{attr_name} != ''"]
|
50
|
+
end
|
51
|
+
|
52
|
+
def filter_condition_inverse
|
53
|
+
BeFalsey.new(permission_matcher).filter_condition
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class BeFalsey < PermissionFilter
|
58
|
+
def filter_condition
|
59
|
+
["#{attr_name} = '' OR #{attr_name} IS NULL"]
|
60
|
+
end
|
61
|
+
|
62
|
+
def filter_condition_inverse
|
63
|
+
BeTruthy.new(permission_matcher).filter_condition
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class BeBetween < PermissionFilter
|
68
|
+
def filter_condition
|
69
|
+
["#{attr_name} >= ? AND #{attr_name} <= ?",
|
70
|
+
matcher.instance_variable_get(:@min),
|
71
|
+
matcher.instance_variable_get(:@max)]
|
72
|
+
end
|
73
|
+
|
74
|
+
def filter_condition_inverse
|
75
|
+
["#{attr_name} < ? OR #{attr_name} > ?",
|
76
|
+
matcher.instance_variable_get(:@min),
|
77
|
+
matcher.instance_variable_get(:@max)]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,54 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(method_name, matcher, is_attr = false)
|
7
|
-
@method_name = method_name
|
8
|
-
@matcher = matcher
|
9
|
-
@is_attr = is_attr
|
10
|
-
end
|
11
|
-
|
12
|
-
def matches?(object)
|
13
|
-
unless object.respond_to?(method_name)
|
14
|
-
raise Toni::NoMethodForMatcherError.new("#{method_name} is not defined for #{object.inspect}")
|
15
|
-
end
|
16
|
-
matcher.matches?(object.send(method_name))
|
17
|
-
end
|
18
|
-
|
19
|
-
class NotMatcher
|
20
|
-
attr_reader :matcher
|
21
|
-
|
22
|
-
def initialize
|
23
|
-
@matcher = nil
|
24
|
-
end
|
25
|
-
|
26
|
-
def method_missing(method_name, *args)
|
27
|
-
builder = Toni::Builder::ExpectationBuilder.new
|
28
|
-
if builder.respond_to?(method_name)
|
29
|
-
@matcher = builder.send(method_name, *args)
|
30
|
-
else
|
31
|
-
super
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def matches?(object)
|
36
|
-
raise Toni::MissingMatcherError if @matcher.nil?
|
37
|
-
!@matcher.matches?(object)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class PermittedToMatcher
|
42
|
-
|
43
|
-
def initialize(activity)
|
44
|
-
@activity = activity
|
45
|
-
end
|
46
|
-
|
47
|
-
def matches?(object)
|
48
|
-
Toni.permitted_to?(@activity, object)
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
1
|
+
require 'toni/permission_matcher/has_matcher'
|
2
|
+
require 'toni/permission_matcher/base'
|
3
|
+
require 'toni/permission_matcher/not_matcher'
|
4
|
+
require 'toni/permission_matcher/permitted_to_matcher'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Toni
|
2
|
+
module PermissionMatcher
|
3
|
+
|
4
|
+
class Base
|
5
|
+
|
6
|
+
include HasMatcher
|
7
|
+
|
8
|
+
attr_reader :method_name, :is_attr
|
9
|
+
|
10
|
+
def initialize(method_name, matcher, is_attr = false)
|
11
|
+
@method_name = method_name
|
12
|
+
@matcher = matcher
|
13
|
+
@is_attr = is_attr
|
14
|
+
end
|
15
|
+
|
16
|
+
def matches?(object)
|
17
|
+
unless object.respond_to?(method_name)
|
18
|
+
raise Toni::NoMethodForMatcherError.new("#{method_name} is not defined for #{object.inspect}")
|
19
|
+
end
|
20
|
+
matcher.matches?(object.send(method_name))
|
21
|
+
end
|
22
|
+
|
23
|
+
def filter_condition
|
24
|
+
return nil unless is_attr
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Toni
|
2
|
+
module PermissionMatcher
|
3
|
+
|
4
|
+
module HasMatcher
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.send(:attr_reader, :matcher)
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(object)
|
11
|
+
raise "implement me"
|
12
|
+
end
|
13
|
+
|
14
|
+
def filter_condition
|
15
|
+
return matcher.filter_condition if matcher.respond_to?(:filter_condition)
|
16
|
+
|
17
|
+
filter = permission_filter
|
18
|
+
if filter.nil?
|
19
|
+
raise Toni::MissingPermissionFilterError.new("No permission matcher for #{matcher.class.inspect}")
|
20
|
+
end
|
21
|
+
|
22
|
+
filter.filter_condition
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def permission_filter
|
28
|
+
if permission_filter_class
|
29
|
+
Toni::PermissionFilter.const_get(permission_filter_class).new(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def permission_filter_class
|
34
|
+
@permission_filter ||= Toni::PermissionFilter.permission_filters.detect do |c|
|
35
|
+
!matcher.class.name.nil? && c.to_s.split('::').last == matcher.class.name.split('::').last
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Toni
|
2
|
+
module PermissionMatcher
|
3
|
+
|
4
|
+
class NotMatcher
|
5
|
+
|
6
|
+
include HasMatcher
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@matcher = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(method_name, *args)
|
13
|
+
builder = Toni::Builder::ExpectationBuilder.new
|
14
|
+
if builder.respond_to?(method_name)
|
15
|
+
@matcher = builder.send(method_name, *args)
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches?(object)
|
22
|
+
raise Toni::MissingMatcherError if @matcher.nil?
|
23
|
+
!@matcher.matches?(object)
|
24
|
+
end
|
25
|
+
|
26
|
+
def filter_condition
|
27
|
+
filter = permission_filter
|
28
|
+
unless filter && filter.respond_to?(:filter_condition_inverse)
|
29
|
+
raise Toni::MissingPermissionFilterError.new("No permission matcher for #{matcher.class.inspect}")
|
30
|
+
end
|
31
|
+
|
32
|
+
filter.filter_condition_inverse
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/toni/role.rb
CHANGED
@@ -26,6 +26,14 @@ module Toni
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def permissions_for(activity, res)
|
30
|
+
unless res.is_a?(Symbol) || res.class.respond_to?(:authorization_context)
|
31
|
+
raise Toni::NoAuthorizationContextProvidedError
|
32
|
+
end
|
33
|
+
res = res.class.authorization_context unless res.is_a?(Symbol)
|
34
|
+
current_permissions.select { |p| p.permission_for?(activity, res) }
|
35
|
+
end
|
36
|
+
|
29
37
|
private
|
30
38
|
|
31
39
|
def current_permissions
|
data/lib/toni/version.rb
CHANGED
@@ -0,0 +1,135 @@
|
|
1
|
+
require "toni"
|
2
|
+
require "toni/in_model"
|
3
|
+
require "active_record"
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe Toni::InModel do
|
7
|
+
let(:record_class) do
|
8
|
+
Class.new(ActiveRecord::Base) do
|
9
|
+
def self.table_name
|
10
|
+
:test
|
11
|
+
end
|
12
|
+
def self.authorization_context
|
13
|
+
:resource_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:record) { record_class.new }
|
19
|
+
|
20
|
+
before do
|
21
|
+
record_class.destroy_all
|
22
|
+
allow(Toni).to receive(:current_roles) { [] }
|
23
|
+
end
|
24
|
+
|
25
|
+
context :before_filter do
|
26
|
+
it "adds before filter on include" do
|
27
|
+
expect(record_class).to receive(:before_destroy)
|
28
|
+
expect(record_class).to receive(:before_create)
|
29
|
+
expect(record_class).to receive(:before_update)
|
30
|
+
expect(record_class).to receive(:after_find)
|
31
|
+
record_class.send(:include, Toni::InModel)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "calls permitted_to? if records gets found" do
|
35
|
+
record_class.send(:include, Toni::InModel)
|
36
|
+
Toni.without_authorization { record.save }
|
37
|
+
allow(Toni).to receive(:permitted_to?) { true }
|
38
|
+
expect(Toni).to receive(:permitted_to?).with(:read, record_class, bang: true)
|
39
|
+
record_class.find(record.id)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "calls permitted_to? if records gets created" do
|
43
|
+
record_class.send(:include, Toni::InModel)
|
44
|
+
allow(Toni).to receive(:permitted_to?) { true }
|
45
|
+
expect(Toni).to receive(:permitted_to?).with(:create, record_class, bang: true)
|
46
|
+
record.save
|
47
|
+
end
|
48
|
+
|
49
|
+
it "calls permitted_to? if records gets updated" do
|
50
|
+
record_class.send(:include, Toni::InModel)
|
51
|
+
allow(Toni).to receive(:permitted_to?) { true }
|
52
|
+
record.save
|
53
|
+
record.foo = :x
|
54
|
+
expect(Toni).to receive(:permitted_to?).with(:update, record_class, bang: true)
|
55
|
+
record.save
|
56
|
+
end
|
57
|
+
|
58
|
+
it "calls permitted_to? if records gets destroyes" do
|
59
|
+
record_class.send(:include, Toni::InModel)
|
60
|
+
allow(Toni).to receive(:permitted_to?) { true }
|
61
|
+
record.save
|
62
|
+
expect(Toni).to receive(:permitted_to?).with(:delete, record_class, bang: true)
|
63
|
+
record.destroy
|
64
|
+
end
|
65
|
+
|
66
|
+
it "does not create record if permitted_to bangs" do
|
67
|
+
record_class.send(:include, Toni::InModel)
|
68
|
+
allow(Toni).to receive(:permitted_to?) { raise Toni::NotAuthorizedError }
|
69
|
+
expect { record.save }.to raise_error(Toni::NotAuthorizedError)
|
70
|
+
expect(record_class.count).to eq(0)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "does not update record if permitted_to bangs" do
|
74
|
+
record_class.send(:include, Toni::InModel)
|
75
|
+
Toni.without_authorization { record.save }
|
76
|
+
allow(Toni).to receive(:permitted_to?) { raise Toni::NotAuthorizedError }
|
77
|
+
record.foo = :x
|
78
|
+
expect { record.save }.to raise_error(Toni::NotAuthorizedError)
|
79
|
+
expect(record_class.count).to eq(1)
|
80
|
+
allow(Toni).to receive(:permitted_to?) { true }
|
81
|
+
expect(record_class.first.foo).to be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it "does not destroy record if permitted_to bangs" do
|
85
|
+
record_class.send(:include, Toni::InModel)
|
86
|
+
Toni.without_authorization { record.save }
|
87
|
+
allow(Toni).to receive(:permitted_to?) { raise Toni::NotAuthorizedError }
|
88
|
+
expect { record.destroy }.to raise_error(Toni::NotAuthorizedError)
|
89
|
+
expect(record_class.count).to eq(1)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context :scope do
|
94
|
+
|
95
|
+
let(:matcher) { RSpec::Matchers::BuiltIn::BeNil.new }
|
96
|
+
let(:matcher2) { RSpec::Matchers::BuiltIn::Eq.new("x") }
|
97
|
+
let(:matcher3) { RSpec::Matchers::BuiltIn::Eq.new("y") }
|
98
|
+
let(:permission) do
|
99
|
+
p = Toni::Permission.new(:resource_name, [:read, :create])
|
100
|
+
p.add_matcher(:foo, matcher, true)
|
101
|
+
p.add_matcher(:bar, matcher2, true)
|
102
|
+
p
|
103
|
+
end
|
104
|
+
let(:permission2) do
|
105
|
+
p = Toni::Permission.new(:resource_name, [:read])
|
106
|
+
p.add_matcher(:foo, matcher3, true)
|
107
|
+
p
|
108
|
+
end
|
109
|
+
|
110
|
+
it "creates a scope" do
|
111
|
+
expect(record_class).to receive(:scope).with(:permitted_to, anything)
|
112
|
+
record_class.send(:include, Toni::InModel)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "creates a useful scope" do
|
116
|
+
record_class.send(:include, Toni::InModel)
|
117
|
+
allow(Toni).to receive(:current_permissions_for).with(:read, :resource_name) do
|
118
|
+
[permission, permission2]
|
119
|
+
end
|
120
|
+
expect(record_class.send(:scope_for_filter_permissions)).to eq(["((foo IS NULL) AND (bar = ?)) OR ((foo = ?))", "x", "y"])
|
121
|
+
end
|
122
|
+
|
123
|
+
it "scopes permitted_to" do
|
124
|
+
allow(Toni).to receive(:current_permissions_for).with(:read, :resource_name) do
|
125
|
+
[permission, permission2]
|
126
|
+
end
|
127
|
+
record_class.send(:include, Toni::InModel)
|
128
|
+
allow(Toni).to receive(:permitted_to?) { true }
|
129
|
+
r1 = record_class.create(foo: "x", bar: "y")
|
130
|
+
r2 = record_class.create(foo: nil, bar: "x")
|
131
|
+
r3 = record_class.create(foo: "y", bar: "something")
|
132
|
+
expect(record_class.permitted_to.map(&:id)).to eq([r2.id, r3.id])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "toni"
|
3
|
+
require "ostruct"
|
4
|
+
|
5
|
+
describe Toni::PermissionFilter do
|
6
|
+
|
7
|
+
let(:expectation_builder) { Toni::Builder::ExpectationBuilder.new }
|
8
|
+
let(:matcher) { expectation_builder.eq("test") }
|
9
|
+
let(:permission_matcher) { Toni::PermissionMatcher::Base.new(:foo, matcher, true) }
|
10
|
+
|
11
|
+
let(:permission_filter) do
|
12
|
+
described_class.new(permission_matcher)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ".permission_filters" do
|
16
|
+
it "returns constants of available permission filters" do
|
17
|
+
expect(Toni::PermissionFilter.permission_filters).to match_array([
|
18
|
+
:Eq, :BeNil, :BeTruthy, :BeFalsey, :BeBetween
|
19
|
+
])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Toni::PermissionFilter::Eq do
|
24
|
+
it "creates condition" do
|
25
|
+
expect(permission_filter.filter_condition).to eq(["foo = ?", "test"])
|
26
|
+
end
|
27
|
+
it "creates opposite condition" do
|
28
|
+
expect(permission_filter.filter_condition_inverse).to eq(["foo != ?", "test"])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe Toni::PermissionFilter::BeNil do
|
33
|
+
it "creates condition" do
|
34
|
+
expect(permission_filter.filter_condition).to eq(["foo IS NULL"])
|
35
|
+
end
|
36
|
+
it "creates opposite condition" do
|
37
|
+
expect(permission_filter.filter_condition_inverse).to eq(["foo IS NOT NULL"])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe Toni::PermissionFilter::BeTruthy do
|
42
|
+
it "creates condition" do
|
43
|
+
expect(permission_filter.filter_condition).to eq(["foo IS NOT NULL AND foo != ''"])
|
44
|
+
end
|
45
|
+
it "creates opposite condition" do
|
46
|
+
expect(permission_filter.filter_condition_inverse).to eq(["foo = '' OR foo IS NULL"])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe Toni::PermissionFilter::BeFalsey do
|
51
|
+
it "creates condition" do
|
52
|
+
expect(permission_filter.filter_condition).to eq(["foo = '' OR foo IS NULL"])
|
53
|
+
end
|
54
|
+
it "creates opposite condition" do
|
55
|
+
expect(permission_filter.filter_condition_inverse).to eq(["foo IS NOT NULL AND foo != ''"])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe Toni::PermissionFilter::BeBetween do
|
60
|
+
let(:matcher) { expectation_builder.be_between(5, 10) }
|
61
|
+
it "creates condition" do
|
62
|
+
expect(permission_filter.filter_condition).to eq(["foo >= ? AND foo <= ?", 5, 10])
|
63
|
+
end
|
64
|
+
it "creates opposite condition" do
|
65
|
+
expect(permission_filter.filter_condition_inverse).to eq(["foo < ? OR foo > ?", 5, 10])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -12,11 +12,11 @@ describe Toni::PermissionMatcher do
|
|
12
12
|
end
|
13
13
|
end.new
|
14
14
|
end
|
15
|
-
let(:permission_matcher) { Toni::PermissionMatcher.new(:foo, matcher) }
|
15
|
+
let(:permission_matcher) { Toni::PermissionMatcher::Base.new(:foo, matcher) }
|
16
16
|
|
17
17
|
describe :method_name do
|
18
18
|
it "sets the method_name on initialize" do
|
19
|
-
expect(Toni::PermissionMatcher.new(:method_name, nil).method_name).to eq(:method_name)
|
19
|
+
expect(Toni::PermissionMatcher::Base.new(:method_name, nil).method_name).to eq(:method_name)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -32,6 +32,33 @@ describe Toni::PermissionMatcher do
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
describe :filter_condition do
|
36
|
+
let(:expectation_builder) { Toni::Builder::ExpectationBuilder.new }
|
37
|
+
let(:matcher2) { expectation_builder.eq("test") }
|
38
|
+
let(:permission_matcher) { Toni::PermissionMatcher::Base.new(:foo, matcher2, true) }
|
39
|
+
|
40
|
+
it "return nil if is_attr is false" do
|
41
|
+
permission_matcher = Toni::PermissionMatcher::Base.new(:foo, matcher2, false)
|
42
|
+
expect(permission_matcher.filter_condition).to eq(nil)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "gets filter condition from filterable permission matcher if it exist" do
|
46
|
+
expect_any_instance_of(Toni::PermissionFilter::Eq).to receive(:filter_condition)
|
47
|
+
permission_matcher.filter_condition
|
48
|
+
end
|
49
|
+
|
50
|
+
it "raises error when permission matcher is not available" do
|
51
|
+
allow(permission_matcher).to receive(:permission_filter) { nil }
|
52
|
+
expect { permission_matcher.filter_condition }.to raise_error(Toni::MissingPermissionFilterError)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "uses filter_condition method of matcher if matcher responds" do
|
56
|
+
allow(matcher2).to receive(:respond_to?) { true }
|
57
|
+
expect(matcher2).to receive(:filter_condition) { "condition" }
|
58
|
+
expect(permission_matcher.filter_condition).to eq("condition")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
35
62
|
describe :matches? do
|
36
63
|
let(:object) do
|
37
64
|
Class.new do
|
@@ -66,14 +93,14 @@ describe Toni::PermissionMatcher do
|
|
66
93
|
|
67
94
|
it "returns true if matcher is rspec nil matcher and value is nil" do
|
68
95
|
matcher = RSpec::Matchers::BuiltIn::BeNil.new
|
69
|
-
permission_matcher = Toni::PermissionMatcher.new(:foo, matcher)
|
96
|
+
permission_matcher = Toni::PermissionMatcher::Base.new(:foo, matcher)
|
70
97
|
expect(permission_matcher.matches?(object)).to eq(true)
|
71
98
|
end
|
72
99
|
|
73
100
|
it "returns false if matcher is rspec nil matcher and value is not nil" do
|
74
101
|
allow(object).to receive(:foo) { "a string" }
|
75
102
|
matcher = RSpec::Matchers::BuiltIn::BeNil.new
|
76
|
-
permission_matcher = Toni::PermissionMatcher.new(:foo, matcher)
|
103
|
+
permission_matcher = Toni::PermissionMatcher::Base.new(:foo, matcher)
|
77
104
|
expect(permission_matcher.matches?(object)).to eq(false)
|
78
105
|
end
|
79
106
|
end
|
@@ -103,6 +130,20 @@ describe Toni::PermissionMatcher::NotMatcher do
|
|
103
130
|
end
|
104
131
|
end
|
105
132
|
|
133
|
+
describe :filter_condition do
|
134
|
+
it "gets filter condition from child matcher if it responds to filter_condition_inverse" do
|
135
|
+
not_matcher.be_truthy
|
136
|
+
expect_any_instance_of(Toni::PermissionFilter::BeTruthy).to receive(:filter_condition_inverse)
|
137
|
+
not_matcher.filter_condition
|
138
|
+
end
|
139
|
+
|
140
|
+
it "raises error when child matcher does not respond to filter_condition_inverse" do
|
141
|
+
not_matcher.be_truthy
|
142
|
+
allow_any_instance_of(Toni::PermissionFilter::BeTruthy).to receive(:respond_to?) { false }
|
143
|
+
expect { not_matcher.filter_condition }.to raise_error(Toni::MissingPermissionFilterError)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
106
147
|
end
|
107
148
|
|
108
149
|
describe Toni::PermissionMatcher::PermittedToMatcher do
|
@@ -21,7 +21,22 @@ describe Toni::Permission do
|
|
21
21
|
describe :add_matcher do
|
22
22
|
it "adds the matcher" do
|
23
23
|
permission.add_matcher(:foo, nil)
|
24
|
-
expect(permission.matchers.first).to be_instance_of(Toni::PermissionMatcher)
|
24
|
+
expect(permission.matchers.first).to be_instance_of(Toni::PermissionMatcher::Base)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe :permission_for? do
|
29
|
+
let(:permission) do
|
30
|
+
Toni::Permission.new(:resource_name, [:read, :create])
|
31
|
+
end
|
32
|
+
it "should be allowed to read resource_name" do
|
33
|
+
expect(permission.permission_for?(:read, :resource_name)).to eq(true)
|
34
|
+
end
|
35
|
+
it "should be allowed to delete resource_name" do
|
36
|
+
expect(permission.permission_for?(:delete, :resource_name)).to eq(false)
|
37
|
+
end
|
38
|
+
it "should be allowed to read xxx" do
|
39
|
+
expect(permission.permission_for?(:read, :xxx)).to eq(false)
|
25
40
|
end
|
26
41
|
end
|
27
42
|
|
@@ -31,16 +46,9 @@ describe Toni::Permission do
|
|
31
46
|
Toni::Permission.new(:resource_name, [:read, :create])
|
32
47
|
end
|
33
48
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
it "should be allowed to delete resource_name" do
|
39
|
-
expect(permission.permitted_to?(:delete, :resource_name)).to eq(false)
|
40
|
-
end
|
41
|
-
it "should be allowed to read xxx" do
|
42
|
-
expect(permission.permitted_to?(:read, :xxx)).to eq(false)
|
43
|
-
end
|
49
|
+
it "calls permission_for?" do
|
50
|
+
expect(permission).to receive(:permission_for?).with(:read, :resource_name) { true }
|
51
|
+
expect(permission.permitted_to?(:read, :resource_name)).to eq(true)
|
44
52
|
end
|
45
53
|
|
46
54
|
context "with matchers" do
|
data/spec/toni/role_spec.rb
CHANGED
@@ -34,6 +34,26 @@ describe Toni::Role do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
describe :permissions_for do
|
38
|
+
|
39
|
+
let(:permission) { Toni::Permission.new(:resource_name, [:read, :create]) }
|
40
|
+
let(:permission2) { Toni::Permission.new(:other_resource, [:read, :create]) }
|
41
|
+
|
42
|
+
let(:role) do
|
43
|
+
role = Toni::Role.new(:user)
|
44
|
+
role.add_permission(permission)
|
45
|
+
role.add_permission(permission2)
|
46
|
+
role
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns all permissions that are belonging to resource and activity" do
|
50
|
+
allow(permission).to receive(:permission_for?).with(:read, :resource_name) { true }
|
51
|
+
allow(permission2).to receive(:permission_for?).with(:read, :resource_name) { false }
|
52
|
+
expect(role.permissions_for(:read, :resource_name)).to eq([permission])
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
37
57
|
describe :permitted_to? do
|
38
58
|
|
39
59
|
let(:permission) do
|
data/spec/toni_spec.rb
CHANGED
@@ -56,6 +56,19 @@ describe Toni do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
describe ".current_permissions_for" do
|
60
|
+
let(:user_role) { Toni::Role.new(:user) }
|
61
|
+
let(:seller_role) { Toni::Role.new(:seller) }
|
62
|
+
let(:permission1) { Toni::Permission.new(:books, [:read]) }
|
63
|
+
let(:permission2) { Toni::Permission.new(:books, [:read]) }
|
64
|
+
it "gets the permissions that are assigned to current roles for a specific resource" do
|
65
|
+
allow(Toni).to receive(:current_roles) { [user_role, seller_role] }
|
66
|
+
expect(user_role).to receive(:permissions_for).with(:read, :books) { [permission1] }
|
67
|
+
expect(seller_role).to receive(:permissions_for).with(:read, :books) { [permission2] }
|
68
|
+
expect(Toni.current_permissions_for(:read, :books)).to eq([permission1, permission2])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
59
72
|
describe ".without_authorization" do
|
60
73
|
it "executes block without authorization and returns result of the given block" do
|
61
74
|
with_authorization = Toni.permitted_to?(:something, :test)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: toni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jalyna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec-expectations
|
@@ -131,8 +131,14 @@ files:
|
|
131
131
|
- lib/toni.rb
|
132
132
|
- lib/toni/anonymous_user.rb
|
133
133
|
- lib/toni/builder.rb
|
134
|
+
- lib/toni/in_model.rb
|
134
135
|
- lib/toni/permission.rb
|
136
|
+
- lib/toni/permission_filter.rb
|
135
137
|
- lib/toni/permission_matcher.rb
|
138
|
+
- lib/toni/permission_matcher/base.rb
|
139
|
+
- lib/toni/permission_matcher/has_matcher.rb
|
140
|
+
- lib/toni/permission_matcher/not_matcher.rb
|
141
|
+
- lib/toni/permission_matcher/permitted_to_matcher.rb
|
136
142
|
- lib/toni/role.rb
|
137
143
|
- lib/toni/rspec_helper.rb
|
138
144
|
- lib/toni/sinatra.rb
|
@@ -140,6 +146,8 @@ files:
|
|
140
146
|
- spec/spec_helper.rb
|
141
147
|
- spec/toni/anonymous_user_spec.rb
|
142
148
|
- spec/toni/builder_spec.rb
|
149
|
+
- spec/toni/in_model_spec.rb
|
150
|
+
- spec/toni/permission_filter_spec.rb
|
143
151
|
- spec/toni/permission_matcher_spec.rb
|
144
152
|
- spec/toni/permission_spec.rb
|
145
153
|
- spec/toni/role_spec.rb
|
@@ -177,6 +185,8 @@ test_files:
|
|
177
185
|
- spec/spec_helper.rb
|
178
186
|
- spec/toni/anonymous_user_spec.rb
|
179
187
|
- spec/toni/builder_spec.rb
|
188
|
+
- spec/toni/in_model_spec.rb
|
189
|
+
- spec/toni/permission_filter_spec.rb
|
180
190
|
- spec/toni/permission_matcher_spec.rb
|
181
191
|
- spec/toni/permission_spec.rb
|
182
192
|
- spec/toni/role_spec.rb
|