ecoportal-api-v2 1.1.7 → 2.0.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 +4 -4
- data/.markdownlint.json +4 -0
- data/.rubocop.yml +54 -15
- data/.ruby-version +1 -0
- data/CHANGELOG.md +485 -373
- data/ecoportal-api-v2.gemspec +13 -12
- data/lib/ecoportal/api/common/concerns/benchmarkable.rb +47 -34
- data/lib/ecoportal/api/common/concerns/threadable.rb +41 -0
- data/lib/ecoportal/api/common/concerns.rb +1 -0
- data/lib/ecoportal/api/common/content/array_model.rb +85 -79
- data/lib/ecoportal/api/common/content/class_helpers.rb +34 -31
- data/lib/ecoportal/api/common/content/collection_model.rb +77 -65
- data/lib/ecoportal/api/common/content/double_model.rb +105 -87
- data/lib/ecoportal/api/common/content/wrapped_response.rb +11 -11
- data/lib/ecoportal/api/v2/page/component/reference_field.rb +17 -13
- data/lib/ecoportal/api/v2/page/component.rb +67 -68
- data/lib/ecoportal/api/v2/page/components.rb +9 -9
- data/lib/ecoportal/api/v2/page/force.rb +6 -7
- data/lib/ecoportal/api/v2/page/stages.rb +5 -6
- data/lib/ecoportal/api/v2/page.rb +35 -33
- data/lib/ecoportal/api/v2/pages/page_stage.rb +22 -20
- data/lib/ecoportal/api/v2/pages.rb +18 -14
- data/lib/ecoportal/api/v2/people.rb +2 -3
- data/lib/ecoportal/api/v2/registers.rb +28 -13
- data/lib/ecoportal/api/v2/s3/data.rb +27 -0
- data/lib/ecoportal/api/v2/s3/files/batch_upload.rb +110 -0
- data/lib/ecoportal/api/v2/s3/files/poll.rb +82 -0
- data/lib/ecoportal/api/v2/s3/files/poll_status.rb +52 -0
- data/lib/ecoportal/api/v2/s3/files.rb +132 -0
- data/lib/ecoportal/api/v2/s3/upload.rb +154 -0
- data/lib/ecoportal/api/v2/s3.rb +66 -0
- data/lib/ecoportal/api/v2.rb +10 -3
- data/lib/ecoportal/api/v2_version.rb +1 -1
- metadata +53 -54
@@ -6,12 +6,8 @@ module Ecoportal
|
|
6
6
|
# which differs of `attr_*` ruby native class methods because `pass*`
|
7
7
|
# completelly **links** the methods **to a subjacent `Hash` model**
|
8
8
|
class DoubleModel < Common::BaseModel
|
9
|
-
NOT_USED = Common::Content::ClassHelpers::NOT_USED
|
10
|
-
extend Common::Content::ClassHelpers
|
11
|
-
include Common::Content::ModelHelpers
|
12
|
-
|
13
9
|
class UnlinkedModel < StandardError
|
14
|
-
def initialize
|
10
|
+
def initialize(msg = "Something went wrong when linking the document.", from: nil, key: nil)
|
15
11
|
msg += " From: #{from}." if from
|
16
12
|
msg += " key: #{key}." if key
|
17
13
|
super(msg)
|
@@ -21,6 +17,10 @@ module Ecoportal
|
|
21
17
|
class NoKeyMethod < StandardError
|
22
18
|
end
|
23
19
|
|
20
|
+
NOT_USED = Common::Content::ClassHelpers::NOT_USED
|
21
|
+
extend Common::Content::ClassHelpers
|
22
|
+
include Common::Content::ModelHelpers
|
23
|
+
|
24
24
|
class << self
|
25
25
|
attr_reader :key
|
26
26
|
|
@@ -118,7 +118,7 @@ module Ecoportal
|
|
118
118
|
# as well as its `key` in the underlying `Hash` model.
|
119
119
|
# @param default [Value] the default value that
|
120
120
|
# this `key` will be written in the model when it doesn't exixt
|
121
|
-
def passforced(method, default
|
121
|
+
def passforced(method, default:, read_only: false)
|
122
122
|
model_forced_keys[method.to_s.freeze] = default
|
123
123
|
passthrough(method, read_only: read_only)
|
124
124
|
end
|
@@ -126,8 +126,9 @@ module Ecoportal
|
|
126
126
|
# Ensures `doc` has the `model_forced_keys`. If it doesn't, it adds those missing
|
127
127
|
# with the defined `default` values
|
128
128
|
def enforce!(doc)
|
129
|
-
return unless doc
|
130
|
-
return if
|
129
|
+
return unless doc.is_a?(Hash)
|
130
|
+
return if model_forced_keys.empty?
|
131
|
+
|
131
132
|
model_forced_keys.each do |key, default|
|
132
133
|
doc[key] = default unless doc.key?(key)
|
133
134
|
end
|
@@ -139,8 +140,8 @@ module Ecoportal
|
|
139
140
|
# as well as its `key` in the underlying `Hash` model.
|
140
141
|
# @param read_only [Boolean] should it only define the reader?
|
141
142
|
def passthrough(*methods, read_only: false)
|
142
|
-
pass_reader
|
143
|
-
pass_writer
|
143
|
+
pass_reader(*methods)
|
144
|
+
pass_writer(*methods) unless read_only
|
144
145
|
self
|
145
146
|
end
|
146
147
|
|
@@ -151,9 +152,7 @@ module Ecoportal
|
|
151
152
|
# @param read_only [Boolean] should it only define the reader?
|
152
153
|
def passdate(*methods, read_only: false)
|
153
154
|
pass_reader(*methods) {|value| to_time(value)}
|
154
|
-
unless read_only
|
155
|
-
pass_writer(*methods) {|value| to_time(value)&.iso8601}
|
156
|
-
end
|
155
|
+
pass_writer(*methods) {|value| to_time(value)&.iso8601} unless read_only
|
157
156
|
self
|
158
157
|
end
|
159
158
|
|
@@ -163,9 +162,7 @@ module Ecoportal
|
|
163
162
|
# @param read_only [Boolean] should it only define the reader?
|
164
163
|
def passboolean(*methods, read_only: false)
|
165
164
|
pass_reader(*methods) {|value| value}
|
166
|
-
unless read_only
|
167
|
-
pass_writer(*methods) {|value| !!value}
|
168
|
-
end
|
165
|
+
pass_writer(*methods) {|value| !!value} unless read_only
|
169
166
|
self
|
170
167
|
end
|
171
168
|
|
@@ -186,7 +183,7 @@ module Ecoportal
|
|
186
183
|
|
187
184
|
define_method method do
|
188
185
|
return instance_variable_get(var) if instance_variable_defined?(var)
|
189
|
-
new_obj = dim_class.new(parent: self, key: method, read_only:
|
186
|
+
new_obj = dim_class.new(parent: self, key: method, read_only: read_only?)
|
190
187
|
variable_set(var, new_obj)
|
191
188
|
end
|
192
189
|
end
|
@@ -197,7 +194,7 @@ module Ecoportal
|
|
197
194
|
# @param key [Symbol] the `key` that embeds it to the underlying `Hash` model
|
198
195
|
# @nullable [Boolean] to specify if this object can be `nil`
|
199
196
|
# @param klass [Class, String] the class of the embedded object
|
200
|
-
def embeds_one(method, key: method, nullable: false
|
197
|
+
def embeds_one(method, klass:, key: method, nullable: false)
|
201
198
|
embed(method, key: key, nullable: nullable, multiple: false, klass: klass)
|
202
199
|
end
|
203
200
|
|
@@ -212,12 +209,13 @@ module Ecoportal
|
|
212
209
|
# @param read_only [Boolean] whether or not should try to **work around** items `klass` missing a `key`
|
213
210
|
# - If set to `true` this is meant only for read purposes (won't be able to successufully insert)
|
214
211
|
def embeds_many(method, key: method, klass: nil, enum_class: nil,
|
215
|
-
order_matters: false, order_key: nil, read_only:
|
212
|
+
order_matters: false, order_key: nil, read_only: read_only?)
|
216
213
|
if enum_class
|
217
214
|
eclass = enum_class
|
218
215
|
elsif klass
|
219
216
|
eclass = new_class("#{method}::#{klass}", inherits: Common::Content::CollectionModel) do |dim_class|
|
220
|
-
|
217
|
+
# NOTE: new_class may resolve the namespace of the class to an already existing class
|
218
|
+
dim_class.klass ||= klass
|
221
219
|
dim_class.order_matters = order_matters
|
222
220
|
dim_class.order_key = order_key
|
223
221
|
dim_class.read_only! if read_only
|
@@ -225,61 +223,69 @@ module Ecoportal
|
|
225
223
|
else
|
226
224
|
raise "You should either specify the 'klass' of the elements or the 'enum_class'"
|
227
225
|
end
|
228
|
-
|
226
|
+
|
227
|
+
embed(
|
228
|
+
method, key: key,
|
229
|
+
multiple: true, klass: eclass,
|
230
|
+
read_only: read_only
|
231
|
+
) do |instance_with_called_method|
|
229
232
|
# keep reference to the original class to resolve the `klass` dependency
|
230
233
|
# See stackoverflow: https://stackoverflow.com/a/73709529/4352306
|
231
234
|
referrer_class = instance_with_called_method.class
|
232
|
-
eclass.klass
|
235
|
+
eclass.klass = {referrer_class => klass} if klass
|
236
|
+
# This helps `resolve_class` to correctly resolve a symbol
|
237
|
+
# by using referrer_class as a base module to resolve it
|
233
238
|
end
|
234
239
|
end
|
235
240
|
|
236
241
|
private
|
237
242
|
|
238
|
-
def embed(
|
243
|
+
def embed(
|
244
|
+
method, klass:, key: method,
|
245
|
+
nullable: false, multiple: false, read_only: read_only?,
|
246
|
+
&embed_block
|
247
|
+
)
|
239
248
|
method = method.to_s.freeze
|
240
249
|
var = instance_variable_name(method).freeze
|
241
|
-
|
250
|
+
obj_k = key.to_s.freeze
|
242
251
|
|
243
252
|
# retrieving method (getter)
|
244
253
|
define_method(method) do
|
245
|
-
|
254
|
+
# set item klass as referrer to klass (to allow resolve symbol)
|
255
|
+
embed_block&.call(self)
|
246
256
|
return instance_variable_get(var) if instance_variable_defined?(var)
|
247
|
-
unless nullable
|
248
|
-
doc[k] ||= multiple ? [] : {}
|
249
|
-
end
|
250
|
-
return variable_set(var, nil) unless doc[k]
|
251
257
|
|
252
|
-
|
253
|
-
|
254
|
-
if multiple && read_only
|
255
|
-
if doc[k].is_a?(Array) && embedded_class < Common::Content::CollectionModel
|
256
|
-
if (item_class = embedded_class.klass) && !item_class.key?
|
257
|
-
item_class.passkey :id
|
258
|
-
doc[k].each_with_index do |item_doc, i|
|
259
|
-
item_doc["id"] = "#{i}" unless item_doc.key?("id")
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
258
|
+
doc[obj_k] ||= (multiple ? [] : {}) unless nullable
|
259
|
+
return variable_set(var, nil) unless doc[obj_k]
|
264
260
|
|
265
|
-
embedded_class
|
266
|
-
|
261
|
+
embedded_class = self.class.resolve_class(klass)
|
262
|
+
setup_items_key(embedded_class, doc[obj_k]) if multiple && read_only
|
263
|
+
|
264
|
+
embedded_class.new(
|
265
|
+
doc[obj_k],
|
266
|
+
parent: self,
|
267
|
+
key: obj_k,
|
268
|
+
read_only: read_only? || read_only
|
269
|
+
).tap do |collection|
|
270
|
+
variable_set(var, collection)
|
267
271
|
end
|
268
272
|
end
|
269
273
|
end
|
270
274
|
|
271
275
|
# The list of keys that will be forced in the model
|
272
276
|
def model_forced_keys
|
273
|
-
@
|
277
|
+
@model_forced_keys ||= {}
|
274
278
|
end
|
275
279
|
end
|
276
280
|
|
277
|
-
inheritable_class_vars :
|
281
|
+
inheritable_class_vars :model_forced_keys, :key, :read_only
|
278
282
|
|
279
|
-
# `_key` refers to the
|
283
|
+
# `_key` refers to the `_parent`'s property that links to this model
|
284
|
+
# @note while `key` refers to the value of theproperty of this model
|
285
|
+
# that is key (identifies an item in a set of elements)
|
280
286
|
attr_reader :_parent, :_key, :_read_only
|
281
287
|
|
282
|
-
def initialize(doc = {}, parent: self, key: nil, read_only: self.class.read_only?)
|
288
|
+
def initialize(doc = {}, parent: self, key: nil, read_only: self.class.read_only?) # rubocop:disable Lint/MissingSuper
|
283
289
|
@_dim_vars = []
|
284
290
|
@_parent = parent || self
|
285
291
|
@_key = key || self
|
@@ -292,10 +298,10 @@ module Ecoportal
|
|
292
298
|
@original_doc = JSON.parse(@doc.to_json)
|
293
299
|
end
|
294
300
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
301
|
+
return unless key_method? && doc && doc.is_a?(Hash)
|
302
|
+
|
303
|
+
self.key = doc[key_method]
|
304
|
+
#puts "\n$(#{self.key}<=>#{self.class})"
|
299
305
|
end
|
300
306
|
|
301
307
|
# @note `read_only` allows for some optimizations, such as storing values
|
@@ -311,15 +317,20 @@ module Ecoportal
|
|
311
317
|
|
312
318
|
# @return [String] the `value` of the `key` method (i.e. `id` value)
|
313
319
|
def key
|
314
|
-
raise NoKeyMethod
|
315
|
-
|
320
|
+
raise NoKeyMethod, "No key_method defined for #{self.class}" unless key_method?
|
321
|
+
|
322
|
+
method(key_method).call
|
316
323
|
end
|
317
324
|
|
318
325
|
# @param [String] the `value` of the `key` method (i.e. `id` value)
|
319
326
|
def key=(value)
|
320
|
-
raise NoKeyMethod
|
321
|
-
|
322
|
-
|
327
|
+
raise NoKeyMethod, "No key_method defined for #{self.class}" unless key_method?
|
328
|
+
|
329
|
+
method("#{key_method}=").call(value)
|
330
|
+
end
|
331
|
+
|
332
|
+
def resolved_doc_key
|
333
|
+
[_doc_key(_key)]
|
323
334
|
end
|
324
335
|
|
325
336
|
# Offers a method for child classes to transform the key,
|
@@ -337,25 +348,22 @@ module Ecoportal
|
|
337
348
|
# @return [nil, Hash] the underlying `Hash` model as is (carrying current changes)
|
338
349
|
def doc
|
339
350
|
return @doc if doc_var?
|
351
|
+
|
340
352
|
raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
|
341
|
-
if is_root?
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
_parent.doc.dig(*[_doc_key(_key)].flatten)
|
347
|
-
end
|
353
|
+
return @doc if is_root?
|
354
|
+
|
355
|
+
# transform parent's `_key` to this object into a
|
356
|
+
# path key that can rerieve from the parents's doc
|
357
|
+
_parent.doc.dig(*resolved_doc_key.flatten)
|
348
358
|
end
|
349
359
|
|
350
360
|
# The `original_doc` holds the model as is now on server-side.
|
351
361
|
# @return [nil, Hash] the underlying `Hash` model as after last `consolidate!` changes
|
352
362
|
def original_doc
|
353
363
|
raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
|
354
|
-
if is_root?
|
355
|
-
|
356
|
-
|
357
|
-
_parent.original_doc.dig(*[_doc_key(_key)].flatten)
|
358
|
-
end
|
364
|
+
return @original_doc if is_root?
|
365
|
+
|
366
|
+
_parent.original_doc.dig(*resolved_doc_key.flatten)
|
359
367
|
end
|
360
368
|
|
361
369
|
def as_json
|
@@ -376,7 +384,7 @@ module Ecoportal
|
|
376
384
|
# @return [Boolean] stating if there are changes
|
377
385
|
def dirty?
|
378
386
|
au = as_update
|
379
|
-
!((au == {}) ||
|
387
|
+
!((au == {}) || au.nil?)
|
380
388
|
end
|
381
389
|
|
382
390
|
# It makes `original_doc` to be like `doc`
|
@@ -396,7 +404,7 @@ module Ecoportal
|
|
396
404
|
if key
|
397
405
|
keys = [key].flatten.compact
|
398
406
|
odoc = original_doc.dig(*keys)
|
399
|
-
odoc
|
407
|
+
odoc &&= JSON.parse(odoc.to_json)
|
400
408
|
dig_set(doc, keys, odoc)
|
401
409
|
else
|
402
410
|
replace_doc(JSON.parse(original_doc.to_json))
|
@@ -410,13 +418,11 @@ module Ecoportal
|
|
410
418
|
|
411
419
|
def replace_doc(new_doc)
|
412
420
|
raise UnlinkedModel.new(from: "#{self.class}#replace_doc", key: _key) unless linked?
|
413
|
-
if is_root?
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
#variables_remove!
|
419
|
-
end
|
421
|
+
return (@doc = new_doc) if is_root?
|
422
|
+
|
423
|
+
dig_set(_parent.doc, resolved_doc_key.flatten, new_doc)
|
424
|
+
_parent.variable_remove!(_key) unless new_doc
|
425
|
+
#variables_remove!
|
420
426
|
end
|
421
427
|
|
422
428
|
protected
|
@@ -438,11 +444,9 @@ module Ecoportal
|
|
438
444
|
|
439
445
|
def replace_original_doc(new_doc)
|
440
446
|
raise UnlinkedModel.new(from: "#{self.class}#replace_original_doc", key: _key) unless linked?
|
441
|
-
if is_root?
|
442
|
-
|
443
|
-
|
444
|
-
dig_set(_parent.original_doc, [_doc_key(_key)].flatten, new_doc)
|
445
|
-
end
|
447
|
+
return (@original_doc = new_doc) if is_root?
|
448
|
+
|
449
|
+
dig_set(_parent.original_doc, resolved_doc_key.flatten, new_doc)
|
446
450
|
end
|
447
451
|
|
448
452
|
# Helper to track down persistent variables
|
@@ -455,16 +459,16 @@ module Ecoportal
|
|
455
459
|
# Helper to remove tracked down instance variables
|
456
460
|
def variable_remove!(key)
|
457
461
|
var = instance_variable_name(key)
|
458
|
-
unless
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
+
return unless @_dim_vars.include?(var)
|
463
|
+
|
464
|
+
@_dim_vars.delete(var)
|
465
|
+
remove_instance_variable(var)
|
462
466
|
end
|
463
467
|
|
464
468
|
# Removes all the persistent variables
|
465
469
|
def variables_remove!
|
466
470
|
#puts "going to remove vars: #{@_dim_vars} on #{self.class} (parent: #{identify_parent(self._parent)})"
|
467
|
-
@_dim_vars.dup.map {|
|
471
|
+
@_dim_vars.dup.map {|var| variable_remove!(var)}
|
468
472
|
end
|
469
473
|
|
470
474
|
private
|
@@ -502,6 +506,20 @@ module Ecoportal
|
|
502
506
|
self.class.key
|
503
507
|
end
|
504
508
|
|
509
|
+
# It allows to work-around missing item_key
|
510
|
+
def setup_items_key(embedded_class, obj_doc)
|
511
|
+
# only if is going to be a collection
|
512
|
+
return unless obj_doc.is_a?(Array) && embedded_class < Common::Content::CollectionModel
|
513
|
+
return unless (item_class = embedded_class.klass)
|
514
|
+
# if already has key don't need to work around
|
515
|
+
return if item_class&.key
|
516
|
+
|
517
|
+
# apply work around
|
518
|
+
item_class.passkey :id
|
519
|
+
obj_doc.each_with_index do |item_doc, idx|
|
520
|
+
item_doc["id"] = idx.to_s unless item_doc.key?("id")
|
521
|
+
end
|
522
|
+
end
|
505
523
|
end
|
506
524
|
end
|
507
525
|
end
|
@@ -7,25 +7,26 @@ module Ecoportal
|
|
7
7
|
|
8
8
|
attr_reader :response, :result
|
9
9
|
|
10
|
-
def initialize(response, klass, key: nil)
|
10
|
+
def initialize(response, klass, key: nil) # rubocop:disable Lint/MissingSuper
|
11
11
|
@response = response
|
12
12
|
@klass = klass
|
13
13
|
@key = key
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
else
|
22
|
-
@klass.new(data)
|
15
|
+
return unless @response.success?
|
16
|
+
|
17
|
+
@result =
|
18
|
+
if data.is_a?(Array)
|
19
|
+
data.map do |doc|
|
20
|
+
@klass.new(doc)
|
23
21
|
end
|
24
|
-
|
22
|
+
else
|
23
|
+
@klass.new(data)
|
24
|
+
end
|
25
25
|
end
|
26
26
|
|
27
27
|
def data
|
28
28
|
return @data if instance_variable_defined?(:@data)
|
29
|
+
|
29
30
|
@data = (response.body || {})["data"]
|
30
31
|
@data = @data[@key] if @key && @data
|
31
32
|
@data
|
@@ -34,7 +35,6 @@ module Ecoportal
|
|
34
35
|
def body
|
35
36
|
data.to_s
|
36
37
|
end
|
37
|
-
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -25,8 +25,8 @@ module Ecoportal
|
|
25
25
|
ref_ids.each do |ref_id|
|
26
26
|
next if reference_ids.include?(ref_id)
|
27
27
|
refs.push({
|
28
|
-
"id"
|
29
|
-
"weight"
|
28
|
+
"id" => ref_id,
|
29
|
+
"weight" => 0,
|
30
30
|
"patch_ver" => 0
|
31
31
|
})
|
32
32
|
end
|
@@ -39,9 +39,13 @@ module Ecoportal
|
|
39
39
|
|
40
40
|
def delete(*ref_ids)
|
41
41
|
ref_ids.each do |ref_id|
|
42
|
-
|
43
|
-
|
42
|
+
doc_ref = doc["references"].find do |df|
|
43
|
+
df["id"] == ref_id
|
44
44
|
end
|
45
|
+
|
46
|
+
next unless doc_ref
|
47
|
+
|
48
|
+
doc["references"].delete(doc_ref)
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
@@ -62,21 +66,21 @@ module Ecoportal
|
|
62
66
|
self.display_fields = true
|
63
67
|
self.display_fields_in_lookup = true
|
64
68
|
when Hash
|
65
|
-
supported = [
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
supported = %i[create attach metadata]
|
70
|
+
rest = hash_except(cnf.dup, *supported)
|
71
|
+
|
72
|
+
unused.push(rest) unless rest.empty?
|
73
|
+
|
74
|
+
self.hide_create = !cnf[:create] if cnf.key?(:create)
|
75
|
+
self.hide_attach = !cnf[:attach] if cnf.key?(:attach)
|
76
|
+
self.hide_metadata = !cnf[:metadata] if cnf.key?(:metadata)
|
72
77
|
else
|
73
78
|
unused.push(cnf)
|
74
79
|
end
|
75
|
-
end.
|
80
|
+
end.then do |unused|
|
76
81
|
super(*unused)
|
77
82
|
end
|
78
83
|
end
|
79
|
-
|
80
84
|
end
|
81
85
|
end
|
82
86
|
end
|