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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66e7e1705d61760713253718eabda896ffa49f25ea6e1a9a6c4fc1a188730cfb
4
- data.tar.gz: 4dc120c6f1e89a3cb612a62cf9fdbac565e51b9fabe9d04a68c64c3d9a8fd193
3
+ metadata.gz: 925e2e71db7ce7b4c7104784bbd54cfeb8273b2502f0f73f599e64754d5a010a
4
+ data.tar.gz: 256326fbd83020d39881b53eadc1b3b7cb9c5169bedee5aac5491661a0e3023b
5
5
  SHA512:
6
- metadata.gz: 9ca74d2788b689711966b38e11ce4b857009064d1fce59c2b5335adc437c1b20a9298acb61a0e71cf3aac2eef1f13f6b8b06570014938ef757374b6a4f98b9c4
7
- data.tar.gz: 9d4e6cf5d18d0671c9aade10a33933cc93b0cb704c623d6705332de55a1a02b3952b01fdee9d357a1c0ba9f37d570910ac1fe54614087cd88c94d3d890b5761d
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
- @subjects.find_all do |subject|
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
- Consent.find_subjects(subject_key)
48
- .map(&:actions).flatten
49
- .find do |action|
50
- action.key.eql?(action_key)
51
- end
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
- views = Consent.find_subjects(subject_key)
59
- .map(&:views)
60
- .reduce({}, &:merge)
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
@@ -10,17 +10,26 @@ module Consent
10
10
  apply_defaults! if apply_defaults
11
11
  end
12
12
 
13
- def consent(permission: nil, subject: nil, action: nil, view: nil)
14
- permission ||= Permission.new(subject, action, view)
15
- return unless permission.valid?
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
- permission.action_key, permission.subject_key,
19
- permission.conditions(*@context),
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!
@@ -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 view_keys
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[:default_view]
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, @defaults.merge(options))
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 consent_view(:department, department_id: 15).to(user)
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
- extend RSpec::Matchers::DSL
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
- matcher :consent_view do |view_key, conditions|
67
- chain :to do |*context|
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Consent
4
- VERSION = '1.0.0'
4
+ VERSION = '1.0.1'
5
5
  end
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.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-04-22 00:00:00.000000000 Z
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
@@ -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