haveapi 0.20.0 → 0.21.1
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 -1
- data/Rakefile +6 -6
- data/haveapi.gemspec +13 -13
- data/lib/haveapi/action.rb +153 -167
- data/lib/haveapi/action_state.rb +2 -6
- data/lib/haveapi/actions/default.rb +8 -10
- data/lib/haveapi/api.rb +2 -1
- data/lib/haveapi/authentication/base.rb +5 -8
- data/lib/haveapi/authentication/basic/provider.rb +4 -5
- data/lib/haveapi/authentication/chain.rb +19 -17
- data/lib/haveapi/authentication/oauth2/config.rb +12 -32
- data/lib/haveapi/authentication/oauth2/provider.rb +20 -30
- data/lib/haveapi/authentication/oauth2/revoke_endpoint.rb +1 -2
- data/lib/haveapi/authentication/token/action_config.rb +5 -3
- data/lib/haveapi/authentication/token/config.rb +5 -5
- data/lib/haveapi/authentication/token/provider.rb +33 -37
- data/lib/haveapi/authorization.rb +10 -4
- data/lib/haveapi/client_example.rb +11 -14
- data/lib/haveapi/client_examples/curl.rb +37 -37
- data/lib/haveapi/client_examples/fs_client.rb +29 -31
- data/lib/haveapi/client_examples/http.rb +35 -36
- data/lib/haveapi/client_examples/js_client.rb +62 -63
- data/lib/haveapi/client_examples/php_client.rb +77 -76
- data/lib/haveapi/client_examples/ruby_cli.rb +30 -30
- data/lib/haveapi/client_examples/ruby_client.rb +26 -26
- data/lib/haveapi/common.rb +3 -4
- data/lib/haveapi/context.rb +11 -10
- data/lib/haveapi/example.rb +9 -4
- data/lib/haveapi/example_list.rb +2 -2
- data/lib/haveapi/exceptions.rb +1 -1
- data/lib/haveapi/extensions/action_exceptions.rb +2 -2
- data/lib/haveapi/extensions/base.rb +1 -3
- data/lib/haveapi/extensions/exception_mailer.rb +260 -257
- data/lib/haveapi/hooks.rb +40 -39
- data/lib/haveapi/metadata.rb +1 -1
- data/lib/haveapi/model_adapter.rb +16 -27
- data/lib/haveapi/model_adapters/active_record.rb +59 -69
- data/lib/haveapi/output_formatter.rb +7 -7
- data/lib/haveapi/output_formatters/base.rb +2 -4
- data/lib/haveapi/parameters/resource.rb +7 -7
- data/lib/haveapi/parameters/typed.rb +6 -9
- data/lib/haveapi/params.rb +38 -45
- data/lib/haveapi/resource.rb +8 -8
- data/lib/haveapi/resources/action_state.rb +11 -19
- data/lib/haveapi/server.rb +102 -107
- data/lib/haveapi/spec/api_response.rb +1 -1
- data/lib/haveapi/spec/helpers.rb +1 -1
- data/lib/haveapi/spec/mock_action.rb +11 -10
- data/lib/haveapi/spec/spec_methods.rb +9 -8
- data/lib/haveapi/tasks/yard.rb +2 -2
- data/lib/haveapi/types.rb +0 -3
- data/lib/haveapi/validator.rb +6 -3
- data/lib/haveapi/validator_chain.rb +9 -8
- data/lib/haveapi/validators/acceptance.rb +6 -6
- data/lib/haveapi/validators/confirmation.rb +2 -3
- data/lib/haveapi/validators/exclusion.rb +1 -1
- data/lib/haveapi/validators/format.rb +1 -1
- data/lib/haveapi/validators/inclusion.rb +1 -1
- data/lib/haveapi/validators/length.rb +12 -11
- data/lib/haveapi/validators/numericality.rb +14 -13
- data/lib/haveapi/validators/presence.rb +4 -3
- data/lib/haveapi/version.rb +2 -2
- data/lib/haveapi.rb +2 -3
- data/spec/.rubocop.yml +4 -0
- data/spec/action/dsl_spec.rb +18 -18
- data/spec/authorization_spec.rb +8 -8
- data/spec/common_spec.rb +2 -1
- data/spec/documentation_spec.rb +2 -9
- data/spec/envelope_spec.rb +2 -2
- data/spec/hooks_spec.rb +12 -12
- data/spec/parameters/typed_spec.rb +6 -6
- data/spec/params_spec.rb +22 -24
- data/spec/resource_spec.rb +5 -7
- data/spec/spec_helper.rb +0 -1
- data/spec/validators/acceptance_spec.rb +1 -1
- data/spec/validators/confirmation_spec.rb +5 -5
- data/spec/validators/exclusion_spec.rb +3 -3
- data/spec/validators/format_spec.rb +2 -2
- data/spec/validators/inclusion_spec.rb +4 -4
- data/spec/validators/length_spec.rb +23 -23
- data/spec/validators/numericality_spec.rb +13 -13
- data/spec/validators/presence_spec.rb +3 -3
- metadata +49 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e72ad9fd9ee5a7d0ada6b5985e28f51d6fe65423b290aae824f6ff55a067145
|
4
|
+
data.tar.gz: c6c35096b29c02199c3dd4ae46d2ee8ec6920e2f5d5436596e4cde1a133c80cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 722c8af5849aef6fe6dbbf48d53bb159c66a9dcd4decafcc4ba20a5f6fee441dbe0eb2d08a2f91283dd900869e1e36632281fcabc038a0ad8ed83dbc9255e053
|
7
|
+
data.tar.gz: b26b675cb2ce63c3d7f2723f3084bb7e7289d4ee896dfbdcf875ed841adedc9feb991b3ee76715586fc79d8b21657e537c446e2284aab24dd94361dfbbd78383
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -16,16 +16,16 @@ begin
|
|
16
16
|
YARD::Rake::YardocTask.new do |t|
|
17
17
|
t.files = ['lib/**/*.rb']
|
18
18
|
t.options = [
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
'--protected',
|
20
|
+
'--output-dir=html_doc',
|
21
|
+
'--files=doc/*.md',
|
22
|
+
'--files=doc/*.html'
|
23
23
|
]
|
24
|
-
t.before =
|
24
|
+
t.before = proc do
|
25
25
|
document_hooks.call
|
26
26
|
render_doc_file('doc/json-schema.erb', 'doc/JSON-Schema.html').call
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
29
|
rescue LoadError
|
30
|
+
# ignore
|
31
31
|
end
|
data/haveapi.gemspec
CHANGED
@@ -1,30 +1,30 @@
|
|
1
|
-
lib = File.expand_path('
|
2
|
-
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$:.unshift(lib) unless $:.include?(lib)
|
3
3
|
require 'haveapi/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'haveapi'
|
7
7
|
s.version = HaveAPI::VERSION
|
8
8
|
s.summary =
|
9
|
-
|
9
|
+
s.description = 'Framework for creating self-describing APIs'
|
10
10
|
s.authors = 'Jakub Skokan'
|
11
11
|
s.email = 'jakub.skokan@vpsfree.cz'
|
12
12
|
s.files = `git ls-files -z`.split("\x0") + Dir.glob('doc/*')
|
13
13
|
s.license = 'MIT'
|
14
14
|
|
15
|
-
s.required_ruby_version =
|
15
|
+
s.required_ruby_version = ">= #{File.read('../../.ruby-version').strip}"
|
16
16
|
|
17
|
-
s.add_runtime_dependency 'require_all', '~> 2.0.0'
|
18
|
-
s.add_runtime_dependency 'json'
|
19
17
|
s.add_runtime_dependency 'activesupport', '>= 7.1'
|
20
|
-
s.add_runtime_dependency 'sinatra', '~> 3.1.0'
|
21
|
-
s.add_runtime_dependency 'sinatra-contrib', '~> 3.1.0'
|
22
|
-
s.add_runtime_dependency 'tilt', '~> 2.3.0'
|
23
|
-
s.add_runtime_dependency 'redcarpet', '~> 3.6'
|
24
|
-
s.add_runtime_dependency 'rake'
|
25
18
|
s.add_runtime_dependency 'github-markdown'
|
26
|
-
s.add_runtime_dependency '
|
27
|
-
s.add_runtime_dependency '
|
19
|
+
s.add_runtime_dependency 'haveapi-client', '~> 0.21.1'
|
20
|
+
s.add_runtime_dependency 'json'
|
28
21
|
s.add_runtime_dependency 'mail'
|
22
|
+
s.add_runtime_dependency 'nesty', '~> 1.0'
|
29
23
|
s.add_runtime_dependency 'rack-oauth2', '~> 2.2.0'
|
24
|
+
s.add_runtime_dependency 'rake'
|
25
|
+
s.add_runtime_dependency 'redcarpet', '~> 3.6'
|
26
|
+
s.add_runtime_dependency 'require_all', '~> 2.0.0'
|
27
|
+
s.add_runtime_dependency 'sinatra', '~> 3.1.0'
|
28
|
+
s.add_runtime_dependency 'sinatra-contrib', '~> 3.1.0'
|
29
|
+
s.add_runtime_dependency 'tilt', '~> 2.3.0'
|
30
30
|
end
|
data/lib/haveapi/action.rb
CHANGED
@@ -17,29 +17,26 @@ module HaveAPI
|
|
17
17
|
include Hookable
|
18
18
|
|
19
19
|
has_hook :pre_authorize,
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
ret: {
|
28
|
-
blocks: 'array of authorization blocks',
|
29
|
-
}
|
20
|
+
desc: "Called to provide additional authorization blocks. These blocks are called before action's own authorization block. Note that if any of the blocks uses allow/deny rule, it will be the final authorization decision and even action's own authorization block will not be called.",
|
21
|
+
args: {
|
22
|
+
context: 'HaveAPI::Context instance'
|
23
|
+
},
|
24
|
+
ret: {
|
25
|
+
blocks: 'array of authorization blocks'
|
26
|
+
}
|
30
27
|
|
31
28
|
has_hook :exec_exception,
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
attr_reader :message, :errors, :version
|
29
|
+
desc: 'Called when unhandled exceptions occurs during Action.exec',
|
30
|
+
args: {
|
31
|
+
context: 'HaveAPI::Context instance',
|
32
|
+
exception: 'exception instance'
|
33
|
+
},
|
34
|
+
ret: {
|
35
|
+
status: 'true or false, indicating whether error should be reported',
|
36
|
+
message: 'error message sent to the user'
|
37
|
+
}
|
38
|
+
|
39
|
+
attr_reader :message, :errors, :version, :current_user, :request
|
43
40
|
attr_accessor :flags
|
44
41
|
|
45
42
|
class << self
|
@@ -48,13 +45,13 @@ module HaveAPI
|
|
48
45
|
|
49
46
|
def inherited(subclass)
|
50
47
|
# puts "Action.inherited called #{subclass} from #{to_s}"
|
51
|
-
|
48
|
+
super
|
52
49
|
subclass.instance_variable_set(:@obj_type, obj_type)
|
53
50
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
51
|
+
return unless subclass.name
|
52
|
+
|
53
|
+
# not an anonymouse class
|
54
|
+
delayed_inherited(subclass)
|
58
55
|
end
|
59
56
|
|
60
57
|
def delayed_inherited(subclass)
|
@@ -71,9 +68,10 @@ module HaveAPI
|
|
71
68
|
|
72
69
|
m = {}
|
73
70
|
|
74
|
-
@meta.each do |k,v|
|
71
|
+
@meta.each do |k, v|
|
75
72
|
m[k] = v && v.clone
|
76
73
|
next unless v
|
74
|
+
|
77
75
|
m[k].action = subclass
|
78
76
|
end
|
79
77
|
|
@@ -86,11 +84,11 @@ module HaveAPI
|
|
86
84
|
subclass.instance_variable_set(:@model, resource.model)
|
87
85
|
resource.action_defined(subclass)
|
88
86
|
rescue NoMethodError
|
89
|
-
|
87
|
+
nil
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
93
|
-
def initialize
|
91
|
+
def initialize # rubocop:disable Lint/MissingSuper
|
94
92
|
return if @initialized
|
95
93
|
|
96
94
|
check_build("#{self}.input") do
|
@@ -109,9 +107,9 @@ module HaveAPI
|
|
109
107
|
meta(:global) do
|
110
108
|
output do
|
111
109
|
integer :action_state_id,
|
112
|
-
|
113
|
-
|
114
|
-
|
110
|
+
label: 'Action state ID',
|
111
|
+
desc: 'ID of ActionState object for state querying. When null, the action ' \
|
112
|
+
'is not blocking for the current invocation.'
|
115
113
|
end
|
116
114
|
end
|
117
115
|
end
|
@@ -171,7 +169,7 @@ module HaveAPI
|
|
171
169
|
|
172
170
|
def meta(type = :object, &block)
|
173
171
|
if block
|
174
|
-
@meta ||= {object: nil, global: nil}
|
172
|
+
@meta ||= { object: nil, global: nil }
|
175
173
|
@meta[type] ||= Metadata::ActionMetadata.new
|
176
174
|
@meta[type].action = self
|
177
175
|
@meta[type].instance_exec(&block)
|
@@ -180,14 +178,14 @@ module HaveAPI
|
|
180
178
|
end
|
181
179
|
end
|
182
180
|
|
183
|
-
def authorize(&
|
184
|
-
@authorization = Authorization.new(&
|
181
|
+
def authorize(&)
|
182
|
+
@authorization = Authorization.new(&)
|
185
183
|
end
|
186
184
|
|
187
|
-
def example(title = '', &
|
185
|
+
def example(title = '', &)
|
188
186
|
@examples ||= ExampleList.new
|
189
187
|
e = Example.new(title)
|
190
|
-
e.instance_eval(&
|
188
|
+
e.instance_eval(&)
|
191
189
|
@examples << e
|
192
190
|
end
|
193
191
|
|
@@ -195,29 +193,28 @@ module HaveAPI
|
|
195
193
|
(@action_name ? @action_name.to_s : to_s).demodulize
|
196
194
|
end
|
197
195
|
|
198
|
-
|
199
|
-
@action_name = name
|
200
|
-
end
|
196
|
+
attr_writer :action_name
|
201
197
|
|
202
198
|
def build_route(prefix)
|
203
199
|
route = @route || action_name.underscore
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
200
|
+
if @route
|
201
|
+
@route
|
202
|
+
elsif action_name
|
203
|
+
action_name.to_s.demodulize.underscore
|
204
|
+
else
|
205
|
+
to_s.demodulize.underscore
|
206
|
+
end
|
211
207
|
|
212
208
|
if !route.is_a?(String) && route.respond_to?(:call)
|
213
|
-
route = route.call(
|
209
|
+
route = route.call(resource)
|
214
210
|
end
|
215
211
|
|
216
|
-
prefix + route
|
212
|
+
prefix + format(route, resource: resource.resource_name.underscore)
|
217
213
|
end
|
218
214
|
|
219
215
|
def describe(context)
|
220
216
|
authorization = (@authorization && @authorization.clone) || Authorization.new
|
217
|
+
add_pre_authorize_blocks(authorization, context)
|
221
218
|
|
222
219
|
if (context.endpoint || context.current_user) \
|
223
220
|
&& !authorization.authorized?(context.current_user, context.path_params_from_args)
|
@@ -242,14 +239,14 @@ module HaveAPI
|
|
242
239
|
description: @desc,
|
243
240
|
aliases: @aliases,
|
244
241
|
blocking: @blocking ? true : false,
|
245
|
-
input: @input ? @input.describe(context) : {parameters: {}},
|
246
|
-
output: @output ? @output.describe(context) : {parameters: {}},
|
242
|
+
input: @input ? @input.describe(context) : { parameters: {} },
|
243
|
+
output: @output ? @output.describe(context) : { parameters: {} },
|
247
244
|
meta: @meta ? @meta.merge(@meta) { |_, v| v && v.describe(context) } : nil,
|
248
245
|
examples: @examples ? @examples.describe(context) : [],
|
249
246
|
scope: context.action_scope,
|
250
247
|
path: context.resolved_path,
|
251
248
|
method: route_method,
|
252
|
-
help: "#{context.path}?method=#{route_method}"
|
249
|
+
help: "#{context.path}?method=#{route_method}"
|
253
250
|
}
|
254
251
|
end
|
255
252
|
|
@@ -257,7 +254,6 @@ module HaveAPI
|
|
257
254
|
def inherit_attrs_from_resource(action, r, attrs)
|
258
255
|
begin
|
259
256
|
return unless r.obj_type == :resource
|
260
|
-
|
261
257
|
rescue NoMethodError
|
262
258
|
return
|
263
259
|
end
|
@@ -279,16 +275,29 @@ module HaveAPI
|
|
279
275
|
end
|
280
276
|
|
281
277
|
def resolve_path_params(object)
|
282
|
-
if
|
283
|
-
|
278
|
+
if resolve
|
279
|
+
resolve.call(object)
|
284
280
|
|
285
281
|
else
|
286
282
|
object.respond_to?(:id) ? object.id : nil
|
287
283
|
end
|
288
284
|
end
|
285
|
+
|
286
|
+
def add_pre_authorize_blocks(authorization, context)
|
287
|
+
ret = Action.call_hooks(
|
288
|
+
:pre_authorize,
|
289
|
+
args: [context],
|
290
|
+
initial: { blocks: [] }
|
291
|
+
)
|
292
|
+
|
293
|
+
ret[:blocks].reverse_each do |block|
|
294
|
+
authorization.prepend_block(block)
|
295
|
+
end
|
296
|
+
end
|
289
297
|
end
|
290
298
|
|
291
299
|
def initialize(request, version, params, body, context)
|
300
|
+
super()
|
292
301
|
@request = request
|
293
302
|
@version = version
|
294
303
|
@params = params
|
@@ -297,35 +306,24 @@ module HaveAPI
|
|
297
306
|
@context.action = self.class
|
298
307
|
@context.action_instance = self
|
299
308
|
@metadata = {}
|
300
|
-
@reply_meta = {object: {}, global: {}}
|
309
|
+
@reply_meta = { object: {}, global: {} }
|
301
310
|
@flags = {}
|
302
311
|
|
303
312
|
class_auth = self.class.authorization
|
304
313
|
|
305
|
-
if class_auth
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
ret = call_class_hooks_as_for(
|
312
|
-
Action,
|
313
|
-
:pre_authorize,
|
314
|
-
args: [@context],
|
315
|
-
initial: {blocks: []},
|
316
|
-
)
|
314
|
+
@authorization = if class_auth
|
315
|
+
class_auth.clone
|
316
|
+
else
|
317
|
+
Authorization.new {}
|
318
|
+
end
|
317
319
|
|
318
|
-
|
319
|
-
@authorization.prepend_block(block)
|
320
|
-
end
|
320
|
+
self.class.add_pre_authorize_blocks(@authorization, @context)
|
321
321
|
end
|
322
322
|
|
323
323
|
def validate!
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
error(e.message, e.to_hash)
|
328
|
-
end
|
324
|
+
@params = validate
|
325
|
+
rescue ValidationError => e
|
326
|
+
error(e.message, e.to_hash)
|
329
327
|
end
|
330
328
|
|
331
329
|
def authorized?(user)
|
@@ -333,20 +331,12 @@ module HaveAPI
|
|
333
331
|
@authorization.authorized?(user, extract_path_params)
|
334
332
|
end
|
335
333
|
|
336
|
-
def current_user
|
337
|
-
@current_user
|
338
|
-
end
|
339
|
-
|
340
334
|
def params
|
341
335
|
@safe_params
|
342
336
|
end
|
343
337
|
|
344
338
|
def input
|
345
|
-
@safe_params[
|
346
|
-
end
|
347
|
-
|
348
|
-
def request
|
349
|
-
@request
|
339
|
+
@safe_params[self.class.input.namespace] if self.class.input
|
350
340
|
end
|
351
341
|
|
352
342
|
def meta
|
@@ -364,13 +354,9 @@ module HaveAPI
|
|
364
354
|
# --
|
365
355
|
# FIXME: is this correct behaviour?
|
366
356
|
# ++
|
367
|
-
def prepare
|
357
|
+
def prepare; end
|
368
358
|
|
369
|
-
end
|
370
|
-
|
371
|
-
def pre_exec
|
372
|
-
|
373
|
-
end
|
359
|
+
def pre_exec; end
|
374
360
|
|
375
361
|
# This method must be reimplemented in every action.
|
376
362
|
# It must not be invoked directly, only via safe_exec, which restricts output.
|
@@ -383,29 +369,27 @@ module HaveAPI
|
|
383
369
|
# Return array +[status, data|error, errors]+
|
384
370
|
def safe_exec
|
385
371
|
exec_ret = catch(:return) do
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
tmp = call_class_hooks_as_for(Action, :exec_exception, args: [@context, e])
|
393
|
-
|
394
|
-
if tmp.empty?
|
395
|
-
p e.message
|
396
|
-
puts e.backtrace
|
397
|
-
error('Server error occurred')
|
398
|
-
end
|
372
|
+
validate!
|
373
|
+
prepare
|
374
|
+
pre_exec
|
375
|
+
exec
|
376
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
377
|
+
tmp = call_class_hooks_as_for(Action, :exec_exception, args: [@context, e])
|
399
378
|
|
400
|
-
|
401
|
-
|
402
|
-
|
379
|
+
if tmp.empty?
|
380
|
+
p e.message
|
381
|
+
puts e.backtrace
|
382
|
+
error('Server error occurred')
|
383
|
+
end
|
384
|
+
|
385
|
+
unless tmp[:status]
|
386
|
+
error(tmp[:message], {}, http_status: tmp[:http_status] || 500)
|
403
387
|
end
|
404
388
|
end
|
405
389
|
|
406
390
|
begin
|
407
391
|
output_ret = safe_output(exec_ret)
|
408
|
-
rescue Exception => e
|
392
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
409
393
|
tmp = call_class_hooks_as_for(Action, :exec_exception, args: [@context, e])
|
410
394
|
|
411
395
|
p e.message
|
@@ -415,7 +399,7 @@ module HaveAPI
|
|
415
399
|
tmp[:status] || false,
|
416
400
|
tmp[:message] || 'Server error occurred',
|
417
401
|
{},
|
418
|
-
tmp[:http_status] || 500
|
402
|
+
tmp[:http_status] || 500
|
419
403
|
]
|
420
404
|
end
|
421
405
|
|
@@ -436,55 +420,55 @@ module HaveAPI
|
|
436
420
|
out_params = self.class.output.params
|
437
421
|
|
438
422
|
case output.layout
|
439
|
-
|
440
|
-
|
441
|
-
|
423
|
+
when :object
|
424
|
+
out = adapter.output(@context, ret)
|
425
|
+
safe_ret = @authorization.filter_output(
|
426
|
+
out_params,
|
427
|
+
out,
|
428
|
+
true
|
429
|
+
)
|
430
|
+
@reply_meta[:global].update(out.meta)
|
431
|
+
|
432
|
+
when :object_list
|
433
|
+
safe_ret = []
|
434
|
+
|
435
|
+
ret.each do |obj|
|
436
|
+
out = adapter.output(@context, obj)
|
437
|
+
|
438
|
+
safe_ret << @authorization.filter_output(
|
442
439
|
out_params,
|
443
440
|
out,
|
444
441
|
true
|
445
442
|
)
|
446
|
-
|
447
|
-
|
448
|
-
when :object_list
|
449
|
-
safe_ret = []
|
450
|
-
|
451
|
-
ret.each do |obj|
|
452
|
-
out = adapter.output(@context, obj)
|
443
|
+
safe_ret.last.update({ Metadata.namespace => out.meta }) unless meta[:no]
|
444
|
+
end
|
453
445
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
end
|
446
|
+
when :hash
|
447
|
+
safe_ret = @authorization.filter_output(
|
448
|
+
out_params,
|
449
|
+
adapter.output(@context, ret),
|
450
|
+
true
|
451
|
+
)
|
461
452
|
|
462
|
-
|
463
|
-
|
453
|
+
when :hash_list
|
454
|
+
safe_ret = ret
|
455
|
+
safe_ret.map! do |hash|
|
456
|
+
@authorization.filter_output(
|
464
457
|
out_params,
|
465
|
-
adapter.output(@context,
|
458
|
+
adapter.output(@context, hash),
|
466
459
|
true
|
467
460
|
)
|
461
|
+
end
|
468
462
|
|
469
|
-
|
470
|
-
|
471
|
-
safe_ret.map! do |hash|
|
472
|
-
@authorization.filter_output(
|
473
|
-
out_params,
|
474
|
-
adapter.output(@context, hash),
|
475
|
-
true
|
476
|
-
)
|
477
|
-
end
|
478
|
-
|
479
|
-
else
|
480
|
-
safe_ret = ret
|
463
|
+
else
|
464
|
+
safe_ret = ret
|
481
465
|
end
|
482
466
|
|
483
467
|
if self.class.blocking
|
484
468
|
@reply_meta[:global][:action_state_id] = state_id
|
485
469
|
end
|
486
470
|
|
487
|
-
ns = {output.namespace => safe_ret}
|
471
|
+
ns = { output.namespace => safe_ret }
|
488
472
|
ns[Metadata.namespace] = @reply_meta[:global] unless meta[:no]
|
489
473
|
|
490
474
|
[true, ns]
|
@@ -507,6 +491,7 @@ module HaveAPI
|
|
507
491
|
end
|
508
492
|
|
509
493
|
protected
|
494
|
+
|
510
495
|
def with_restricted(**kwargs)
|
511
496
|
if kwargs.empty?
|
512
497
|
@authorization.restrictions
|
@@ -517,7 +502,7 @@ module HaveAPI
|
|
517
502
|
|
518
503
|
# Convert parameter names to corresponding DB names.
|
519
504
|
# By default, input parameters are used for the translation.
|
520
|
-
def to_db_names(hash, src
|
505
|
+
def to_db_names(hash, src = :input)
|
521
506
|
return {} unless hash
|
522
507
|
|
523
508
|
params = self.class.method(src).call.params
|
@@ -528,11 +513,11 @@ module HaveAPI
|
|
528
513
|
hit = false
|
529
514
|
|
530
515
|
params.each do |p|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
516
|
+
next unless k == p.name
|
517
|
+
|
518
|
+
ret[p.db_name] = v
|
519
|
+
hit = true
|
520
|
+
break
|
536
521
|
end
|
537
522
|
|
538
523
|
ret[k] = v unless hit
|
@@ -543,7 +528,7 @@ module HaveAPI
|
|
543
528
|
|
544
529
|
# Convert DB names to corresponding parameter names.
|
545
530
|
# By default, output parameters are used for the translation.
|
546
|
-
def to_param_names(hash, src
|
531
|
+
def to_param_names(hash, src = :output)
|
547
532
|
return {} unless hash
|
548
533
|
|
549
534
|
params = self.class.method(src).call.params
|
@@ -554,11 +539,11 @@ module HaveAPI
|
|
554
539
|
hit = false
|
555
540
|
|
556
541
|
params.each do |p|
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
542
|
+
next unless k == p.db_name
|
543
|
+
|
544
|
+
ret[p.name] = v
|
545
|
+
hit = true
|
546
|
+
break
|
562
547
|
end
|
563
548
|
|
564
549
|
ret[k] = v unless hit
|
@@ -587,6 +572,7 @@ module HaveAPI
|
|
587
572
|
end
|
588
573
|
|
589
574
|
private
|
575
|
+
|
590
576
|
def validate
|
591
577
|
# Validate standard input
|
592
578
|
@safe_params = @params.dup
|
@@ -598,19 +584,19 @@ module HaveAPI
|
|
598
584
|
|
599
585
|
# Then filter allowed params
|
600
586
|
case input.layout
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
self.class.input.params,
|
605
|
-
self.class.model_adapter(self.class.input.layout).input(obj)
|
606
|
-
)
|
607
|
-
end
|
608
|
-
|
609
|
-
else
|
610
|
-
@safe_params[input.namespace] = @authorization.filter_input(
|
587
|
+
when :object_list, :hash_list
|
588
|
+
@safe_params[input.namespace].map! do |obj|
|
589
|
+
@authorization.filter_input(
|
611
590
|
self.class.input.params,
|
612
|
-
self.class.model_adapter(self.class.input.layout).input(
|
591
|
+
self.class.model_adapter(self.class.input.layout).input(obj)
|
613
592
|
)
|
593
|
+
end
|
594
|
+
|
595
|
+
else
|
596
|
+
@safe_params[input.namespace] = @authorization.filter_input(
|
597
|
+
self.class.input.params,
|
598
|
+
self.class.model_adapter(self.class.input.layout).input(@safe_params[input.namespace])
|
599
|
+
)
|
614
600
|
end
|
615
601
|
|
616
602
|
# Now check required params, convert types and set defaults
|
@@ -621,9 +607,9 @@ module HaveAPI
|
|
621
607
|
auth = Authorization.new { allow }
|
622
608
|
@metadata = {}
|
623
609
|
|
624
|
-
return if input && %i
|
610
|
+
return if input && %i[object_list hash_list].include?(input.layout)
|
625
611
|
|
626
|
-
[
|
612
|
+
%i[object global].each do |v|
|
627
613
|
meta = self.class.meta(v)
|
628
614
|
next unless meta
|
629
615
|
|
data/lib/haveapi/action_state.rb
CHANGED
@@ -65,14 +65,10 @@ module HaveAPI
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# @return [Time]
|
68
|
-
def created_at
|
69
|
-
|
70
|
-
end
|
68
|
+
def created_at; end
|
71
69
|
|
72
70
|
# @return [Time]
|
73
|
-
def updated_at
|
74
|
-
|
75
|
-
end
|
71
|
+
def updated_at; end
|
76
72
|
|
77
73
|
# @return [Boolean] true if the action can be cancelled
|
78
74
|
def can_cancel?
|