iknow_view_models 3.6.1 → 3.6.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/Gemfile +1 -0
- data/gemfiles/rails_5_2.gemfile +1 -0
- data/gemfiles/rails_6_0.gemfile +1 -0
- data/gemfiles/rails_6_1.gemfile +1 -0
- data/gemfiles/rails_7_0.gemfile +1 -0
- data/iknow_view_models.gemspec +1 -0
- data/lib/iknow_view_models/version.rb +1 -1
- data/lib/view_model/access_control/composed.rb +50 -12
- data/lib/view_model/access_control.rb +8 -0
- data/test/unit/view_model/access_control_test.rb +48 -0
- data/test/unit/view_model/active_record/cache_test.rb +3 -8
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 267212f1572c3f81b65462be6c30e02a12a6562a29d01bd5e0c342a12396acbc
|
4
|
+
data.tar.gz: e8c4addd984351d6df889ba7d75abbe8d5bde7793a48791e24a1b42e7a3fdf42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6039dcc05bed20bce4681c322c3509be3f2a276c0a755fb3e27240eec74fd9eddef68f3c272df33554407853065a98e0f4d03a068c8c0e068cfc02be6f73ab67
|
7
|
+
data.tar.gz: 95fb89d93724d5028905612d846534916c4bdacd1bb88009ae434090b183e17d7311bb2709bfa81b08ff3dff45940ced0ce080ff861529c59cbb96671a661b64
|
data/Gemfile
CHANGED
data/gemfiles/rails_5_2.gemfile
CHANGED
data/gemfiles/rails_6_0.gemfile
CHANGED
data/gemfiles/rails_6_1.gemfile
CHANGED
data/gemfiles/rails_7_0.gemfile
CHANGED
data/iknow_view_models.gemspec
CHANGED
@@ -39,7 +39,7 @@ class ViewModel::AccessControl::Composed < ViewModel::AccessControl
|
|
39
39
|
case
|
40
40
|
when new_allow
|
41
41
|
nil
|
42
|
-
when self.allow_error && other.allow_error
|
42
|
+
when mergeable_error?(self.allow_error) && mergeable_error?(other.allow_error)
|
43
43
|
self.allow_error.merge(other.allow_error)
|
44
44
|
else
|
45
45
|
self.allow_error || other.allow_error
|
@@ -48,6 +48,12 @@ class ViewModel::AccessControl::Composed < ViewModel::AccessControl
|
|
48
48
|
ComposedResult.new(new_allow, other.veto, new_allow_error, other.veto_error)
|
49
49
|
end
|
50
50
|
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def mergeable_error?(err)
|
55
|
+
err&.is_a?(NoRequiredConditionsError)
|
56
|
+
end
|
51
57
|
end
|
52
58
|
|
53
59
|
PermissionsCheck = Struct.new(:location, :reason, :error_type, :checker) do
|
@@ -196,22 +202,54 @@ class ViewModel::AccessControl::Composed < ViewModel::AccessControl
|
|
196
202
|
protected
|
197
203
|
|
198
204
|
def check_delegates(env, ifs, unlesses)
|
199
|
-
|
205
|
+
veto, veto_error = detect_veto(env, unlesses)
|
206
|
+
allow, allow_error = detect_allow(env, ifs)
|
207
|
+
|
208
|
+
ComposedResult.new(allow, veto, allow_error, veto_error)
|
209
|
+
end
|
210
|
+
|
211
|
+
private
|
212
|
+
|
213
|
+
def detect_veto(env, checkers)
|
214
|
+
checkers.each do |checker|
|
215
|
+
result = checker.check(env)
|
216
|
+
next unless result
|
200
217
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
218
|
+
error =
|
219
|
+
if result.is_a?(StandardError)
|
220
|
+
result
|
221
|
+
else
|
222
|
+
checker.error_type.new('Action not permitted because: ' +
|
223
|
+
checker.reason,
|
224
|
+
env.view.blame_reference)
|
225
|
+
end
|
226
|
+
|
227
|
+
# short-circuit exit with failure
|
228
|
+
return true, error
|
206
229
|
end
|
207
230
|
|
208
|
-
|
231
|
+
return false, nil
|
232
|
+
end
|
233
|
+
|
234
|
+
def detect_allow(env, checkers)
|
235
|
+
error = nil
|
236
|
+
|
237
|
+
checkers.each do |checker|
|
238
|
+
result = checker.check(env)
|
239
|
+
next unless result
|
209
240
|
|
210
|
-
|
211
|
-
|
212
|
-
|
241
|
+
if result.is_a?(StandardError)
|
242
|
+
error ||= result
|
243
|
+
else
|
244
|
+
# short-circuit exit with success
|
245
|
+
return true, nil
|
246
|
+
end
|
213
247
|
end
|
214
248
|
|
215
|
-
|
249
|
+
error ||= NoRequiredConditionsError.new(
|
250
|
+
env.view.blame_reference,
|
251
|
+
checkers.map(&:name))
|
252
|
+
|
253
|
+
return false, error
|
216
254
|
end
|
217
255
|
end
|
@@ -149,6 +149,14 @@ class ViewModel::AccessControl
|
|
149
149
|
def raise_if_error!(result)
|
150
150
|
raise (result.error || yield) unless result.permit?
|
151
151
|
end
|
152
|
+
|
153
|
+
# Called from composed access controls via the `env`, this is used to make the
|
154
|
+
# if/unless DSL more readable when returning a custom failure error.
|
155
|
+
def failure(err)
|
156
|
+
raise ArgumentError.new("Unexpected failure type: #{err}") unless err.is_a?(StandardError)
|
157
|
+
|
158
|
+
err
|
159
|
+
end
|
152
160
|
end
|
153
161
|
|
154
162
|
require 'view_model/access_control/open'
|
@@ -156,6 +156,54 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
|
|
156
156
|
assert_equal(2, ex.reasons.count)
|
157
157
|
end
|
158
158
|
|
159
|
+
def test_veto_ordering
|
160
|
+
TestAccessControl.visible_if!('always') { true }
|
161
|
+
|
162
|
+
TestAccessControl.visible_unless!('car starts with i') do
|
163
|
+
view.car =~ /^i/
|
164
|
+
end
|
165
|
+
|
166
|
+
TestAccessControl.visible_unless!('car ends with e') do
|
167
|
+
view.car =~ /e$/
|
168
|
+
end
|
169
|
+
|
170
|
+
assert_serializes(ListView, List.create!(car: 'ok'))
|
171
|
+
refute_serializes(ListView, List.create!(car: 'invisible'), /not permitted.*car starts with i/)
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_custom_error_if
|
175
|
+
TestAccessControl.visible_if!('car is visible1') do
|
176
|
+
view.car == 'visible1' ||
|
177
|
+
# In principle a failure() may return any error, but by returning an
|
178
|
+
# AccessControlError we make it possible to test with refute_serializes
|
179
|
+
failure(ViewModel::AccessControlError.new('Custom Error Message', view.blame_reference))
|
180
|
+
end
|
181
|
+
|
182
|
+
TestAccessControl.visible_if!('car is visible2') do
|
183
|
+
view.car == 'visible2' ||
|
184
|
+
# Only the first failure() recorded by a failed if check will be
|
185
|
+
# raised as the error.
|
186
|
+
failure(ViewModel::AccessControlError.new('Should not be seen', view.blame_reference))
|
187
|
+
end
|
188
|
+
|
189
|
+
assert_serializes(ListView, List.create!(car: 'visible1'))
|
190
|
+
assert_serializes(ListView, List.create!(car: 'visible2'))
|
191
|
+
refute_serializes(ListView, List.create!(car: 'bad'), /Custom Error Message/)
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_custom_error_unless
|
195
|
+
TestAccessControl.visible_if!('always') { true }
|
196
|
+
|
197
|
+
TestAccessControl.visible_unless!('car is invisible') do
|
198
|
+
if view.car == 'invisible'
|
199
|
+
failure(ViewModel::AccessControlError.new('Custom Error Message', view.blame_reference))
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
assert_serializes(ListView, List.create!(car: 'ok'))
|
204
|
+
refute_serializes(ListView, List.create!(car: 'invisible'), /Custom Error Message/)
|
205
|
+
end
|
206
|
+
|
159
207
|
def test_inheritance
|
160
208
|
child_access_control = Class.new(ViewModel::AccessControl::Composed)
|
161
209
|
child_access_control.include_from(TestAccessControl)
|
@@ -15,16 +15,11 @@ require 'view_model/active_record'
|
|
15
15
|
|
16
16
|
DUMMY_RAILS_CACHE = ActiveSupport::Cache::MemoryStore.new
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
18
|
+
IknowCache.configure! do
|
19
|
+
logger ::ActiveRecord::Base.logger
|
20
|
+
cache DUMMY_RAILS_CACHE
|
22
21
|
end
|
23
22
|
|
24
|
-
# Ensure we have a dummy Rails, and then prepend our dummy cache
|
25
|
-
module Rails; end
|
26
|
-
Rails.singleton_class.prepend(RailsDummyCache)
|
27
|
-
|
28
23
|
class ViewModel::ActiveRecord
|
29
24
|
class CacheTest < ActiveSupport::TestCase
|
30
25
|
using ViewModel::Utils::Collections
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iknow_view_models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.6.
|
4
|
+
version: 3.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iKnow Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: actionpack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: activerecord
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|