ecoportal-api-v2 1.1.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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