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