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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.markdownlint.json +4 -0
  3. data/.rubocop.yml +54 -15
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +485 -373
  6. data/ecoportal-api-v2.gemspec +13 -12
  7. data/lib/ecoportal/api/common/concerns/benchmarkable.rb +47 -34
  8. data/lib/ecoportal/api/common/concerns/threadable.rb +41 -0
  9. data/lib/ecoportal/api/common/concerns.rb +1 -0
  10. data/lib/ecoportal/api/common/content/array_model.rb +85 -79
  11. data/lib/ecoportal/api/common/content/class_helpers.rb +34 -31
  12. data/lib/ecoportal/api/common/content/collection_model.rb +77 -65
  13. data/lib/ecoportal/api/common/content/double_model.rb +105 -87
  14. data/lib/ecoportal/api/common/content/wrapped_response.rb +11 -11
  15. data/lib/ecoportal/api/v2/page/component/reference_field.rb +17 -13
  16. data/lib/ecoportal/api/v2/page/component.rb +67 -68
  17. data/lib/ecoportal/api/v2/page/components.rb +9 -9
  18. data/lib/ecoportal/api/v2/page/force.rb +6 -7
  19. data/lib/ecoportal/api/v2/page/stages.rb +5 -6
  20. data/lib/ecoportal/api/v2/page.rb +35 -33
  21. data/lib/ecoportal/api/v2/pages/page_stage.rb +22 -20
  22. data/lib/ecoportal/api/v2/pages.rb +18 -14
  23. data/lib/ecoportal/api/v2/people.rb +2 -3
  24. data/lib/ecoportal/api/v2/registers.rb +28 -13
  25. data/lib/ecoportal/api/v2/s3/data.rb +27 -0
  26. data/lib/ecoportal/api/v2/s3/files/batch_upload.rb +110 -0
  27. data/lib/ecoportal/api/v2/s3/files/poll.rb +82 -0
  28. data/lib/ecoportal/api/v2/s3/files/poll_status.rb +52 -0
  29. data/lib/ecoportal/api/v2/s3/files.rb +132 -0
  30. data/lib/ecoportal/api/v2/s3/upload.rb +154 -0
  31. data/lib/ecoportal/api/v2/s3.rb +66 -0
  32. data/lib/ecoportal/api/v2.rb +10 -3
  33. data/lib/ecoportal/api/v2_version.rb +1 -1
  34. 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 (msg = "Something went wrong when linking the document.", from: nil, key: nil)
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: , read_only: false)
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 && doc.is_a?(Hash)
130
- return if model_forced_keys.empty?
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 *methods
143
- pass_writer *methods unless read_only
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: self.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, klass:)
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: self.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
- dim_class.klass = klass
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
- embed(method, key: key, multiple: true, klass: eclass, read_only: read_only) do |instance_with_called_method|
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 = {referrer_class => klass} if 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(method, key: method, nullable: false, multiple: false, klass:, read_only: self.read_only?, &block)
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
- k = key.to_s.freeze
250
+ obj_k = key.to_s.freeze
242
251
 
243
252
  # retrieving method (getter)
244
253
  define_method(method) do
245
- yield(self) if block_given?
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
- embedded_class = self.class.resolve_class(klass)
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.new(doc[k], parent: self, key: k, read_only: self.read_only? || read_only).tap do |obj|
266
- variable_set(var, obj)
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
- @forced_model_keys ||= {}
277
+ @model_forced_keys ||= {}
274
278
  end
275
279
  end
276
280
 
277
- inheritable_class_vars :forced_model_keys, :key, :read_only
281
+ inheritable_class_vars :model_forced_keys, :key, :read_only
278
282
 
279
- # `_key` refers to the parent's property that links to this model
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
- if key_method? && doc && doc.is_a?(Hash)
296
- self.key = doc[key_method]
297
- #puts "\n$(#{self.key}<=>#{self.class})"
298
- end
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.new "No key_method defined for #{self.class}" unless key_method?
315
- self.method(key_method).call
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.new "No key_method defined for #{self.class}" unless key_method?
321
- method = "#{key_method}="
322
- self.method(method).call(value)
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
- @doc
343
- else
344
- # transform parent's `_key` to this object into a
345
- # path key that can rerieve from the parents's doc
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
- @original_doc
356
- else
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 == {}) || (au == nil))
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 = odoc && JSON.parse(odoc.to_json)
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
- @doc = new_doc
415
- else
416
- dig_set(_parent.doc, [_doc_key(_key)].flatten, new_doc)
417
- _parent.variable_remove!(_key) unless new_doc
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
- @original_doc = new_doc
443
- else
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 !@_dim_vars.include?(var)
459
- @_dim_vars.delete(var)
460
- remove_instance_variable(var)
461
- end
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 {|k| variable_remove!(k)}
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
- if @response.success?
16
- @result =
17
- if data.is_a?(Array)
18
- data.map do |doc|
19
- @klass.new(doc)
20
- end
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
- end
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" => ref_id,
29
- "weight" => 0,
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
- if doc_ref = doc["references"].find {|doc_ref| doc_ref["id"] == ref_id}
43
- doc["references"].delete(doc_ref)
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 = [:create, :attach, :metadata]
66
- unless (rest = hash_except(cnf.dup, *supported)).empty?
67
- unused.push(rest)
68
- end
69
- if cnf.key?(:create) then self.hide_create = !cnf[:create] end
70
- if cnf.key?(:attach) then self.hide_attach = !cnf[:attach] end
71
- if cnf.key?(:metadata) then self.hide_metadata = !cnf[:metadata] end
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.yield_self do |unused|
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