pundit 2.2.0 → 2.5.2
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/CHANGELOG.md +98 -29
- data/CONTRIBUTING.md +3 -5
- data/README.md +125 -54
- data/SECURITY.md +19 -0
- data/config/rubocop-rspec.yml +5 -0
- data/lib/generators/pundit/install/install_generator.rb +3 -1
- data/lib/generators/pundit/install/templates/{application_policy.rb → application_policy.rb.tt} +1 -1
- data/lib/generators/pundit/policy/policy_generator.rb +3 -1
- data/lib/generators/pundit/policy/templates/policy.rb.tt +16 -0
- data/lib/generators/rspec/policy_generator.rb +4 -1
- data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +1 -1
- data/lib/generators/test_unit/policy_generator.rb +4 -1
- data/lib/pundit/authorization.rb +176 -75
- data/lib/pundit/cache_store/legacy_store.rb +27 -0
- data/lib/pundit/cache_store/null_store.rb +30 -0
- data/lib/pundit/cache_store.rb +24 -0
- data/lib/pundit/context.rb +190 -0
- data/lib/pundit/error.rb +71 -0
- data/lib/pundit/helper.rb +16 -0
- data/lib/pundit/policy_finder.rb +34 -2
- data/lib/pundit/railtie.rb +20 -0
- data/lib/pundit/rspec.rb +92 -7
- data/lib/pundit/version.rb +2 -1
- data/lib/pundit.rb +45 -140
- metadata +25 -170
- data/.gitignore +0 -19
- data/.rubocop.yml +0 -72
- data/.travis.yml +0 -26
- data/.yardopts +0 -1
- data/CODE_OF_CONDUCT.md +0 -28
- data/Gemfile +0 -7
- data/Rakefile +0 -20
- data/lib/generators/pundit/policy/templates/policy.rb +0 -10
- data/pundit.gemspec +0 -33
- data/spec/authorization_spec.rb +0 -258
- data/spec/generators_spec.rb +0 -43
- data/spec/policies/post_policy_spec.rb +0 -22
- data/spec/policy_finder_spec.rb +0 -187
- data/spec/pundit_spec.rb +0 -427
- data/spec/spec_helper.rb +0 -275
- /data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
data/lib/pundit/error.rb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pundit
|
|
4
|
+
# @api private
|
|
5
|
+
# @since v1.0.0
|
|
6
|
+
# To avoid name clashes with common Error naming when mixing in Pundit,
|
|
7
|
+
# keep it here with compact class style definition.
|
|
8
|
+
class Error < StandardError; end
|
|
9
|
+
|
|
10
|
+
# Error that will be raised when authorization has failed
|
|
11
|
+
# @since v0.1.0
|
|
12
|
+
class NotAuthorizedError < Error
|
|
13
|
+
# @see #initialize
|
|
14
|
+
# @since v0.2.3
|
|
15
|
+
attr_reader :query
|
|
16
|
+
# @see #initialize
|
|
17
|
+
# @since v0.2.3
|
|
18
|
+
attr_reader :record
|
|
19
|
+
# @see #initialize
|
|
20
|
+
# @since v0.2.3
|
|
21
|
+
attr_reader :policy
|
|
22
|
+
|
|
23
|
+
# @since v1.0.0
|
|
24
|
+
#
|
|
25
|
+
# @overload initialize(message)
|
|
26
|
+
# Create an error with a simple error message.
|
|
27
|
+
# @param [String] message A simple error message string.
|
|
28
|
+
#
|
|
29
|
+
# @overload initialize(options)
|
|
30
|
+
# Create an error with the specified attributes.
|
|
31
|
+
# @param [Hash] options The error options.
|
|
32
|
+
# @option options [String] :message Optional custom error message. Will default to a generalized message.
|
|
33
|
+
# @option options [Symbol] :query The name of the policy method that was checked.
|
|
34
|
+
# @option options [Object] :record The object that was being checked with the policy.
|
|
35
|
+
# @option options [Class] :policy The class of policy that was used for the check.
|
|
36
|
+
def initialize(options = {})
|
|
37
|
+
if options.is_a? String
|
|
38
|
+
message = options
|
|
39
|
+
else
|
|
40
|
+
@query = options[:query]
|
|
41
|
+
@record = options[:record]
|
|
42
|
+
@policy = options[:policy]
|
|
43
|
+
|
|
44
|
+
message = options.fetch(:message) do
|
|
45
|
+
record_name = record.is_a?(Class) ? record.to_s : "this #{record.class}"
|
|
46
|
+
"not allowed to #{policy.class}##{query} #{record_name}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
super(message)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Error that will be raised if a policy or policy scope constructor is not called correctly.
|
|
55
|
+
# @since v2.0.0
|
|
56
|
+
class InvalidConstructorError < Error; end
|
|
57
|
+
|
|
58
|
+
# Error that will be raised if a controller action has not called the
|
|
59
|
+
# `authorize` or `skip_authorization` methods.
|
|
60
|
+
# @since v0.2.3
|
|
61
|
+
class AuthorizationNotPerformedError < Error; end
|
|
62
|
+
|
|
63
|
+
# Error that will be raised if a controller action has not called the
|
|
64
|
+
# `policy_scope` or `skip_policy_scope` methods.
|
|
65
|
+
# @since v0.3.0
|
|
66
|
+
class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
|
|
67
|
+
|
|
68
|
+
# Error that will be raised if a policy or policy scope is not defined.
|
|
69
|
+
# @since v0.1.0
|
|
70
|
+
class NotDefinedError < Error; end
|
|
71
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pundit
|
|
4
|
+
# Rails view helpers, to allow a slightly different view-specific
|
|
5
|
+
# implementation of the methods in {Pundit::Authorization}.
|
|
6
|
+
#
|
|
7
|
+
# @api private
|
|
8
|
+
# @since v1.0.0
|
|
9
|
+
module Helper
|
|
10
|
+
# @see Pundit::Authorization#pundit_policy_scope
|
|
11
|
+
# @since v1.0.0
|
|
12
|
+
def policy_scope(scope)
|
|
13
|
+
pundit_policy_scope(scope)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/pundit/policy_finder.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# String#safe_constantize, String#demodulize, String#underscore, String#camelize
|
|
4
|
+
require "active_support/core_ext/string/inflections"
|
|
5
|
+
|
|
3
6
|
module Pundit
|
|
4
7
|
# Finds policy and scope classes for given object.
|
|
8
|
+
# @since v0.1.0
|
|
5
9
|
# @api public
|
|
6
10
|
# @example
|
|
7
11
|
# user = User.find(params[:id])
|
|
@@ -10,10 +14,18 @@ module Pundit
|
|
|
10
14
|
# finder.scope #=> UserPolicy::Scope
|
|
11
15
|
#
|
|
12
16
|
class PolicyFinder
|
|
17
|
+
# A constant applied to the end of the class name to find the policy class.
|
|
18
|
+
#
|
|
19
|
+
# @api private
|
|
20
|
+
# @since v2.5.0
|
|
21
|
+
SUFFIX = "Policy"
|
|
22
|
+
|
|
23
|
+
# @see #initialize
|
|
24
|
+
# @since v0.1.0
|
|
13
25
|
attr_reader :object
|
|
14
26
|
|
|
15
27
|
# @param object [any] the object to find policy and scope classes for
|
|
16
|
-
#
|
|
28
|
+
# @since v0.1.0
|
|
17
29
|
def initialize(object)
|
|
18
30
|
@object = object
|
|
19
31
|
end
|
|
@@ -24,6 +36,7 @@ module Pundit
|
|
|
24
36
|
# scope = finder.scope #=> UserPolicy::Scope
|
|
25
37
|
# scope.resolve #=> <#ActiveRecord::Relation ...>
|
|
26
38
|
#
|
|
39
|
+
# @since v0.1.0
|
|
27
40
|
def scope
|
|
28
41
|
"#{policy}::Scope".safe_constantize
|
|
29
42
|
end
|
|
@@ -35,6 +48,7 @@ module Pundit
|
|
|
35
48
|
# policy.show? #=> true
|
|
36
49
|
# policy.update? #=> false
|
|
37
50
|
#
|
|
51
|
+
# @since v0.1.0
|
|
38
52
|
def policy
|
|
39
53
|
klass = find(object)
|
|
40
54
|
klass.is_a?(String) ? klass.safe_constantize : klass
|
|
@@ -43,6 +57,7 @@ module Pundit
|
|
|
43
57
|
# @return [Scope{#resolve}] scope class which can resolve to a scope
|
|
44
58
|
# @raise [NotDefinedError] if scope could not be determined
|
|
45
59
|
#
|
|
60
|
+
# @since v0.1.0
|
|
46
61
|
def scope!
|
|
47
62
|
scope or raise NotDefinedError, "unable to find scope `#{find(object)}::Scope` for `#{object.inspect}`"
|
|
48
63
|
end
|
|
@@ -50,13 +65,15 @@ module Pundit
|
|
|
50
65
|
# @return [Class] policy class with query methods
|
|
51
66
|
# @raise [NotDefinedError] if policy could not be determined
|
|
52
67
|
#
|
|
68
|
+
# @since v0.1.0
|
|
53
69
|
def policy!
|
|
54
70
|
policy or raise NotDefinedError, "unable to find policy `#{find(object)}` for `#{object.inspect}`"
|
|
55
71
|
end
|
|
56
72
|
|
|
57
73
|
# @return [String] the name of the key this object would have in a params hash
|
|
58
74
|
#
|
|
59
|
-
|
|
75
|
+
# @since v1.1.0
|
|
76
|
+
def param_key # rubocop:disable Metrics/AbcSize
|
|
60
77
|
model = object.is_a?(Array) ? object.last : object
|
|
61
78
|
|
|
62
79
|
if model.respond_to?(:model_name)
|
|
@@ -70,6 +87,12 @@ module Pundit
|
|
|
70
87
|
|
|
71
88
|
private
|
|
72
89
|
|
|
90
|
+
# Given an object, find the policy class name.
|
|
91
|
+
#
|
|
92
|
+
# Uses recursion to handle namespaces.
|
|
93
|
+
#
|
|
94
|
+
# @return [String, Class] the policy class, or its name.
|
|
95
|
+
# @since v0.2.0
|
|
73
96
|
def find(subject)
|
|
74
97
|
if subject.is_a?(Array)
|
|
75
98
|
modules = subject.dup
|
|
@@ -86,6 +109,15 @@ module Pundit
|
|
|
86
109
|
end
|
|
87
110
|
end
|
|
88
111
|
|
|
112
|
+
# Given an object, find its' class name.
|
|
113
|
+
#
|
|
114
|
+
# - Supports ActiveModel.
|
|
115
|
+
# - Supports regular classes.
|
|
116
|
+
# - Supports symbols.
|
|
117
|
+
# - Supports object instances.
|
|
118
|
+
#
|
|
119
|
+
# @return [String, Class] the class, or its name.
|
|
120
|
+
# @since v1.1.0
|
|
89
121
|
def find_class_name(subject)
|
|
90
122
|
if subject.respond_to?(:model_name)
|
|
91
123
|
subject.model_name
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pundit
|
|
4
|
+
# @since v2.5.0
|
|
5
|
+
class Railtie < Rails::Railtie
|
|
6
|
+
if Rails.version.to_f >= 8.0
|
|
7
|
+
initializer "pundit.stats_directories" do
|
|
8
|
+
require "rails/code_statistics"
|
|
9
|
+
|
|
10
|
+
if Rails.root.join("app/policies").directory?
|
|
11
|
+
Rails::CodeStatistics.register_directory("Policies", "app/policies")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
if Rails.root.join("test/policies").directory?
|
|
15
|
+
Rails::CodeStatistics.register_directory("Policy tests", "test/policies", test_directory: true)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/pundit/rspec.rb
CHANGED
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "pundit"
|
|
4
|
+
# Array#to_sentence
|
|
5
|
+
require "active_support/core_ext/array/conversions"
|
|
6
|
+
|
|
3
7
|
module Pundit
|
|
8
|
+
# Namespace for Pundit's RSpec integration.
|
|
9
|
+
# @since v0.1.0
|
|
4
10
|
module RSpec
|
|
11
|
+
# Namespace for Pundit's RSpec matchers.
|
|
5
12
|
module Matchers
|
|
6
13
|
extend ::RSpec::Matchers::DSL
|
|
7
14
|
|
|
15
|
+
# @!method description=(description)
|
|
16
|
+
class << self
|
|
17
|
+
# Used to build a suitable description for the Pundit `permit` matcher.
|
|
18
|
+
# @api public
|
|
19
|
+
# @param value [String, Proc]
|
|
20
|
+
# @example
|
|
21
|
+
# Pundit::RSpec::Matchers.description = ->(user, record) do
|
|
22
|
+
# "permit user with role #{user.role} to access record with ID #{record.id}"
|
|
23
|
+
# end
|
|
24
|
+
attr_writer :description
|
|
25
|
+
|
|
26
|
+
# Used to retrieve a suitable description for the Pundit `permit` matcher.
|
|
27
|
+
# @api private
|
|
28
|
+
# @private
|
|
29
|
+
def description(user, record)
|
|
30
|
+
return @description.call(user, record) if defined?(@description) && @description.respond_to?(:call)
|
|
31
|
+
|
|
32
|
+
@description
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
8
36
|
# rubocop:disable Metrics/BlockLength
|
|
9
37
|
matcher :permit do |user, record|
|
|
10
38
|
match_proc = lambda do |policy|
|
|
@@ -22,15 +50,25 @@ module Pundit
|
|
|
22
50
|
end
|
|
23
51
|
|
|
24
52
|
failure_message_proc = lambda do |policy|
|
|
25
|
-
was_were = @violating_permissions.count > 1 ? "were" : "was"
|
|
26
53
|
"Expected #{policy} to grant #{permissions.to_sentence} on " \
|
|
27
|
-
"#{record} but #{@violating_permissions.to_sentence} #{
|
|
54
|
+
"#{record} but #{@violating_permissions.to_sentence} #{was_or_were} not granted"
|
|
28
55
|
end
|
|
29
56
|
|
|
30
57
|
failure_message_when_negated_proc = lambda do |policy|
|
|
31
|
-
was_were = @violating_permissions.count > 1 ? "were" : "was"
|
|
32
58
|
"Expected #{policy} not to grant #{permissions.to_sentence} on " \
|
|
33
|
-
"#{record} but #{@violating_permissions.to_sentence} #{
|
|
59
|
+
"#{record} but #{@violating_permissions.to_sentence} #{was_or_were} granted"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def was_or_were
|
|
63
|
+
if @violating_permissions.count > 1
|
|
64
|
+
"were"
|
|
65
|
+
else
|
|
66
|
+
"was"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
description do
|
|
71
|
+
Pundit::RSpec::Matchers.description(user, record) || super()
|
|
34
72
|
end
|
|
35
73
|
|
|
36
74
|
if respond_to?(:match_when_negated)
|
|
@@ -39,26 +77,73 @@ module Pundit
|
|
|
39
77
|
failure_message(&failure_message_proc)
|
|
40
78
|
failure_message_when_negated(&failure_message_when_negated_proc)
|
|
41
79
|
else
|
|
80
|
+
# :nocov:
|
|
81
|
+
# Compatibility with RSpec < 3.0, released 2014-06-01.
|
|
42
82
|
match_for_should(&match_proc)
|
|
43
83
|
match_for_should_not(&match_when_negated_proc)
|
|
44
84
|
failure_message_for_should(&failure_message_proc)
|
|
45
85
|
failure_message_for_should_not(&failure_message_when_negated_proc)
|
|
86
|
+
# :nocov:
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if ::RSpec.respond_to?(:current_example)
|
|
90
|
+
def current_example
|
|
91
|
+
::RSpec.current_example
|
|
92
|
+
end
|
|
93
|
+
else
|
|
94
|
+
# :nocov:
|
|
95
|
+
# Compatibility with RSpec < 3.0, released 2014-06-01.
|
|
96
|
+
def current_example
|
|
97
|
+
example
|
|
98
|
+
end
|
|
99
|
+
# :nocov:
|
|
46
100
|
end
|
|
47
101
|
|
|
48
102
|
def permissions
|
|
49
|
-
current_example
|
|
50
|
-
|
|
103
|
+
current_example.metadata.fetch(:permissions) do
|
|
104
|
+
raise KeyError, <<~ERROR.strip
|
|
105
|
+
No permissions in example metadata, did you forget to wrap with `permissions :show?, ...`?
|
|
106
|
+
ERROR
|
|
107
|
+
end
|
|
51
108
|
end
|
|
52
109
|
end
|
|
53
110
|
# rubocop:enable Metrics/BlockLength
|
|
54
111
|
end
|
|
55
112
|
|
|
113
|
+
# Mixed in to all policy example groups to provide a DSL.
|
|
56
114
|
module DSL
|
|
115
|
+
# @example
|
|
116
|
+
# describe PostPolicy do
|
|
117
|
+
# permissions :show?, :update? do
|
|
118
|
+
# it { is_expected.to permit(user, own_post) }
|
|
119
|
+
# end
|
|
120
|
+
# end
|
|
121
|
+
#
|
|
122
|
+
# @example focused example group
|
|
123
|
+
# describe PostPolicy do
|
|
124
|
+
# permissions :show?, :update?, :focus do
|
|
125
|
+
# it { is_expected.to permit(user, own_post) }
|
|
126
|
+
# end
|
|
127
|
+
# end
|
|
128
|
+
#
|
|
129
|
+
# @param list [Symbol, Array<Symbol>] a permission to describe
|
|
130
|
+
# @return [void]
|
|
57
131
|
def permissions(*list, &block)
|
|
58
|
-
|
|
132
|
+
metadata = { permissions: list, caller: caller }
|
|
133
|
+
|
|
134
|
+
if list.last == :focus
|
|
135
|
+
list.pop
|
|
136
|
+
metadata[:focus] = true
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
description = list.to_sentence
|
|
140
|
+
describe(description, metadata) { instance_eval(&block) }
|
|
59
141
|
end
|
|
60
142
|
end
|
|
61
143
|
|
|
144
|
+
# Mixed in to all policy example groups.
|
|
145
|
+
#
|
|
146
|
+
# @private not useful
|
|
62
147
|
module PolicyExampleGroup
|
|
63
148
|
include Pundit::RSpec::Matchers
|
|
64
149
|
|
data/lib/pundit/version.rb
CHANGED
data/lib/pundit.rb
CHANGED
|
@@ -1,172 +1,77 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support"
|
|
4
|
+
|
|
3
5
|
require "pundit/version"
|
|
6
|
+
require "pundit/error"
|
|
4
7
|
require "pundit/policy_finder"
|
|
5
|
-
require "
|
|
6
|
-
require "active_support/core_ext/string/inflections"
|
|
7
|
-
require "active_support/core_ext/object/blank"
|
|
8
|
-
require "active_support/core_ext/module/introspection"
|
|
9
|
-
require "active_support/dependencies/autoload"
|
|
8
|
+
require "pundit/context"
|
|
10
9
|
require "pundit/authorization"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
require "pundit/helper"
|
|
11
|
+
require "pundit/cache_store"
|
|
12
|
+
require "pundit/cache_store/null_store"
|
|
13
|
+
require "pundit/cache_store/legacy_store"
|
|
14
|
+
require "pundit/railtie" if defined?(Rails)
|
|
15
|
+
|
|
16
|
+
# Hello? Yes, this is Pundit.
|
|
17
|
+
#
|
|
17
18
|
# @api public
|
|
18
19
|
module Pundit
|
|
19
|
-
|
|
20
|
+
# @api private
|
|
21
|
+
# @since v1.0.0
|
|
22
|
+
# @deprecated See {Pundit::PolicyFinder}
|
|
23
|
+
SUFFIX = Pundit::PolicyFinder::SUFFIX
|
|
20
24
|
|
|
21
25
|
# @api private
|
|
26
|
+
# @private
|
|
27
|
+
# @since v0.1.0
|
|
22
28
|
module Generators; end
|
|
23
29
|
|
|
24
|
-
# Error that will be raised when authorization has failed
|
|
25
|
-
class NotAuthorizedError < Error
|
|
26
|
-
attr_reader :query, :record, :policy
|
|
27
|
-
|
|
28
|
-
def initialize(options = {})
|
|
29
|
-
if options.is_a? String
|
|
30
|
-
message = options
|
|
31
|
-
else
|
|
32
|
-
@query = options[:query]
|
|
33
|
-
@record = options[:record]
|
|
34
|
-
@policy = options[:policy]
|
|
35
|
-
|
|
36
|
-
message = options.fetch(:message) { "not allowed to #{query} this #{record.class}" }
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
super(message)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Error that will be raised if a policy or policy scope constructor is not called correctly.
|
|
44
|
-
class InvalidConstructorError < Error; end
|
|
45
|
-
|
|
46
|
-
# Error that will be raised if a controller action has not called the
|
|
47
|
-
# `authorize` or `skip_authorization` methods.
|
|
48
|
-
class AuthorizationNotPerformedError < Error; end
|
|
49
|
-
|
|
50
|
-
# Error that will be raised if a controller action has not called the
|
|
51
|
-
# `policy_scope` or `skip_policy_scope` methods.
|
|
52
|
-
class PolicyScopingNotPerformedError < AuthorizationNotPerformedError; end
|
|
53
|
-
|
|
54
|
-
# Error that will be raised if a policy or policy scope is not defined.
|
|
55
|
-
class NotDefinedError < Error; end
|
|
56
|
-
|
|
57
30
|
def self.included(base)
|
|
58
|
-
|
|
31
|
+
location = caller_locations(1, 1).first
|
|
32
|
+
warn <<~WARNING
|
|
59
33
|
'include Pundit' is deprecated. Please use 'include Pundit::Authorization' instead.
|
|
34
|
+
(called from #{location.label} at #{location.path}:#{location.lineno})
|
|
60
35
|
WARNING
|
|
61
36
|
base.include Authorization
|
|
62
37
|
end
|
|
63
38
|
|
|
64
39
|
class << self
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# @param query [Symbol, String] the predicate method to check on the policy (e.g. `:show?`)
|
|
72
|
-
# @param policy_class [Class] the policy class we want to force use of
|
|
73
|
-
# @param cache [#[], #[]=] a Hash-like object to cache the found policy instance in
|
|
74
|
-
# @raise [NotAuthorizedError] if the given query method returned false
|
|
75
|
-
# @return [Object] Always returns the passed object record
|
|
76
|
-
def authorize(user, possibly_namespaced_record, query, policy_class: nil, cache: {})
|
|
77
|
-
record = pundit_model(possibly_namespaced_record)
|
|
78
|
-
policy = if policy_class
|
|
79
|
-
policy_class.new(user, record)
|
|
40
|
+
# @see Pundit::Context#authorize
|
|
41
|
+
# @since v1.0.0
|
|
42
|
+
def authorize(user, record, query, policy_class: nil, cache: nil)
|
|
43
|
+
context = if cache
|
|
44
|
+
policy_cache = CacheStore::LegacyStore.new(cache)
|
|
45
|
+
Context.new(user: user, policy_cache: policy_cache)
|
|
80
46
|
else
|
|
81
|
-
|
|
47
|
+
Context.new(user: user)
|
|
82
48
|
end
|
|
83
49
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
record
|
|
50
|
+
context.authorize(record, query: query, policy_class: policy_class)
|
|
87
51
|
end
|
|
88
52
|
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# @param scope [Object] the object we're retrieving the policy scope for
|
|
94
|
-
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
|
95
|
-
# @return [Scope{#resolve}, nil] instance of scope class which can resolve to a scope
|
|
96
|
-
def policy_scope(user, scope)
|
|
97
|
-
policy_scope_class = PolicyFinder.new(scope).scope
|
|
98
|
-
return unless policy_scope_class
|
|
99
|
-
|
|
100
|
-
begin
|
|
101
|
-
policy_scope = policy_scope_class.new(user, pundit_model(scope))
|
|
102
|
-
rescue ArgumentError
|
|
103
|
-
raise InvalidConstructorError, "Invalid #<#{policy_scope_class}> constructor is called"
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
policy_scope.resolve
|
|
53
|
+
# @see Pundit::Context#policy_scope
|
|
54
|
+
# @since v0.1.0
|
|
55
|
+
def policy_scope(user, *args, **kwargs, &block)
|
|
56
|
+
Context.new(user: user).policy_scope(*args, **kwargs, &block)
|
|
107
57
|
end
|
|
108
58
|
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# @param scope [Object] the object we're retrieving the policy scope for
|
|
114
|
-
# @raise [NotDefinedError] if the policy scope cannot be found
|
|
115
|
-
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
|
116
|
-
# @return [Scope{#resolve}] instance of scope class which can resolve to a scope
|
|
117
|
-
def policy_scope!(user, scope)
|
|
118
|
-
policy_scope_class = PolicyFinder.new(scope).scope!
|
|
119
|
-
return unless policy_scope_class
|
|
120
|
-
|
|
121
|
-
begin
|
|
122
|
-
policy_scope = policy_scope_class.new(user, pundit_model(scope))
|
|
123
|
-
rescue ArgumentError
|
|
124
|
-
raise InvalidConstructorError, "Invalid #<#{policy_scope_class}> constructor is called"
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
policy_scope.resolve
|
|
59
|
+
# @see Pundit::Context#policy_scope!
|
|
60
|
+
# @since v0.1.0
|
|
61
|
+
def policy_scope!(user, *args, **kwargs, &block)
|
|
62
|
+
Context.new(user: user).policy_scope!(*args, **kwargs, &block)
|
|
128
63
|
end
|
|
129
64
|
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# @param record [Object] the object we're retrieving the policy for
|
|
135
|
-
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
|
136
|
-
# @return [Object, nil] instance of policy class with query methods
|
|
137
|
-
def policy(user, record)
|
|
138
|
-
policy = PolicyFinder.new(record).policy
|
|
139
|
-
policy&.new(user, pundit_model(record))
|
|
140
|
-
rescue ArgumentError
|
|
141
|
-
raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
|
|
65
|
+
# @see Pundit::Context#policy
|
|
66
|
+
# @since v0.1.0
|
|
67
|
+
def policy(user, *args, **kwargs, &block)
|
|
68
|
+
Context.new(user: user).policy(*args, **kwargs, &block)
|
|
142
69
|
end
|
|
143
70
|
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
# @param record [Object] the object we're retrieving the policy for
|
|
149
|
-
# @raise [NotDefinedError] if the policy cannot be found
|
|
150
|
-
# @raise [InvalidConstructorError] if the policy constructor called incorrectly
|
|
151
|
-
# @return [Object] instance of policy class with query methods
|
|
152
|
-
def policy!(user, record)
|
|
153
|
-
policy = PolicyFinder.new(record).policy!
|
|
154
|
-
policy.new(user, pundit_model(record))
|
|
155
|
-
rescue ArgumentError
|
|
156
|
-
raise InvalidConstructorError, "Invalid #<#{policy}> constructor is called"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
private
|
|
160
|
-
|
|
161
|
-
def pundit_model(record)
|
|
162
|
-
record.is_a?(Array) ? record.last : record
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
# @api private
|
|
167
|
-
module Helper
|
|
168
|
-
def policy_scope(scope)
|
|
169
|
-
pundit_policy_scope(scope)
|
|
71
|
+
# @see Pundit::Context#policy!
|
|
72
|
+
# @since v0.1.0
|
|
73
|
+
def policy!(user, *args, **kwargs, &block)
|
|
74
|
+
Context.new(user: user).policy!(*args, **kwargs, &block)
|
|
170
75
|
end
|
|
171
76
|
end
|
|
172
77
|
end
|