subroutine 2.0.1 → 2.1.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/.ruby-version +1 -1
- data/CHANGELOG.MD +6 -0
- data/lib/subroutine/auth.rb +65 -32
- data/lib/subroutine/fields.rb +2 -2
- data/lib/subroutine/version.rb +2 -2
- data/test/subroutine/auth_test.rb +14 -0
- data/test/subroutine/fields_test.rb +7 -0
- data/test/support/ops.rb +29 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63080af90148b6faaff42be6f9753d6f5ef36f3f8ebe650a1372905836f5e208
|
4
|
+
data.tar.gz: 9522cbaf937f5bdfa85fbb629ad8a1f3f014dce6ea42784ef68b39c4ecebad49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a76f25b779fd8a9ccc3958febe5b68906d7260f052b5200d6b080680f9f80f79debebe2bf35ee199f6996cccd827f0844e3710d30f0ee367dd248c6900f45c74
|
7
|
+
data.tar.gz: c3e50c34de7e4f656168cec625bccb1bede1fcd4dbbdd5bef7d9d0dabf9a2695a470dd749b2ec5785448b6cd45c0c3454b469d49a157e9d19fffc2ada78b75ce
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.5
|
1
|
+
2.7.5
|
data/CHANGELOG.MD
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## Subroutine 2.0
|
2
|
+
|
3
|
+
The updates between 1.0 and 2.0 are relatively minor and are focused more on cleaning up the codebase and extending the use of the 0.9->1.0 refactor. There are, however, breaking changes to how associations are loaded. The association is no longer loaded via `find()` but rather `find_by!(id:)`. Given this, a major version was released.
|
4
|
+
|
5
|
+
**Note:** 2.0.0 was released with a bug and subsequently yanked. 2.0.1 is the first available 2.x version.
|
6
|
+
|
1
7
|
## Subroutine 1.0
|
2
8
|
|
3
9
|
A massive refactor took place between 0.9 and 1.0, including breaking changes. The goal was to reduce complexity, simplify backtraces, and increase the overall safety and reliability of the library.
|
data/lib/subroutine/auth.rb
CHANGED
@@ -9,11 +9,13 @@ module Subroutine
|
|
9
9
|
extend ActiveSupport::Concern
|
10
10
|
|
11
11
|
included do
|
12
|
-
class_attribute :
|
13
|
-
self.
|
12
|
+
class_attribute :authorization_checks
|
13
|
+
self.authorization_checks = []
|
14
14
|
|
15
15
|
class_attribute :user_class_name, instance_writer: false
|
16
16
|
self.user_class_name = "User"
|
17
|
+
|
18
|
+
validate :validate_authorization_checks, unless: :skip_auth_checks?
|
17
19
|
end
|
18
20
|
|
19
21
|
module ClassMethods
|
@@ -22,28 +24,24 @@ module Subroutine
|
|
22
24
|
[user_class_name, "Integer", "NilClass"].compact
|
23
25
|
end
|
24
26
|
|
25
|
-
def
|
26
|
-
|
27
|
+
def authorization_declared?
|
28
|
+
authorization_checks.any?
|
29
|
+
end
|
30
|
+
|
31
|
+
def authorize(check_name)
|
32
|
+
self.authorization_checks += [check_name.to_sym]
|
27
33
|
end
|
28
34
|
|
29
35
|
def no_user_requirements!
|
30
|
-
|
36
|
+
authorize :authorize_user_not_required
|
31
37
|
end
|
32
38
|
|
33
39
|
def require_user!
|
34
|
-
|
35
|
-
|
36
|
-
validate unless: :skip_auth_checks? do
|
37
|
-
unauthorized! unless current_user.present?
|
38
|
-
end
|
40
|
+
authorize :authorize_user_required
|
39
41
|
end
|
40
42
|
|
41
43
|
def require_no_user!
|
42
|
-
|
43
|
-
|
44
|
-
validate unless: :skip_auth_checks? do
|
45
|
-
unauthorized! :empty_unauthorized if current_user.present?
|
46
|
-
end
|
44
|
+
authorize :authorize_no_user_required
|
47
45
|
end
|
48
46
|
|
49
47
|
# policy :can_update_user
|
@@ -57,33 +55,50 @@ module Subroutine
|
|
57
55
|
if_conditionals = Array(opts[:if])
|
58
56
|
unless_conditionals = Array(opts[:unless])
|
59
57
|
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
meths.each do |meth|
|
59
|
+
normalized_meth = if normalized_meth.to_s.end_with?("?")
|
60
|
+
meth.to_s[0...-1]
|
61
|
+
else
|
62
|
+
meth
|
63
|
+
end
|
63
64
|
|
64
|
-
|
65
|
-
if if_conditionals.present?
|
66
|
-
run_it &&= if_conditionals.all? { |i| send(i) }
|
67
|
-
end
|
65
|
+
auth_method_name = :"authorize_#{policy_name}_#{normalized_meth}"
|
68
66
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
67
|
+
define_method auth_method_name do
|
68
|
+
run_it = true
|
69
|
+
# http://guides.rubyonrails.org/active_record_validations.html#combining-validation-conditions
|
70
|
+
|
71
|
+
# The validation only runs when all the :if conditions evaluate to true
|
72
|
+
if if_conditionals.present?
|
73
|
+
run_it &&= if_conditionals.all? { |i| send(i) }
|
74
|
+
end
|
75
|
+
|
76
|
+
# and none of the :unless conditions are evaluated to true.
|
77
|
+
if unless_conditionals.present?
|
78
|
+
run_it &&= unless_conditionals.none? { |u| send(u) }
|
79
|
+
end
|
80
|
+
|
81
|
+
return unless run_it
|
73
82
|
|
74
|
-
|
83
|
+
p = send(policy_name)
|
84
|
+
unauthorized! unless p
|
75
85
|
|
76
|
-
|
77
|
-
|
78
|
-
|
86
|
+
result = if p.respond_to?("#{normalized_meth}?")
|
87
|
+
p.send("#{normalized_meth}?")
|
88
|
+
else
|
89
|
+
p.send(normalized_meth)
|
90
|
+
end
|
91
|
+
|
92
|
+
unauthorized! opts[:error] unless result
|
79
93
|
end
|
94
|
+
|
95
|
+
authorize auth_method_name
|
80
96
|
end
|
81
97
|
end
|
82
|
-
|
83
98
|
end
|
84
99
|
|
85
100
|
def initialize(*args, &block)
|
86
|
-
raise Subroutine::Auth::AuthorizationNotDeclaredError unless self.class.authorization_declared
|
101
|
+
raise Subroutine::Auth::AuthorizationNotDeclaredError unless self.class.authorization_declared?
|
87
102
|
|
88
103
|
@skip_auth_checks = false
|
89
104
|
|
@@ -124,5 +139,23 @@ module Subroutine
|
|
124
139
|
raise ::Subroutine::Auth::NotAuthorizedError, reason
|
125
140
|
end
|
126
141
|
|
142
|
+
def validate_authorization_checks
|
143
|
+
authorization_checks.each do |check|
|
144
|
+
send(check)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def authorize_user_not_required
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
def authorize_user_required
|
153
|
+
unauthorized! unless current_user.present?
|
154
|
+
end
|
155
|
+
|
156
|
+
def authorize_no_user_required
|
157
|
+
unauthorized! :empty_unauthorized if current_user.present?
|
158
|
+
end
|
159
|
+
|
127
160
|
end
|
128
161
|
end
|
data/lib/subroutine/fields.rb
CHANGED
@@ -216,9 +216,9 @@ module Subroutine
|
|
216
216
|
field_provided?(name) ? all_params[name] : all_default_params[name]
|
217
217
|
end
|
218
218
|
|
219
|
-
def set_field(name, value,
|
219
|
+
def set_field(name, value, opts = {})
|
220
220
|
config = get_field_config(name)
|
221
|
-
@provided_fields[name] = true
|
221
|
+
@provided_fields[name] = true unless opts[:track_provided] == false
|
222
222
|
value = attempt_cast(value, config) do |e|
|
223
223
|
"Error during assignment of field `#{name}`: #{e}"
|
224
224
|
end
|
data/lib/subroutine/version.rb
CHANGED
@@ -57,6 +57,16 @@ module Subroutine
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
def test_authorization_checks_are_registered_on_the_class
|
61
|
+
assert_equal false, MissingAuthOp.authorization_declared?
|
62
|
+
|
63
|
+
assert_equal true, CustomAuthorizeOp.authorization_declared?
|
64
|
+
assert_equal [:authorize_user_required, :authorize_user_is_correct], CustomAuthorizeOp.authorization_checks
|
65
|
+
|
66
|
+
assert_equal true, NoUserRequirementsOp.authorization_declared?
|
67
|
+
assert_equal [:authorize_user_not_required], NoUserRequirementsOp.authorization_checks
|
68
|
+
end
|
69
|
+
|
60
70
|
def test_the_current_user_can_be_defined_by_an_id
|
61
71
|
user = CustomAuthorizeOp.new(1).current_user
|
62
72
|
assert_equal 1, user.id
|
@@ -92,6 +102,10 @@ module Subroutine
|
|
92
102
|
op.submit!
|
93
103
|
end
|
94
104
|
|
105
|
+
def policy_invocations_are_registered_as_authorization_methods
|
106
|
+
assert PolicyOp.authorization_checks.include?(:authorize_policy_user_can_access)
|
107
|
+
end
|
108
|
+
|
95
109
|
def test_it_runs_policies_with_conditionals
|
96
110
|
# if: false
|
97
111
|
op = IfConditionalPolicyOp.new(user, check_policy: false)
|
@@ -136,5 +136,12 @@ module Subroutine
|
|
136
136
|
assert_equal({}.with_indifferent_access, op.without_inherited_params)
|
137
137
|
end
|
138
138
|
|
139
|
+
def test_fields_are_inherited_to_subclasses
|
140
|
+
assert_equal(%i[amount_cents], ParentInheritanceOp.field_configurations.keys.sort)
|
141
|
+
assert_equal(%i[debit_cents], ParentInheritanceOp::EarlyInheritanceOp.field_configurations.keys.sort)
|
142
|
+
assert_equal(%i[amount_cents debit_cents], ParentInheritanceOp::LateInheritanceOp.field_configurations.keys.sort)
|
143
|
+
assert_equal(%i[amount_cents credit_cents], OuterInheritanceOp.field_configurations.keys.sort)
|
144
|
+
end
|
145
|
+
|
139
146
|
end
|
140
147
|
end
|
data/test/support/ops.rb
CHANGED
@@ -228,13 +228,19 @@ class PolicyOp < OpWithAuth
|
|
228
228
|
class FakePolicy
|
229
229
|
|
230
230
|
def user_can_access?
|
231
|
+
true
|
232
|
+
end
|
233
|
+
|
234
|
+
def user_can_do_it
|
231
235
|
false
|
232
236
|
end
|
233
237
|
|
234
238
|
end
|
235
239
|
|
236
240
|
require_user!
|
241
|
+
|
237
242
|
policy :user_can_access?
|
243
|
+
policy :user_can_do_it
|
238
244
|
|
239
245
|
def policy
|
240
246
|
@policy ||= FakePolicy.new
|
@@ -284,10 +290,33 @@ class UnlessConditionalPolicyOp < OpWithAuth
|
|
284
290
|
|
285
291
|
end
|
286
292
|
|
293
|
+
class ParentInheritanceOp < ::Subroutine::Op
|
294
|
+
class EarlyInheritanceOp < ParentInheritanceOp
|
295
|
+
integer :debit_cents
|
296
|
+
end
|
297
|
+
|
298
|
+
integer :amount_cents
|
299
|
+
|
300
|
+
class LateInheritanceOp < ParentInheritanceOp
|
301
|
+
integer :debit_cents
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
class OuterInheritanceOp < ParentInheritanceOp
|
307
|
+
|
308
|
+
integer :credit_cents
|
309
|
+
|
310
|
+
end
|
311
|
+
|
287
312
|
class OpWithAssociation < ::Subroutine::Op
|
288
313
|
|
289
314
|
include ::Subroutine::AssociationFields
|
290
315
|
|
316
|
+
def perform
|
317
|
+
false
|
318
|
+
end
|
319
|
+
|
291
320
|
end
|
292
321
|
|
293
322
|
class SimpleAssociationOp < ::OpWithAssociation
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: subroutine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Nelson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -218,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
218
218
|
- !ruby/object:Gem::Version
|
219
219
|
version: '0'
|
220
220
|
requirements: []
|
221
|
-
rubygems_version: 3.
|
221
|
+
rubygems_version: 3.1.6
|
222
222
|
signing_key:
|
223
223
|
specification_version: 4
|
224
224
|
summary: Feature-driven operation objects.
|