action_policy 0.4.2 → 0.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 +229 -171
- data/LICENSE.txt +1 -1
- data/README.md +7 -11
- data/lib/.rbnext/2.7/action_policy/behaviours/policy_for.rb +62 -0
- data/lib/.rbnext/2.7/action_policy/i18n.rb +56 -0
- data/lib/.rbnext/2.7/action_policy/policy/cache.rb +101 -0
- data/lib/.rbnext/2.7/action_policy/policy/pre_check.rb +162 -0
- data/lib/.rbnext/2.7/action_policy/rspec/be_authorized_to.rb +89 -0
- data/lib/.rbnext/2.7/action_policy/rspec/have_authorized_scope.rb +124 -0
- data/lib/.rbnext/2.7/action_policy/utils/pretty_print.rb +159 -0
- data/lib/.rbnext/3.0/action_policy/behaviour.rb +115 -0
- data/lib/.rbnext/3.0/action_policy/behaviours/policy_for.rb +62 -0
- data/lib/.rbnext/3.0/action_policy/behaviours/scoping.rb +35 -0
- data/lib/.rbnext/3.0/action_policy/behaviours/thread_memoized.rb +59 -0
- data/lib/.rbnext/3.0/action_policy/ext/policy_cache_key.rb +72 -0
- data/lib/.rbnext/3.0/action_policy/policy/aliases.rb +69 -0
- data/lib/.rbnext/3.0/action_policy/policy/authorization.rb +87 -0
- data/lib/.rbnext/3.0/action_policy/policy/cache.rb +101 -0
- data/lib/.rbnext/3.0/action_policy/policy/core.rb +161 -0
- data/lib/.rbnext/3.0/action_policy/policy/defaults.rb +31 -0
- data/lib/.rbnext/3.0/action_policy/policy/execution_result.rb +37 -0
- data/lib/.rbnext/3.0/action_policy/policy/pre_check.rb +162 -0
- data/lib/.rbnext/3.0/action_policy/policy/reasons.rb +210 -0
- data/lib/.rbnext/3.0/action_policy/policy/scoping.rb +160 -0
- data/lib/.rbnext/3.0/action_policy/rspec/be_authorized_to.rb +89 -0
- data/lib/.rbnext/3.0/action_policy/rspec/have_authorized_scope.rb +124 -0
- data/lib/.rbnext/3.0/action_policy/utils/pretty_print.rb +159 -0
- data/lib/.rbnext/3.0/action_policy/utils/suggest_message.rb +19 -0
- data/lib/action_policy.rb +7 -1
- data/lib/action_policy/behaviour.rb +22 -16
- data/lib/action_policy/behaviours/policy_for.rb +10 -3
- data/lib/action_policy/behaviours/scoping.rb +2 -1
- data/lib/action_policy/behaviours/thread_memoized.rb +1 -3
- data/lib/action_policy/ext/module_namespace.rb +1 -6
- data/lib/action_policy/ext/policy_cache_key.rb +15 -33
- data/lib/action_policy/ext/{symbol_classify.rb → symbol_camelize.rb} +6 -6
- data/lib/action_policy/i18n.rb +1 -1
- data/lib/action_policy/lookup_chain.rb +41 -21
- data/lib/action_policy/policy/aliases.rb +7 -12
- data/lib/action_policy/policy/authorization.rb +14 -17
- data/lib/action_policy/policy/cache.rb +34 -18
- data/lib/action_policy/policy/core.rb +25 -12
- data/lib/action_policy/policy/defaults.rb +3 -9
- data/lib/action_policy/policy/execution_result.rb +3 -9
- data/lib/action_policy/policy/pre_check.rb +19 -58
- data/lib/action_policy/policy/reasons.rb +32 -20
- data/lib/action_policy/policy/scoping.rb +5 -6
- data/lib/action_policy/rails/controller.rb +6 -1
- data/lib/action_policy/rails/ext/active_record.rb +7 -0
- data/lib/action_policy/rails/policy/instrumentation.rb +1 -1
- data/lib/action_policy/rspec/be_authorized_to.rb +5 -9
- data/lib/action_policy/rspec/dsl.rb +3 -3
- data/lib/action_policy/rspec/have_authorized_scope.rb +5 -7
- data/lib/action_policy/utils/pretty_print.rb +21 -24
- data/lib/action_policy/utils/suggest_message.rb +1 -3
- data/lib/action_policy/version.rb +1 -1
- data/lib/generators/action_policy/install/templates/{application_policy.rb → application_policy.rb.tt} +1 -1
- data/lib/generators/action_policy/policy/policy_generator.rb +4 -1
- data/lib/generators/action_policy/policy/templates/{policy.rb → policy.rb.tt} +0 -0
- data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
- data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
- metadata +55 -119
- data/.gitattributes +0 -2
- data/.github/FUNDING.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -18
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -29
- data/.gitignore +0 -15
- data/.rubocop.yml +0 -54
- data/.tidelift.yml +0 -6
- data/.travis.yml +0 -31
- data/Gemfile +0 -22
- data/Rakefile +0 -27
- data/action_policy.gemspec +0 -44
- data/benchmarks/namespaced_lookup_cache.rb +0 -71
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/docs/.nojekyll +0 -0
- data/docs/CNAME +0 -1
- data/docs/README.md +0 -77
- data/docs/_sidebar.md +0 -27
- data/docs/aliases.md +0 -122
- data/docs/assets/docsify-search.js +0 -364
- data/docs/assets/docsify.min.js +0 -3
- data/docs/assets/fonts/FiraCode-Medium.woff +0 -0
- data/docs/assets/fonts/FiraCode-Regular.woff +0 -0
- data/docs/assets/images/banner.png +0 -0
- data/docs/assets/images/cache.png +0 -0
- data/docs/assets/images/cache.svg +0 -70
- data/docs/assets/images/layer.png +0 -0
- data/docs/assets/images/layer.svg +0 -35
- data/docs/assets/prism-ruby.min.js +0 -1
- data/docs/assets/styles.css +0 -347
- data/docs/assets/vue.min.css +0 -1
- data/docs/authorization_context.md +0 -92
- data/docs/behaviour.md +0 -113
- data/docs/caching.md +0 -273
- data/docs/controller_action_aliases.md +0 -109
- data/docs/custom_lookup_chain.md +0 -48
- data/docs/custom_policy.md +0 -53
- data/docs/debugging.md +0 -55
- data/docs/decorators.md +0 -27
- data/docs/favicon.ico +0 -0
- data/docs/graphql.md +0 -302
- data/docs/i18n.md +0 -44
- data/docs/index.html +0 -43
- data/docs/instrumentation.md +0 -84
- data/docs/lookup_chain.md +0 -17
- data/docs/namespaces.md +0 -77
- data/docs/non_rails.md +0 -28
- data/docs/pre_checks.md +0 -57
- data/docs/pundit_migration.md +0 -80
- data/docs/quick_start.md +0 -118
- data/docs/rails.md +0 -120
- data/docs/reasons.md +0 -120
- data/docs/scoping.md +0 -255
- data/docs/testing.md +0 -333
- data/docs/writing_policies.md +0 -107
- data/gemfiles/jruby.gemfile +0 -8
- data/gemfiles/rails42.gemfile +0 -8
- data/gemfiles/rails6.gemfile +0 -8
- data/gemfiles/railsmaster.gemfile +0 -6
- data/lib/action_policy/ext/string_match.rb +0 -14
- data/lib/action_policy/ext/yield_self_then.rb +0 -25
|
@@ -8,8 +8,11 @@ module ActionPolicy
|
|
|
8
8
|
using ActionPolicy::Ext::PolicyCacheKey
|
|
9
9
|
|
|
10
10
|
# Returns policy instance for the record.
|
|
11
|
-
def policy_for(record:, with: nil, namespace: authorization_namespace, context: authorization_context, allow_nil: false)
|
|
12
|
-
policy_class = with || ::ActionPolicy.lookup(
|
|
11
|
+
def policy_for(record:, with: nil, namespace: authorization_namespace, context: authorization_context, allow_nil: false, default: default_authorization_policy_class)
|
|
12
|
+
policy_class = with || ::ActionPolicy.lookup(
|
|
13
|
+
record,
|
|
14
|
+
**{namespace, context, allow_nil, default}
|
|
15
|
+
)
|
|
13
16
|
policy_class&.new(record, **context)
|
|
14
17
|
end
|
|
15
18
|
|
|
@@ -21,6 +24,10 @@ module ActionPolicy
|
|
|
21
24
|
# override to provide specific authorization namespace
|
|
22
25
|
end
|
|
23
26
|
|
|
27
|
+
def default_authorization_policy_class
|
|
28
|
+
# override to provide a policy class use when no policy found
|
|
29
|
+
end
|
|
30
|
+
|
|
24
31
|
# Override this method to provide implicit authorization target
|
|
25
32
|
# that would be used in case `record` is not specified in
|
|
26
33
|
# `authorize!` and `allowed_to?` call.
|
|
@@ -46,7 +53,7 @@ module ActionPolicy
|
|
|
46
53
|
|
|
47
54
|
def policy_for_cache_key(record:, with: nil, namespace: nil, context: authorization_context, **)
|
|
48
55
|
record_key = record._policy_cache_key(use_object_id: true)
|
|
49
|
-
context_key = context.values.map {
|
|
56
|
+
context_key = context.values.map { _1._policy_cache_key(use_object_id: true) }.join(".")
|
|
50
57
|
|
|
51
58
|
"#{namespace}/#{with}/#{context_key}/#{record_key}"
|
|
52
59
|
end
|
|
@@ -17,8 +17,9 @@ module ActionPolicy
|
|
|
17
17
|
policy ||= policy_for(record: implicit_authorization_target!, **options)
|
|
18
18
|
|
|
19
19
|
type ||= authorization_scope_type_for(policy, target)
|
|
20
|
+
name = as
|
|
20
21
|
|
|
21
|
-
Authorizer.scopify(target, policy, type
|
|
22
|
+
Authorizer.scopify(target, policy, **{type, name, scope_options})
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
# For backward compatibility
|
|
@@ -9,11 +9,6 @@ module ActionPolicy
|
|
|
9
9
|
using ActionPolicy::Ext::StringConstantize
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
unless "".respond_to?(:match?)
|
|
13
|
-
require "action_policy/ext/string_match"
|
|
14
|
-
using ActionPolicy::Ext::StringMatch
|
|
15
|
-
end
|
|
16
|
-
|
|
17
12
|
module Ext
|
|
18
13
|
def namespace
|
|
19
14
|
return unless name&.match?(/[^^]::/)
|
|
@@ -23,7 +18,7 @@ module ActionPolicy
|
|
|
23
18
|
end
|
|
24
19
|
|
|
25
20
|
# See https://github.com/jruby/jruby/issues/5220
|
|
26
|
-
::Module.include(Ext) if RUBY_PLATFORM
|
|
21
|
+
::Module.include(Ext) if RUBY_PLATFORM.match?(/java/i)
|
|
27
22
|
|
|
28
23
|
refine Module do
|
|
29
24
|
include Ext
|
|
@@ -13,77 +13,59 @@ module ActionPolicy
|
|
|
13
13
|
module ObjectExt
|
|
14
14
|
def _policy_cache_key(use_object_id: false)
|
|
15
15
|
return policy_cache_key if respond_to?(:policy_cache_key)
|
|
16
|
+
return cache_key_with_version if respond_to?(:cache_key_with_version)
|
|
16
17
|
return cache_key if respond_to?(:cache_key)
|
|
17
18
|
|
|
18
|
-
return object_id if use_object_id == true
|
|
19
|
+
return object_id.to_s if use_object_id == true
|
|
19
20
|
|
|
20
21
|
raise ArgumentError, "object is not cacheable"
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
# JRuby doesn't support _global_ modules refinements (see https://github.com/jruby/jruby/issues/5220)
|
|
25
|
-
# Fallback to monkey-patching.
|
|
26
|
-
# TODO: remove after 9.2.7.0 (See https://github.com/jruby/jruby/pull/5627)
|
|
27
|
-
::Object.include(ObjectExt) if RUBY_PLATFORM =~ /java/i
|
|
28
|
-
|
|
29
25
|
refine Object do
|
|
30
26
|
include ObjectExt
|
|
31
27
|
end
|
|
32
28
|
|
|
33
29
|
refine NilClass do
|
|
34
|
-
def _policy_cache_key(*)
|
|
35
|
-
""
|
|
36
|
-
end
|
|
30
|
+
def _policy_cache_key(*) = ""
|
|
37
31
|
end
|
|
38
32
|
|
|
39
33
|
refine TrueClass do
|
|
40
|
-
def _policy_cache_key(*)
|
|
41
|
-
"t"
|
|
42
|
-
end
|
|
34
|
+
def _policy_cache_key(*) = "t"
|
|
43
35
|
end
|
|
44
36
|
|
|
45
37
|
refine FalseClass do
|
|
46
|
-
def _policy_cache_key(*)
|
|
47
|
-
"f"
|
|
48
|
-
end
|
|
38
|
+
def _policy_cache_key(*) = "f"
|
|
49
39
|
end
|
|
50
40
|
|
|
51
41
|
refine String do
|
|
52
|
-
def _policy_cache_key(*)
|
|
53
|
-
self
|
|
54
|
-
end
|
|
42
|
+
def _policy_cache_key(*) = self
|
|
55
43
|
end
|
|
56
44
|
|
|
57
45
|
refine Symbol do
|
|
58
|
-
def _policy_cache_key(*)
|
|
59
|
-
to_s
|
|
60
|
-
end
|
|
46
|
+
def _policy_cache_key(*) = to_s
|
|
61
47
|
end
|
|
62
48
|
|
|
63
49
|
if RUBY_PLATFORM.match?(/java/i)
|
|
64
50
|
refine Integer do
|
|
65
|
-
def _policy_cache_key(*)
|
|
66
|
-
to_s
|
|
67
|
-
end
|
|
51
|
+
def _policy_cache_key(*) = to_s
|
|
68
52
|
end
|
|
69
53
|
|
|
70
54
|
refine Float do
|
|
71
|
-
def _policy_cache_key(*)
|
|
72
|
-
to_s
|
|
73
|
-
end
|
|
55
|
+
def _policy_cache_key(*) = to_s
|
|
74
56
|
end
|
|
75
57
|
else
|
|
76
58
|
refine Numeric do
|
|
77
|
-
def _policy_cache_key(*)
|
|
78
|
-
to_s
|
|
79
|
-
end
|
|
59
|
+
def _policy_cache_key(*) = to_s
|
|
80
60
|
end
|
|
81
61
|
end
|
|
82
62
|
|
|
83
63
|
refine Time do
|
|
84
|
-
def _policy_cache_key(*)
|
|
85
|
-
|
|
86
|
-
|
|
64
|
+
def _policy_cache_key(*) = to_s
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
refine Module do
|
|
68
|
+
def _policy_cache_key(*) = name
|
|
87
69
|
end
|
|
88
70
|
end
|
|
89
71
|
end
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
module ActionPolicy
|
|
4
4
|
module Ext
|
|
5
|
-
# Add `
|
|
6
|
-
module
|
|
5
|
+
# Add `camelize` to Symbol
|
|
6
|
+
module SymbolCamelize
|
|
7
7
|
refine Symbol do
|
|
8
|
-
if "".respond_to?(:
|
|
9
|
-
def
|
|
10
|
-
to_s.
|
|
8
|
+
if "".respond_to?(:camelize)
|
|
9
|
+
def camelize
|
|
10
|
+
to_s.camelize
|
|
11
11
|
end
|
|
12
12
|
else
|
|
13
|
-
def
|
|
13
|
+
def camelize
|
|
14
14
|
word = to_s.capitalize
|
|
15
15
|
word.gsub!(/(?:_)([a-z\d]*)/) { $1.capitalize }
|
|
16
16
|
word
|
data/lib/action_policy/i18n.rb
CHANGED
|
@@ -21,7 +21,7 @@ module ActionPolicy
|
|
|
21
21
|
private
|
|
22
22
|
|
|
23
23
|
def candidates_for(policy_class, rule)
|
|
24
|
-
policy_hierarchy = policy_class.ancestors.select {
|
|
24
|
+
policy_hierarchy = policy_class.ancestors.select { _1.respond_to?(:identifier) }
|
|
25
25
|
[
|
|
26
26
|
*policy_hierarchy.map { |klass| :"policy.#{klass.identifier}.#{rule}" },
|
|
27
27
|
:"policy.#{rule}",
|
|
@@ -12,8 +12,8 @@ module ActionPolicy
|
|
|
12
12
|
using ActionPolicy::Ext::StringConstantize
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
require "action_policy/ext/
|
|
16
|
-
using ActionPolicy::Ext::
|
|
15
|
+
require "action_policy/ext/symbol_camelize"
|
|
16
|
+
using ActionPolicy::Ext::SymbolCamelize
|
|
17
17
|
|
|
18
18
|
require "action_policy/ext/module_namespace"
|
|
19
19
|
using ActionPolicy::Ext::ModuleNamespace
|
|
@@ -24,14 +24,26 @@ module ActionPolicy
|
|
|
24
24
|
class << self
|
|
25
25
|
attr_reader :store
|
|
26
26
|
|
|
27
|
-
def
|
|
27
|
+
def put_if_absent(scope, namespace, policy)
|
|
28
|
+
local_store = store[scope][namespace]
|
|
29
|
+
return local_store[policy] if local_store[policy]
|
|
30
|
+
local_store[policy] ||= yield
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def fetch(namespace, policy, strict:, &block)
|
|
28
34
|
return yield unless LookupChain.namespace_cache_enabled?
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
|
|
36
|
+
if strict
|
|
37
|
+
put_if_absent(:strict, namespace, policy, &block)
|
|
38
|
+
else
|
|
39
|
+
cached_policy = put_if_absent(:strict, namespace, policy, &block)
|
|
40
|
+
put_if_absent(:flexible, namespace, policy) { cached_policy }
|
|
41
|
+
end
|
|
31
42
|
end
|
|
32
43
|
|
|
33
44
|
def clear
|
|
34
|
-
|
|
45
|
+
hash = Hash.new { |h, k| h[k] = {} }
|
|
46
|
+
@store = {strict: hash, flexible: hash.clone}
|
|
35
47
|
end
|
|
36
48
|
end
|
|
37
49
|
|
|
@@ -53,22 +65,23 @@ module ActionPolicy
|
|
|
53
65
|
|
|
54
66
|
private
|
|
55
67
|
|
|
56
|
-
def lookup_within_namespace(policy_name, namespace)
|
|
57
|
-
|
|
68
|
+
def lookup_within_namespace(policy_name, namespace, strict: false)
|
|
69
|
+
return unless namespace
|
|
70
|
+
NamespaceCache.fetch(namespace.name, policy_name, strict: strict) do
|
|
58
71
|
mod = namespace
|
|
59
|
-
|
|
60
72
|
loop do
|
|
61
73
|
policy = "#{mod.name}::#{policy_name}".safe_constantize
|
|
62
|
-
|
|
63
74
|
break policy unless policy.nil?
|
|
64
|
-
|
|
65
75
|
mod = mod.namespace
|
|
66
|
-
|
|
67
|
-
break if mod.nil?
|
|
76
|
+
break if mod.nil? || strict
|
|
68
77
|
end
|
|
69
78
|
end
|
|
70
79
|
end
|
|
71
80
|
|
|
81
|
+
def objectify_policy(policy_name, strict: false)
|
|
82
|
+
policy_name.safe_constantize unless strict
|
|
83
|
+
end
|
|
84
|
+
|
|
72
85
|
def policy_class_name_for(record)
|
|
73
86
|
return record.policy_name.to_s if record.respond_to?(:policy_name)
|
|
74
87
|
|
|
@@ -111,23 +124,30 @@ module ActionPolicy
|
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
# Infer from passed symbol
|
|
114
|
-
SYMBOL_LOOKUP = ->(record, namespace: nil, **) {
|
|
127
|
+
SYMBOL_LOOKUP = ->(record, namespace: nil, strict_namespace: false, **) {
|
|
115
128
|
next unless record.is_a?(Symbol)
|
|
116
129
|
|
|
117
|
-
policy_name = "#{record.
|
|
118
|
-
|
|
119
|
-
policy_name
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
policy_name = "#{record.camelize}Policy"
|
|
131
|
+
lookup_within_namespace(policy_name, namespace, strict: strict_namespace) ||
|
|
132
|
+
objectify_policy(policy_name, strict: strict_namespace)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# (Optional) Infer using String#classify if available
|
|
136
|
+
CLASSIFY_SYMBOL_LOOKUP = ->(record, namespace: nil, strict_namespace: false, **) {
|
|
137
|
+
next unless record.is_a?(Symbol)
|
|
138
|
+
|
|
139
|
+
policy_name = "#{record.to_s.classify}Policy"
|
|
140
|
+
lookup_within_namespace(policy_name, namespace, strict: strict_namespace) ||
|
|
141
|
+
objectify_policy(policy_name, strict: strict_namespace)
|
|
123
142
|
}
|
|
124
143
|
|
|
125
144
|
self.chain = [
|
|
126
145
|
SYMBOL_LOOKUP,
|
|
146
|
+
(CLASSIFY_SYMBOL_LOOKUP if String.method_defined?(:classify)),
|
|
127
147
|
INSTANCE_POLICY_CLASS,
|
|
128
148
|
CLASS_POLICY_CLASS,
|
|
129
149
|
NAMESPACE_LOOKUP,
|
|
130
150
|
INFER_FROM_CLASS
|
|
131
|
-
]
|
|
151
|
+
].compact
|
|
132
152
|
end
|
|
133
153
|
end
|
|
@@ -46,23 +46,18 @@ module ActionPolicy
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def lookup_alias(rule)
|
|
50
|
-
rules_aliases[rule]
|
|
51
|
-
end
|
|
49
|
+
def lookup_alias(rule) = rules_aliases[rule]
|
|
52
50
|
|
|
53
|
-
def lookup_default_rule
|
|
54
|
-
rules_aliases[DEFAULT]
|
|
55
|
-
end
|
|
51
|
+
def lookup_default_rule() = rules_aliases[DEFAULT]
|
|
56
52
|
|
|
57
53
|
def rules_aliases
|
|
58
54
|
return @rules_aliases if instance_variable_defined?(:@rules_aliases)
|
|
59
55
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
end
|
|
56
|
+
if superclass.respond_to?(:rules_aliases)
|
|
57
|
+
superclass.rules_aliases.dup
|
|
58
|
+
else
|
|
59
|
+
{}
|
|
60
|
+
end => @rules_aliases
|
|
66
61
|
end
|
|
67
62
|
|
|
68
63
|
def method_added(name)
|
|
@@ -43,21 +43,17 @@ module ActionPolicy
|
|
|
43
43
|
|
|
44
44
|
attr_reader :authorization_context
|
|
45
45
|
|
|
46
|
-
def initialize(
|
|
47
|
-
super(
|
|
46
|
+
def initialize(record = nil, **params)
|
|
47
|
+
super(record)
|
|
48
48
|
|
|
49
49
|
@authorization_context = {}
|
|
50
50
|
|
|
51
51
|
self.class.authorization_targets.each do |id, opts|
|
|
52
|
-
|
|
53
|
-
val = params.fetch(id, nil)
|
|
54
|
-
else
|
|
55
|
-
raise AuthorizationContextMissing, id unless params.key?(id)
|
|
52
|
+
raise AuthorizationContextMissing, id unless params.key?(id) || opts[:optional]
|
|
56
53
|
|
|
57
|
-
|
|
54
|
+
val = params.fetch(id, nil)
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
end
|
|
56
|
+
raise AuthorizationContextMissing, id if val.nil? && opts[:allow_nil] != true
|
|
61
57
|
|
|
62
58
|
authorization_context[id] = instance_variable_set("@#{id}", val)
|
|
63
59
|
end
|
|
@@ -66,9 +62,11 @@ module ActionPolicy
|
|
|
66
62
|
end
|
|
67
63
|
|
|
68
64
|
module ClassMethods # :nodoc:
|
|
69
|
-
def authorize(*ids,
|
|
65
|
+
def authorize(*ids, allow_nil: false, optional: false)
|
|
66
|
+
allow_nil ||= optional
|
|
67
|
+
|
|
70
68
|
ids.each do |id|
|
|
71
|
-
authorization_targets[id] =
|
|
69
|
+
authorization_targets[id] = {allow_nil, optional}
|
|
72
70
|
end
|
|
73
71
|
|
|
74
72
|
attr_reader(*ids)
|
|
@@ -77,12 +75,11 @@ module ActionPolicy
|
|
|
77
75
|
def authorization_targets
|
|
78
76
|
return @authorization_targets if instance_variable_defined?(:@authorization_targets)
|
|
79
77
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
end
|
|
78
|
+
if superclass.respond_to?(:authorization_targets)
|
|
79
|
+
superclass.authorization_targets.dup
|
|
80
|
+
else
|
|
81
|
+
{}
|
|
82
|
+
end => @authorization_targets
|
|
86
83
|
end
|
|
87
84
|
end
|
|
88
85
|
end
|
|
@@ -3,16 +3,13 @@
|
|
|
3
3
|
require "action_policy/version"
|
|
4
4
|
|
|
5
5
|
module ActionPolicy # :nodoc:
|
|
6
|
+
using RubyNext
|
|
7
|
+
|
|
6
8
|
# By default cache namespace (or prefix) contains major and minor version of the gem
|
|
7
9
|
CACHE_NAMESPACE = "acp:#{ActionPolicy::VERSION.split(".").take(2).join(".")}"
|
|
8
10
|
|
|
9
|
-
require "action_policy/ext/yield_self_then"
|
|
10
11
|
require "action_policy/ext/policy_cache_key"
|
|
11
12
|
|
|
12
|
-
unless "".respond_to?(:then)
|
|
13
|
-
require "action_policy/ext/yield_self_then"
|
|
14
|
-
using ActionPolicy::Ext::YieldSelfThen
|
|
15
|
-
end
|
|
16
13
|
using ActionPolicy::Ext::PolicyCacheKey
|
|
17
14
|
|
|
18
15
|
module Policy
|
|
@@ -26,22 +23,31 @@ module ActionPolicy # :nodoc:
|
|
|
26
23
|
end
|
|
27
24
|
end
|
|
28
25
|
|
|
29
|
-
def cache_namespace
|
|
30
|
-
|
|
26
|
+
def cache_namespace() = ActionPolicy::CACHE_NAMESPACE
|
|
27
|
+
|
|
28
|
+
def cache_key(*parts)
|
|
29
|
+
[
|
|
30
|
+
cache_namespace,
|
|
31
|
+
*parts
|
|
32
|
+
].map { _1._policy_cache_key }.join("/")
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
def rule_cache_key(rule)
|
|
36
|
+
cache_key(
|
|
37
|
+
context_cache_key,
|
|
38
|
+
record,
|
|
39
|
+
self.class,
|
|
40
|
+
rule
|
|
41
|
+
)
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
def context_cache_key
|
|
39
|
-
authorization_context.map {
|
|
45
|
+
authorization_context.map { _2._policy_cache_key.to_s }.join("/")
|
|
40
46
|
end
|
|
41
47
|
|
|
42
48
|
def apply_with_cache(rule)
|
|
43
49
|
options = self.class.cached_rules.fetch(rule)
|
|
44
|
-
key =
|
|
50
|
+
key = rule_cache_key(rule)
|
|
45
51
|
|
|
46
52
|
ActionPolicy.cache_store.then do |store|
|
|
47
53
|
@result = store.read(key)
|
|
@@ -62,6 +68,17 @@ module ActionPolicy # :nodoc:
|
|
|
62
68
|
apply_with_cache(rule) { super }
|
|
63
69
|
end
|
|
64
70
|
|
|
71
|
+
def cache(*parts, **options)
|
|
72
|
+
key = cache_key(*parts)
|
|
73
|
+
ActionPolicy.cache_store.then do |store|
|
|
74
|
+
res = store.read(key)
|
|
75
|
+
next res unless res.nil?
|
|
76
|
+
res = yield
|
|
77
|
+
store.write(key, res, options)
|
|
78
|
+
res
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
65
82
|
module ClassMethods # :nodoc:
|
|
66
83
|
def cache(*rules, **options)
|
|
67
84
|
rules.each do |rule|
|
|
@@ -72,12 +89,11 @@ module ActionPolicy # :nodoc:
|
|
|
72
89
|
def cached_rules
|
|
73
90
|
return @cached_rules if instance_variable_defined?(:@cached_rules)
|
|
74
91
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
end
|
|
92
|
+
if superclass.respond_to?(:cached_rules)
|
|
93
|
+
superclass.cached_rules.dup
|
|
94
|
+
else
|
|
95
|
+
{}
|
|
96
|
+
end => @cached_rules
|
|
81
97
|
end
|
|
82
98
|
end
|
|
83
99
|
end
|