subroutine 2.0.1 → 2.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9fbd9c97951c8e07f3f84fe1f9826d4fff45a7f0fe99045d375e34d530fb0934
4
- data.tar.gz: db76eef88d0afd766a7a906d0cf5a202286d90da3f6ec113e798b6709f3c96e4
3
+ metadata.gz: be1eef70ae231ae5b344cf1400ed9ea17a60df49fd1243eb744c13e4aca5904e
4
+ data.tar.gz: 21f60843110c2b5f6c70281dc1999ed84923848f805cbd08472cb7a863a00a59
5
5
  SHA512:
6
- metadata.gz: 2310334da4ebf40292d6868c1ab59b028d790fd01db3ef55825d4f680810e157ffd35c9d6a19e6b1e58816aad8eb87f01b1ae9e9395914350d23b80a84b4874b
7
- data.tar.gz: 4b426d21e7e91f27405daf3a7438f4a049f4a5a7ee13002488259e5599989a867d2fbf9c31f56cff7c8be452708175ba786700729ab88b2f186c4ed4159fcecb
6
+ metadata.gz: 3cb5596227a06ddfdcca54205bb0c599919ffae5f29ef30ab25d437e7cf8cb03462c99015c957fdfce8d2a7a3ed910b013da7e84f6516a9f37a34a44fa44734b
7
+ data.tar.gz: 141e1f223f7da3dc7d080cbc891cd9533a905833ceb8a85e0941b06b6455cf83dea42aabe9f3eeaf977966ea227ead94446462c86ad28261b37436b389152c45
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.5.7
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.
@@ -9,11 +9,13 @@ module Subroutine
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
- class_attribute :authorization_declared, instance_writer: false
13
- self.authorization_declared = false
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 authorize(validation_name)
26
- validate validation_name, unless: :skip_auth_checks?
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
- self.authorization_declared = true
36
+ authorize :authorize_user_not_required
31
37
  end
32
38
 
33
39
  def require_user!
34
- self.authorization_declared = true
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
- self.authorization_declared = true
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,45 @@ module Subroutine
57
55
  if_conditionals = Array(opts[:if])
58
56
  unless_conditionals = Array(opts[:unless])
59
57
 
60
- validate unless: :skip_auth_checks? do
61
- run_it = true
62
- # http://guides.rubyonrails.org/active_record_validations.html#combining-validation-conditions
58
+ meths.each do |meth|
59
+ normalized_meth = meth.to_s[0...-1] if meth.to_s.end_with?("?")
60
+ auth_method_name = :"authorize_#{policy_name}_#{normalized_meth}"
63
61
 
64
- # The validation only runs when all the :if conditions
65
- if if_conditionals.present?
66
- run_it &&= if_conditionals.all? { |i| send(i) }
67
- end
62
+ define_method auth_method_name do
63
+ run_it = true
64
+ # http://guides.rubyonrails.org/active_record_validations.html#combining-validation-conditions
68
65
 
69
- # and none of the :unless conditions are evaluated to true.
70
- if unless_conditionals.present?
71
- run_it &&= unless_conditionals.none? { |u| send(u) }
72
- end
66
+ # The validation only runs when all the :if conditions evaluate to true
67
+ if if_conditionals.present?
68
+ run_it &&= if_conditionals.all? { |i| send(i) }
69
+ end
70
+
71
+ # and none of the :unless conditions are evaluated to true.
72
+ if unless_conditionals.present?
73
+ run_it &&= unless_conditionals.none? { |u| send(u) }
74
+ end
75
+
76
+ return unless run_it
77
+
78
+ p = send(policy_name)
79
+ unauthorized! unless p
73
80
 
74
- next unless run_it
81
+ result = if p.respond_to?("#{normalized_meth}?")
82
+ p.send("#{normalized_meth}?")
83
+ else
84
+ p.send(normalized_meth)
85
+ end
75
86
 
76
- p = send(policy_name)
77
- if !p || meths.any? { |m| !(p.respond_to?("#{m}?") ? p.send("#{m}?") : p.send(m)) }
78
- unauthorized! opts[:error]
87
+ unauthorized! opts[:error] unless result
79
88
  end
89
+
90
+ authorize auth_method_name
80
91
  end
81
92
  end
82
-
83
93
  end
84
94
 
85
95
  def initialize(*args, &block)
86
- raise Subroutine::Auth::AuthorizationNotDeclaredError unless self.class.authorization_declared
96
+ raise Subroutine::Auth::AuthorizationNotDeclaredError unless self.class.authorization_declared?
87
97
 
88
98
  @skip_auth_checks = false
89
99
 
@@ -124,5 +134,23 @@ module Subroutine
124
134
  raise ::Subroutine::Auth::NotAuthorizedError, reason
125
135
  end
126
136
 
137
+ def validate_authorization_checks
138
+ authorization_checks.each do |check|
139
+ send(check)
140
+ end
141
+ end
142
+
143
+ def authorize_user_not_required
144
+ true
145
+ end
146
+
147
+ def authorize_user_required
148
+ unauthorized! unless current_user.present?
149
+ end
150
+
151
+ def authorize_no_user_required
152
+ unauthorized! :empty_unauthorized if current_user.present?
153
+ end
154
+
127
155
  end
128
156
  end
@@ -3,8 +3,8 @@
3
3
  module Subroutine
4
4
 
5
5
  MAJOR = 2
6
- MINOR = 0
7
- PATCH = 1
6
+ MINOR = 1
7
+ PATCH = 0
8
8
  PRE = nil
9
9
 
10
10
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
@@ -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)
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.0.1
4
+ version: 2.1.0
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-02-18 00:00:00.000000000 Z
11
+ date: 2022-04-11 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.3.7
221
+ rubygems_version: 3.1.6
222
222
  signing_key:
223
223
  specification_version: 4
224
224
  summary: Feature-driven operation objects.