consent 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/consent.gemspec +3 -0
- data/lib/consent.rb +12 -19
- data/lib/consent/ability.rb +15 -6
- data/lib/consent/action.rb +8 -5
- data/lib/consent/dsl.rb +2 -1
- data/lib/consent/rspec.rb +12 -72
- data/lib/consent/rspec/consent_action.rb +65 -0
- data/lib/consent/rspec/consent_view.rb +79 -0
- data/lib/consent/version.rb +1 -1
- metadata +46 -3
- data/lib/consent/permission.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 925e2e71db7ce7b4c7104784bbd54cfeb8273b2502f0f73f599e64754d5a010a
|
4
|
+
data.tar.gz: 256326fbd83020d39881b53eadc1b3b7cb9c5169bedee5aac5491661a0e3023b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84ee14b357d0edd8c7be190cc4f79e67d6a0a7f8e0f869d1bf15b0d1ebe87e6f076939aa9db684c172eec8f489bb83f8794c3ca0946a4edc569c07f04a6a9889
|
7
|
+
data.tar.gz: 490da917b1363a0b5d2f209df9363978764874fbe74d500c548b91a95f16f3ca35fab2a80a1ab7ac4de7364e7892101efc4e4a022d25683d0dc82896c7b39da9
|
data/consent.gemspec
CHANGED
@@ -20,9 +20,12 @@ Gem::Specification.new do |spec|
|
|
20
20
|
end
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
|
+
spec.add_development_dependency 'activerecord', '>= 5'
|
23
24
|
spec.add_development_dependency 'bundler', '>= 1.17.3'
|
24
25
|
spec.add_development_dependency 'cancancan', '~> 1.15.0'
|
26
|
+
spec.add_development_dependency 'pry', '~> 0.14.1'
|
25
27
|
spec.add_development_dependency 'rake', '>= 12.3.3'
|
26
28
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
29
|
spec.add_development_dependency 'rubocop', '~> 0.65.0'
|
30
|
+
spec.add_development_dependency 'sqlite3', '~> 1.4.2'
|
28
31
|
end
|
data/lib/consent.rb
CHANGED
@@ -5,7 +5,6 @@ require 'consent/subject'
|
|
5
5
|
require 'consent/view'
|
6
6
|
require 'consent/action'
|
7
7
|
require 'consent/dsl'
|
8
|
-
require 'consent/permission'
|
9
8
|
require 'consent/ability' if defined?(CanCan)
|
10
9
|
require 'consent/railtie' if defined?(Rails)
|
11
10
|
|
@@ -13,6 +12,8 @@ require 'consent/railtie' if defined?(Rails)
|
|
13
12
|
# concise DSL for authorization so that all abilities do not have
|
14
13
|
# to be in your `Ability` class.
|
15
14
|
module Consent
|
15
|
+
ViewNotFound = Class.new(StandardError)
|
16
|
+
|
16
17
|
# Default views available to every permission
|
17
18
|
#
|
18
19
|
# i.e.:
|
@@ -35,7 +36,7 @@ module Consent
|
|
35
36
|
#
|
36
37
|
# @return [Array<Consent::Subject>]
|
37
38
|
def self.find_subjects(subject_key)
|
38
|
-
|
39
|
+
subjects.find_all do |subject|
|
39
40
|
subject.key.eql?(subject_key)
|
40
41
|
end
|
41
42
|
end
|
@@ -44,21 +45,20 @@ module Consent
|
|
44
45
|
#
|
45
46
|
# @return [Consent::Action,nil]
|
46
47
|
def self.find_action(subject_key, action_key)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
find_subjects(subject_key)
|
49
|
+
.flat_map(&:actions)
|
50
|
+
.find do |action|
|
51
|
+
action.key.eql?(action_key)
|
52
|
+
end
|
52
53
|
end
|
53
54
|
|
54
55
|
# Finds a view within a subject context
|
55
56
|
#
|
56
57
|
# @return [Consent::View,nil]
|
57
|
-
def self.find_view(subject_key, view_key)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
views[view_key]
|
58
|
+
def self.find_view(subject_key, action_key, view_key)
|
59
|
+
find_action(subject_key, action_key)&.yield_self do |action|
|
60
|
+
action.views[view_key] || raise(Consent::ViewNotFound)
|
61
|
+
end
|
62
62
|
end
|
63
63
|
|
64
64
|
# Loads all permission (ruby) files from the given directory
|
@@ -87,11 +87,4 @@ module Consent
|
|
87
87
|
DSL.build(subject, defaults, &block)
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
91
|
-
# Maps a permissions hash to a Consent::Permissions
|
92
|
-
#
|
93
|
-
# @return [Consent::Permissions]
|
94
|
-
def self.permissions(permissions)
|
95
|
-
Permissions.new(permissions)
|
96
|
-
end
|
97
90
|
end
|
data/lib/consent/ability.rb
CHANGED
@@ -10,17 +10,26 @@ module Consent
|
|
10
10
|
apply_defaults! if apply_defaults
|
11
11
|
end
|
12
12
|
|
13
|
-
def consent(
|
14
|
-
|
15
|
-
|
13
|
+
def consent!(subject: nil, action: nil, view: nil)
|
14
|
+
view = case view
|
15
|
+
when Consent::View
|
16
|
+
view
|
17
|
+
when Symbol
|
18
|
+
Consent.find_view(subject, action, view)
|
19
|
+
end
|
16
20
|
|
17
21
|
can(
|
18
|
-
|
19
|
-
|
20
|
-
&permission.object_conditions(*@context)
|
22
|
+
action, subject,
|
23
|
+
view&.conditions(*@context), &view&.object_conditions(*@context)
|
21
24
|
)
|
22
25
|
end
|
23
26
|
|
27
|
+
def consent(**kwargs)
|
28
|
+
consent!(**kwargs)
|
29
|
+
rescue Consent::ViewNotFound
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
24
33
|
private
|
25
34
|
|
26
35
|
def apply_defaults!
|
data/lib/consent/action.rb
CHANGED
@@ -2,20 +2,23 @@
|
|
2
2
|
|
3
3
|
module Consent
|
4
4
|
class Action # :nodoc:
|
5
|
-
attr_reader :key, :label, :options
|
5
|
+
attr_reader :subject, :key, :label, :options
|
6
6
|
|
7
|
-
def initialize(key, label, options = {})
|
7
|
+
def initialize(subject, key, label, options = {})
|
8
|
+
@subject = subject
|
8
9
|
@key = key
|
9
10
|
@label = label
|
10
11
|
@options = options
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
@options.fetch(:views, [])
|
14
|
+
def views
|
15
|
+
@views ||= @subject.views.slice(*@options.fetch(:views, []))
|
15
16
|
end
|
16
17
|
|
17
18
|
def default_view
|
18
|
-
@options
|
19
|
+
return unless @options.key?(:default_view)
|
20
|
+
|
21
|
+
@default_view ||= @subject.views[@options[:default_view]]
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
data/lib/consent/dsl.rb
CHANGED
@@ -27,7 +27,8 @@ module Consent
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def action(key, label, options = {})
|
30
|
-
@subject.actions << Action.new(key, label,
|
30
|
+
@subject.actions << Action.new(@subject, key, label,
|
31
|
+
@defaults.merge(options))
|
31
32
|
end
|
32
33
|
|
33
34
|
def self.build(subject, defaults = {}, &block)
|
data/lib/consent/rspec.rb
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'consent'
|
4
4
|
|
5
|
+
require_relative 'rspec/consent_action'
|
6
|
+
require_relative 'rspec/consent_view'
|
7
|
+
|
5
8
|
module Consent
|
6
9
|
# RSpec helpers for consent. Given permissions are loaded,
|
7
10
|
# gives you the ability of defining permission specs like
|
@@ -20,7 +23,11 @@ module Consent
|
|
20
23
|
# let(:user) { double(department_id: 15) }
|
21
24
|
#
|
22
25
|
# it do
|
23
|
-
# is_expected.to
|
26
|
+
# is_expected.to(
|
27
|
+
# consent_view(:department)
|
28
|
+
# .with_conditions(department_id: 15)
|
29
|
+
# .to(user)
|
30
|
+
# )
|
24
31
|
# end
|
25
32
|
# it { is_expected.to consent_action(:read) }
|
26
33
|
# it { is_expected.to consent_action(:update).with_views(:department) }
|
@@ -29,79 +36,12 @@ module Consent
|
|
29
36
|
# Find more examples at:
|
30
37
|
# https://github.com/powerhome/consent
|
31
38
|
module Rspec
|
32
|
-
|
33
|
-
|
34
|
-
matcher :consent_action do |action_key|
|
35
|
-
chain :with_views do |*views|
|
36
|
-
@views = views
|
37
|
-
end
|
38
|
-
|
39
|
-
match do |subject_key|
|
40
|
-
action = Consent.find_action(subject_key, action_key)
|
41
|
-
if action && @views
|
42
|
-
values_match?(action.view_keys.sort, @views.sort)
|
43
|
-
else
|
44
|
-
!action.nil?
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
failure_message do |subject_key|
|
49
|
-
action = Consent.find_action(subject_key, action_key)
|
50
|
-
message = format(
|
51
|
-
'expected %<skey>s (%<sclass>s) to provide action %<action>s',
|
52
|
-
skey: subject_key.to_s, sclass: subject.class, action: action_key
|
53
|
-
)
|
54
|
-
|
55
|
-
if action && @views
|
56
|
-
format(
|
57
|
-
'%<message>s with views %<views>s, but actual views are %<keys>p',
|
58
|
-
message: message, views: @views, keys: action.view_keys
|
59
|
-
)
|
60
|
-
else
|
61
|
-
message
|
62
|
-
end
|
63
|
-
end
|
39
|
+
def consent_view(view_key, conditions = nil)
|
40
|
+
ConsentView.new(view_key, conditions)
|
64
41
|
end
|
65
42
|
|
66
|
-
|
67
|
-
|
68
|
-
@context = context
|
69
|
-
end
|
70
|
-
|
71
|
-
match do |subject_key|
|
72
|
-
view = Consent.find_view(subject_key, view_key)
|
73
|
-
if conditions
|
74
|
-
view&.conditions(*@context).eql?(conditions)
|
75
|
-
else
|
76
|
-
!view.nil?
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
failure_message do |subject_key|
|
81
|
-
view = Consent.find_view(subject_key, view_key)
|
82
|
-
message = format(
|
83
|
-
'expected %<skey>s (%<sclass>s) to provide view %<view>s with` \
|
84
|
-
`%<conditions>p, but',
|
85
|
-
skey: subject_key.to_s, sclass: subject.class,
|
86
|
-
view: view_key, conditions: conditions
|
87
|
-
)
|
88
|
-
|
89
|
-
if view && conditions
|
90
|
-
actual_conditions = view.conditions(*@context)
|
91
|
-
format(
|
92
|
-
'%<message>s conditions are %<conditions>p',
|
93
|
-
message: message, conditions: actual_conditions
|
94
|
-
)
|
95
|
-
else
|
96
|
-
actual_views = Consent.find_subjects(subject_key)
|
97
|
-
.map(&:views)
|
98
|
-
.map(&:keys).flatten
|
99
|
-
format(
|
100
|
-
'%<message>s available views are %<views>p',
|
101
|
-
message: message, views: actual_views
|
102
|
-
)
|
103
|
-
end
|
104
|
-
end
|
43
|
+
def consent_action(action_key)
|
44
|
+
ConsentAction.new(action_key)
|
105
45
|
end
|
106
46
|
end
|
107
47
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'consent'
|
4
|
+
RSpec::Support.require_rspec_support 'fuzzy_matcher'
|
5
|
+
|
6
|
+
module Consent
|
7
|
+
module Rspec
|
8
|
+
# @private
|
9
|
+
class ConsentAction
|
10
|
+
def initialize(action_key)
|
11
|
+
@action_key = action_key
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_views(*views)
|
15
|
+
@views = views
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def description
|
20
|
+
message = "consents action #{@action_key}"
|
21
|
+
"#{message} with views #{@views}" if @views
|
22
|
+
end
|
23
|
+
|
24
|
+
def matches?(subject_key)
|
25
|
+
@subject_key = subject_key
|
26
|
+
@action = Consent.find_action(@subject_key, @action_key)
|
27
|
+
if @action && @views
|
28
|
+
RSpec::Support::FuzzyMatcher.values_match?(
|
29
|
+
@action.views.keys.sort,
|
30
|
+
@views.sort
|
31
|
+
)
|
32
|
+
else
|
33
|
+
!@action.nil?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def failure_message
|
38
|
+
failure_message_base 'to'
|
39
|
+
end
|
40
|
+
|
41
|
+
def failure_message_when_negated
|
42
|
+
failure_message_base 'to not'
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def failure_message_base(failure) # rubocop:disable Metrics/MethodLength
|
48
|
+
message = format(
|
49
|
+
'expected %<skey>s (%<sclass>s) %<failure> provide action %<action>s',
|
50
|
+
skey: @subject_key.to_s, sclass: @subject_key.class,
|
51
|
+
action: @action_key, failure: failure
|
52
|
+
)
|
53
|
+
|
54
|
+
if @action && @views
|
55
|
+
format(
|
56
|
+
'%<message>s with views %<views>s, but actual views are %<keys>p',
|
57
|
+
message: message, views: @views, keys: @action.views.keys
|
58
|
+
)
|
59
|
+
else
|
60
|
+
message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Consent
|
4
|
+
module Rspec
|
5
|
+
# @private
|
6
|
+
class ConsentView
|
7
|
+
def initialize(view_key, conditions)
|
8
|
+
@conditions = comparable_conditions(conditions) if conditions
|
9
|
+
@view_key = view_key
|
10
|
+
end
|
11
|
+
|
12
|
+
def to(*context)
|
13
|
+
@context = context
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
message = "consents view #{@view_key}"
|
19
|
+
"#{message} with conditions #{@conditions}" if @conditions
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_conditions(conditions)
|
23
|
+
@conditions = comparable_conditions(conditions)
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def matches?(subject_key)
|
28
|
+
@subject_key = subject_key
|
29
|
+
@target = Consent.find_subjects(subject_key)
|
30
|
+
.map do |subject|
|
31
|
+
subject.views[@view_key]&.conditions(*@context)
|
32
|
+
end
|
33
|
+
.compact
|
34
|
+
.map(&method(:comparable_conditions))
|
35
|
+
@target.include?(@conditions)
|
36
|
+
end
|
37
|
+
|
38
|
+
def failure_message
|
39
|
+
failure_message_base 'to'
|
40
|
+
end
|
41
|
+
|
42
|
+
def failure_message_when_negated
|
43
|
+
failure_message_base 'to not'
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def comparable_conditions(conditions)
|
49
|
+
return conditions.to_sql if conditions.respond_to?(:to_sql)
|
50
|
+
|
51
|
+
conditions
|
52
|
+
end
|
53
|
+
|
54
|
+
def failure_message_base(failure) # rubocop:disable Metrics/MethodLength
|
55
|
+
message = format(
|
56
|
+
'expected %<skey>s (%<sclass>s) %<fail>s provide view %<view>s with`\
|
57
|
+
`%<conditions>p, but',
|
58
|
+
skey: @subject_key.to_s, sclass: @subject_key.class,
|
59
|
+
view: @view_key, conditions: @conditions, fail: failure
|
60
|
+
)
|
61
|
+
|
62
|
+
if @target.any?
|
63
|
+
format(
|
64
|
+
'%<message>s conditions are %<conditions>p',
|
65
|
+
message: message, conditions: @target
|
66
|
+
)
|
67
|
+
else
|
68
|
+
actual_views = Consent.find_subjects(subject_key)
|
69
|
+
.map(&:views)
|
70
|
+
.map(&:keys).flatten
|
71
|
+
format(
|
72
|
+
'%<message>s available views are %<views>p',
|
73
|
+
message: message, views: actual_views
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/consent/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: consent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Palhares
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,20 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: 1.15.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.14.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.14.1
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: rake
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +108,20 @@ dependencies:
|
|
80
108
|
- - "~>"
|
81
109
|
- !ruby/object:Gem::Version
|
82
110
|
version: 0.65.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.4.2
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.4.2
|
83
125
|
description: Consent
|
84
126
|
email:
|
85
127
|
- chjunior@gmail.com
|
@@ -105,10 +147,11 @@ files:
|
|
105
147
|
- lib/consent/ability.rb
|
106
148
|
- lib/consent/action.rb
|
107
149
|
- lib/consent/dsl.rb
|
108
|
-
- lib/consent/permission.rb
|
109
150
|
- lib/consent/railtie.rb
|
110
151
|
- lib/consent/reloader.rb
|
111
152
|
- lib/consent/rspec.rb
|
153
|
+
- lib/consent/rspec/consent_action.rb
|
154
|
+
- lib/consent/rspec/consent_view.rb
|
112
155
|
- lib/consent/subject.rb
|
113
156
|
- lib/consent/version.rb
|
114
157
|
- lib/consent/view.rb
|
data/lib/consent/permission.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Consent
|
4
|
-
class Permission # :nodoc:
|
5
|
-
attr_reader :subject_key, :action_key, :view_key, :view
|
6
|
-
|
7
|
-
def initialize(subject_key, action_key, view_key = nil)
|
8
|
-
@subject_key = subject_key
|
9
|
-
@action_key = action_key
|
10
|
-
@view_key = view_key
|
11
|
-
@view = Consent.find_view(subject_key, view_key) if view_key
|
12
|
-
end
|
13
|
-
|
14
|
-
def action
|
15
|
-
@action ||= Consent.find_action(subject_key, action_key)
|
16
|
-
end
|
17
|
-
|
18
|
-
def valid?
|
19
|
-
action && (@view_key.nil? == @view.nil?)
|
20
|
-
end
|
21
|
-
|
22
|
-
def conditions(*args)
|
23
|
-
@view.nil? ? nil : @view.conditions(*args)
|
24
|
-
end
|
25
|
-
|
26
|
-
def object_conditions(*args)
|
27
|
-
@view.nil? ? nil : @view.object_conditions(*args)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|