ecoportal-api-v2 0.8.29 → 0.8.31

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca7591fd58fc849aefad7508d07e7902d5016ccaa19642dc7f8bb94b2ad445ca
4
- data.tar.gz: c0a76091ed2702c29973d7295654f447425bf8e819e9684913bc71132eeccc9a
3
+ metadata.gz: f7fdd84d3767ffc6a9a5adfe976ad4a485754c076475d01da46877aa38e01d65
4
+ data.tar.gz: 8c775abd99edba549b7b8abe049ac06c631005671b972a9340795857b378d39a
5
5
  SHA512:
6
- metadata.gz: aab5c8003ceb2d0bfc71169f9a2bcda26cb37253cad9a6ec277309c4d2c6bb1a3e4a4fc8717b69286a81b4b6cf43b8e3c969267171f5d4b529fefbe1c85e2da8
7
- data.tar.gz: 96d45a7aba715ea08eb0b96f6920f2dae25a8f27383f460e4883bf79233a9efb2a26bea10025d7b8a7931b3450c9650e1518da52044c90e03f8edfcbba8f9058
6
+ metadata.gz: a4cc041705a2ac1e2ebe6eaaf7cc30fe79b780a1b5dc397bb1526fe0112df0a050d07452100e0174110e5cf30271ef1b3ddbb4f8b866c66824755c6f6bd287ad
7
+ data.tar.gz: 1bdb9cd3ff3cf0b64f282f4be9ec372c276c8deee7b47b8a142eab20069c2ef072966b87a1a1c9047e01a54895354bd7e2a9a404215eabf6bbc689641297b8d4
data/CHANGELOG.md CHANGED
@@ -1,7 +1,50 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [0.8.29] - 2022-06-xx
4
+ ## [0.8.31] - 2022-08-xx
5
+
6
+ ### Added
7
+ - `Ecoportal::API:V2::Common::Content::ClassHelpers.uid` to generate a random uid
8
+
9
+ ### Changed
10
+ - added **inheritable attributes** to
11
+ - `Ecoportal::API:V2::Common::Content::ArrayModel` (:order_matteres, :uniq)
12
+ - `Ecoportal::API:V2::Common::Content::CollectionModel` (klass, :order_matters, :order_key, :items_key, :new_item)
13
+ - `Ecoportal::API:V2::Common::Content::DoubleModel` (:key)
14
+ - moved `SecureRandom` dependency to `Ecoportal::API:V2::Common::Content::ClassHelpers`
15
+
16
+ ### Fixed
17
+ - `Ecoportal::API::V2::Page::Component::SelectionOption#numeric!` fix conversion
18
+ - `Ecoportal::API:V2::Common::Content::ClassHelpers`, `new_class`
19
+ - **Added** parameter `namespace` (default: the class `inherits` parameter): it's purpose is to define the namespace where the new class will sit
20
+ - **Fixed** also the namespace where the new class constant will sit (it was using always the source class `self`)
21
+ - **Improved** `name` parameter to have a default value that is randomized. This is useful when we just want to do something like `SomeClass.new_class`, where the name of the new class doesn't really matter.
22
+ - **Fixed** lost reference of class resolvers when using `embeds_many`
23
+ - `Ecoportal::API:V2::Common::Content::ClassHelpers`, `resolve_class` accepts now a `Hash` with `key` referrer class, and `value` any of the previously accepted ones (i.e. `Symbol` or `String`). To this purpose, `source_class` parameter has been added.
24
+ - This has been natively wrapped in `Ecoportal::API:V2::Common::Content::DoubleModel.embeds_many`, as it naturally shares the `class_resolver` with a third party class that loses the reference.
25
+
26
+ ## [0.8.30] - 2022-07-11
27
+
28
+ ### Added
29
+ - `Ecoportal::API::V2::Page::MoultCounter`
30
+ - Available on `Ecoportal::API::V2::Pages::PageStage`
31
+ - `Ecoportal::API::V2::Page::Component#Law` added support for `LawField` content
32
+ - where `Ecoportal::API::V2::Page::Component#LawField` has many of
33
+ - `Ecoportal::API::V2::Component` added parameter `any_length:` for
34
+ - `#ref` and `#indexable_label` (aiming to enhance data exportability)
35
+
36
+ ### Changed
37
+ - Reviewed `to_s` method on multiple components, to ensure smooth export
38
+
39
+ ### Fixed
40
+ - `Ecoportal::API::V2::Pages::PageStage#uid`
41
+ - Should check if `mould_conter` exists
42
+ - Should return `id` if `mould_counter` does not exist
43
+ - **Exports**
44
+ - `Ecoportal::API::V2::Pages::Component::PeopleField#to_s`: fix type conversion
45
+ - `Ecoportal::API::V2::Pages::Component::DateField#to_s`: make time to work to the local timezone where the client script runs
46
+
47
+ ## [0.8.29] - 2022-07-07
5
48
 
6
49
  ### Added
7
50
  - `Ecoportal::API::V2::Page::Component::ActionField#permitted_person_schema_ids`
@@ -6,7 +6,7 @@ module Ecoportal
6
6
  # @note
7
7
  # - Its purpose is to handle an Array of basic objects (i.e. `Date`, `String`, `Number`)
8
8
  class ArrayModel < Content::DoubleModel
9
- class TypeMismatchedComparison < Exception
9
+ class TypeMismatchedComparison < StandardError
10
10
  def initialize (this: nil, that: msg = "Trying to compare objects with different behavior.")
11
11
  if this
12
12
  msg += " From object with 'order_matters: #{this.order_matters?}' and 'uniq: #{this.uniq?}'."
@@ -30,9 +30,10 @@ module Ecoportal
30
30
  raise "To use this comparison both objects should be `ArrayModel`" unless a.is_a?(ArrayModel) && b.is_a?(ArrayModel)
31
31
  (a.order_matters? == b.order_matters?) && (a.uniq? == b.uniq?)
32
32
  end
33
-
34
33
  end
35
34
 
35
+ inheritable_class_vars :order_matteres, :uniq
36
+
36
37
  def initialize(doc = [], parent: self, key: nil)
37
38
  super(doc, parent: parent, key: key)
38
39
  end
@@ -1,3 +1,4 @@
1
+ require 'securerandom'
1
2
  module Ecoportal
2
3
  module API
3
4
  module Common
@@ -10,9 +11,10 @@ module Ecoportal
10
11
  # @note it caches the resolved `klass`es
11
12
  # @raise [Exception] when could not resolve if `exception` is `true`
12
13
  # @param klass [Class, String, Symbol] the class to resolve
14
+ # @param source_class [Class] when the reference to `klass` belongs to a different inheritance chain.
13
15
  # @param exception [Boolean] if it should raise exception when could not resolve
14
16
  # @return [Class] the `Class` constant
15
- def resolve_class(klass, exception: true)
17
+ def resolve_class(klass, source_class: self, exception: true)
16
18
  @resolved ||= {}
17
19
  @resolved[klass] ||=
18
20
  case klass
@@ -25,18 +27,24 @@ module Ecoportal
25
27
  raise if exception
26
28
  end
27
29
  when Symbol
28
- resolve_class(self.send(klass))
30
+ source_class.resolve_class(source_class.send(klass))
31
+ when Hash
32
+ referrer, referred = klass.first
33
+ resolve_class(referred, source_class: referrer, exception: exception)
29
34
  else
30
35
  raise "Unknown class: #{klass}" if exception
31
36
  end
32
37
  end
33
38
 
34
39
  # Helper to normalize `key` into a correct `ruby` **constant name**
40
+ # @note it removes namespace syntax `::`
35
41
  # @param key [String, Symbol] to be normalized
36
42
  # @return [String] a correct constant name
37
43
  def to_constant(key)
38
- str_name = key.to_s.strip.split(/[\-\_ ]/i).compact.map do |str|
39
- str.slice(0).upcase + str.slice(1..-1).downcase
44
+ str_name = key.to_s.strip.split(/::/).compact.map do |str|
45
+ str.slice(0).upcase + str.slice(1..-1)
46
+ end.join("").split(/[\-\_ :]+/i).compact.map do |str|
47
+ str.slice(0).upcase + str.slice(1..-1)
40
48
  end.join("")
41
49
  end
42
50
 
@@ -49,20 +57,27 @@ module Ecoportal
49
57
  str
50
58
  end
51
59
 
60
+ # Generates random ids in hexadecimal to use in class name generation.
61
+ # @param len [Integeter] length of the `uid`
62
+ # @return [String] a random unique id of length `len`
63
+ def uid(len = 8);
64
+ SecureRandom.hex(len/2)
65
+ end
66
+
52
67
  # If the class for `name` exists, it returns it. Otherwise it generates it.
53
68
  # @param name [String, Symbol] the name of the new class
54
69
  # @param inherits [Class] the parent class to _inherit_ from
70
+ # @param namespace [Class, String] an existing `constant` (class or module) the new class will be namespaced on
55
71
  # @yield [child_class] configure the new class
56
72
  # @yieldparam child_class [Class] the new class
57
73
  # @return [Class] the new generated class
58
- def new_class(name, inherits:)
74
+ def new_class(name = "Child#{uid}", inherits: self, namespace: inherits)
59
75
  name = name.to_sym.freeze
60
76
  class_name = to_constant(name)
61
- full_class_name = "#{inherits}::#{class_name}"
62
77
 
63
- unless target_class = resolve_class(full_class_name, exception: false)
78
+ unless target_class = resolve_class("#{namespace}::#{class_name}", exception: false)
64
79
  target_class = Class.new(inherits)
65
- self.const_set class_name, target_class
80
+ Kernel.const_get(namespace.to_s).const_set class_name, target_class
66
81
  end
67
82
 
68
83
  target_class.tap do |klass|
@@ -138,7 +153,6 @@ module Ecoportal
138
153
  subclass.instance_variable_set(instance_var, value.freeze)
139
154
  end
140
155
  end
141
-
142
156
  end
143
157
  end
144
158
  end
@@ -82,11 +82,12 @@ module Ecoportal
82
82
  klass.uniq = uniq
83
83
  end
84
84
  end
85
-
86
85
  end
87
86
 
88
87
  include Enumerable
89
88
 
89
+ inheritable_class_vars :klass, :order_matters, :order_key, :items_key, :new_item
90
+
90
91
  def initialize(ini_doc = [], parent: self, key: nil)
91
92
  unless self.class.klass?
92
93
  raise "Undefined base 'klass' or 'new_item' callback for #{self.class}"
@@ -1,5 +1,3 @@
1
- require 'securerandom'
2
-
3
1
  module Ecoportal
4
2
  module API
5
3
  module Common
@@ -12,7 +10,7 @@ module Ecoportal
12
10
  extend Common::Content::ClassHelpers
13
11
  include Common::Content::ModelHelpers
14
12
 
15
- class UnlinkedModel < Exception
13
+ class UnlinkedModel < StandardError
16
14
  def initialize (msg = "Something went wrong when linking the document.", from: nil, key: nil)
17
15
  msg += " From: #{from}." if from
18
16
  msg += " key: #{key}." if key
@@ -31,8 +29,8 @@ module Ecoportal
31
29
  @key = value.to_s.freeze
32
30
  end
33
31
 
34
- def new_uuid(length: 12)
35
- SecureRandom.hex(length)
32
+ def new_uuid(length: 24)
33
+ uid(length)
36
34
  end
37
35
 
38
36
  # Same as `attr_reader` but links to a subjacent `Hash` model property
@@ -208,18 +206,24 @@ module Ecoportal
208
206
  else
209
207
  raise "You should either specify the 'klass' of the elements or the 'enum_class'"
210
208
  end
211
- embed(method, key: key, multiple: true, klass: eclass)
209
+ embed(method, key: key, multiple: true, klass: eclass) do |instance_with_called_method|
210
+ # keep reference to the original class to resolve the `klass` dependency
211
+ # See stackoverflow: https://stackoverflow.com/a/73709529/4352306
212
+ referrer_class = instance_with_called_method.class
213
+ eclass.klass = {referrer_class => klass} if klass
214
+ end
212
215
  end
213
216
 
214
217
  private
215
218
 
216
- def embed(method, key: method, nullable: false, multiple: false, klass:)
219
+ def embed(method, key: method, nullable: false, multiple: false, klass:, &block)
217
220
  method = method.to_s.freeze
218
221
  var = instance_variable_name(method).freeze
219
222
  k = key.to_s.freeze
220
223
 
221
224
  # retrieving method (getter)
222
225
  define_method(method) do
226
+ yield(self) if block_given?
223
227
  return instance_variable_get(var) if instance_variable_defined?(var)
224
228
  unless nullable
225
229
  doc[k] ||= multiple ? [] : {}
@@ -239,7 +243,7 @@ module Ecoportal
239
243
 
240
244
  end
241
245
 
242
- inheritable_class_vars :forced_model_keys
246
+ inheritable_class_vars :forced_model_keys, :key
243
247
 
244
248
  attr_reader :_parent, :_key
245
249
 
@@ -7,16 +7,16 @@ module Ecoportal
7
7
  module StringDigest
8
8
  MAX_HASH_LABEL = 64
9
9
 
10
- def indexable_label(str)
10
+ def indexable_label(str, any_length: false)
11
11
  return nil unless str
12
12
  lbl = str.downcase.gsub(/[^A-Za-z]+/,"-").slice(0, MAX_HASH_LABEL)
13
- return nil unless lbl.length >= 3
13
+ return nil if (lbl.length < 3) && !any_length
14
14
  lbl
15
15
  end
16
16
 
17
17
  # Calculates the Hash of the field based on label
18
- def hash_label(str)
19
- return nil unless lbl = indexable_label(str)
18
+ def hash_label(str, any_length: false)
19
+ return nil unless lbl = indexable_label(str, any_length: any_length)
20
20
  "z" + Digest::MD5.hexdigest(lbl).slice(0, 8);
21
21
  end
22
22
 
@@ -41,7 +41,6 @@ module Ecoportal
41
41
  assignee = assigned_person_member["name"] || assigned_person_member["email"]
42
42
  "#{name}, #{created_at.to_s}, #{stat}, #{assignee}"
43
43
  end
44
-
45
44
  end
46
45
  end
47
46
  end
@@ -35,7 +35,8 @@ module Ecoportal
35
35
  end
36
36
 
37
37
  def to_s
38
- value.to_s
38
+ return nil unless value
39
+ to_local_time(value).strftime(ISO8601)
39
40
  end
40
41
 
41
42
  # Quick config helper
@@ -78,6 +79,23 @@ module Ecoportal
78
79
 
79
80
  private
80
81
 
82
+ def to_local_time(value)
83
+ case value
84
+ when DateTime
85
+ value.new_offset(local_offset).to_time
86
+ when String
87
+ to_local_time(Time.parse(value))
88
+ when Date
89
+ to_local_time(value.to_time)
90
+ when Time
91
+ to_local_time(value.to_datetime)
92
+ end
93
+ end
94
+
95
+ def local_offset
96
+ @local_offset ||= DateTime.now.offset
97
+ end
98
+
81
99
  def configure_reminder(value)
82
100
  case value
83
101
  when :never, NilClass
@@ -22,7 +22,7 @@ module Ecoportal
22
22
  passdate :file_update_at, read_only: true
23
23
 
24
24
  def to_s
25
- file_container_id
25
+ [label, file_container_id].join(" => ")
26
26
  end
27
27
  end
28
28
  end
@@ -0,0 +1,32 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class Component
6
+ class Law < Common::Content::DoubleModel
7
+
8
+ class << self
9
+ def new_doc
10
+ {
11
+ "id" => new_uuid,
12
+ "weight" => 999
13
+ }
14
+ end
15
+ end
16
+
17
+ passkey :id
18
+ passforced :patch_ver, default: 1
19
+ passthrough :title, :weight
20
+ passthrough :content, :product
21
+ passthrough :legislation, :category, :topic
22
+ passdate :updated_at, read_only: true
23
+
24
+ def to_s
25
+ [legislation, title, category, topic].join(" <:> ")
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -4,9 +4,22 @@ module Ecoportal
4
4
  class Page
5
5
  class Component
6
6
  class LawField < Page::Component
7
+ embeds_many :snippets, klass: "Ecoportal::API::V2::Page::Component::Law", order_key: :weight
8
+
9
+ def ordered_snippets
10
+ snippets.sort_by.with_index do |snippet, index|
11
+ [snippet.weight, index]
12
+ end
13
+ end
14
+
15
+ def to_s(delimiter: "\n")
16
+ ordered_snippets.map(&:to_s).join(delimiter)
17
+ end
7
18
  end
8
19
  end
9
20
  end
10
21
  end
11
22
  end
12
23
  end
24
+
25
+ require 'ecoportal/api/v2/page/component/law'
@@ -5,6 +5,10 @@ module Ecoportal
5
5
  class Component
6
6
  class NumberField < Page::Component
7
7
  passthrough :value
8
+
9
+ def to_s
10
+ value
11
+ end
8
12
  end
9
13
  end
10
14
  end
@@ -41,7 +41,7 @@ module Ecoportal
41
41
  end
42
42
 
43
43
  def to_s(delimiter: "\n")
44
- people_ids.join(delimiter)
44
+ people_ids.to_a.join(delimiter)
45
45
  end
46
46
 
47
47
  # Quick config helper
@@ -130,9 +130,9 @@ module Ecoportal
130
130
  end
131
131
  end
132
132
 
133
- def to_s(name: true, delimiter: "\n")
133
+ def to_s(value: true, delimiter: "\n")
134
134
  [selected].flatten.compact.map do |opt|
135
- name ? opt.name : opt.value
135
+ value ? opt.value : opt.name
136
136
  end.join(delimiter)
137
137
  end
138
138
 
@@ -30,7 +30,7 @@ module Ecoportal
30
30
 
31
31
  private
32
32
 
33
- def to_i
33
+ def to_i(value)
34
34
  Float(value).to_i
35
35
  end
36
36
 
@@ -18,6 +18,9 @@ module Ecoportal
18
18
  passdate :signature_updated_at, read_only: true
19
19
  passthrough :signature_content, :color
20
20
 
21
+ def to_s
22
+ [signed_by_name, signature_updated_at].join(" at ")
23
+ end
21
24
  end
22
25
  end
23
26
  end
@@ -101,8 +101,8 @@ module Ecoportal
101
101
  refs.first
102
102
  end
103
103
 
104
- def ref
105
- if digest = self.class.hash_label(label)
104
+ def ref(any_length: false)
105
+ if digest = self.class.hash_label(label, any_length: any_length)
106
106
  [type, digest].join(".")
107
107
  end
108
108
  end
@@ -144,8 +144,8 @@ module Ecoportal
144
144
  forces.count > 0
145
145
  end
146
146
 
147
- def indexable_label
148
- self.class.indexable_label(label)
147
+ def indexable_label(any_length: false)
148
+ self.class.indexable_label(label, any_length: any_length)
149
149
  end
150
150
 
151
151
  # Quick config helper
@@ -0,0 +1,32 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class MouldCounter < Common::Content::DoubleModel
6
+ UID_REGEX = /^(?<prefix>.*?)(?<counter>\d+)(?<postfix>.*)$/i
7
+ STR_LEN = 5
8
+ BASE_NUM_STR = "0" * STR_LEN
9
+
10
+ passthrough :prefix, :postfix
11
+ passthrough :counter
12
+ passthrough :render
13
+
14
+ def set(uid)
15
+ return nil unless uid.is_a?(String)
16
+ return nil unless match = uid.match(UID_REGEX)
17
+ self.counter = count_str(match[:counter])
18
+ self.prefix = match[:prefix]
19
+ self.postfix = match[:postfix]
20
+ self.render = "#{match[:prefix]}#{counter}#{match[:postfix]}"
21
+ end
22
+
23
+ private
24
+
25
+ def count_str(num)
26
+ (BASE_NUM_STR + num.to_s)[-5..-1]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -102,6 +102,7 @@ module Ecoportal
102
102
  end
103
103
  end
104
104
 
105
+ require 'ecoportal/api/v2/page/mould_counter'
105
106
  require 'ecoportal/api/v2/page/permission_flags'
106
107
  require 'ecoportal/api/v2/page/permit'
107
108
  require 'ecoportal/api/v2/page/component'
@@ -3,20 +3,28 @@ module Ecoportal
3
3
  class V2
4
4
  class Pages
5
5
  class PageStage < V2::Page
6
- passthrough :mould_counter, :archive
6
+ passthrough :archive
7
+ embeds_one :mould_counter, klass: "Ecoportal::API::V2::Page::MouldCounter"
7
8
  passthrough :task_priority, :state, :status
8
9
  passthrough :votes_enabled, :upvotes, :downvotes
9
10
 
10
11
  #embeds_many :permits, klass: "Ecoportal::API::V2::Page::Permit"
11
12
  passarray :force_errors, :subtags, order_matters: false
12
13
 
14
+ # @return [Boolean] whether or not this entry has mould counter
15
+ def mould_counter?
16
+ !!doc["moult_counter"]
17
+ end
18
+
13
19
  # @return [String] unique id
14
20
  def uid
15
- if counter = mould_counter
21
+ if mould_counter? && counter = mould_counter
16
22
  counter.render
23
+ else
24
+ id
17
25
  end
18
26
  end
19
-
27
+
20
28
  # @return [String] `id` of the stage we got the data of.
21
29
  def current_stage_id
22
30
  doc.dig("active_stage", "id") || doc["current_stage_id"]
@@ -52,7 +60,6 @@ module Ecoportal
52
60
  end
53
61
  msg.empty?? true : msg
54
62
  end
55
-
56
63
  end
57
64
  end
58
65
  end
@@ -1,5 +1,5 @@
1
1
  module Ecoportal
2
2
  module API
3
- GEM2_VERSION = "0.8.29"
3
+ GEM2_VERSION = "0.8.31"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecoportal-api-v2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.29
4
+ version: 0.8.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-07 00:00:00.000000000 Z
11
+ date: 2022-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -206,6 +206,7 @@ files:
206
206
  - lib/ecoportal/api/v2/page/component/geo_field.rb
207
207
  - lib/ecoportal/api/v2/page/component/image.rb
208
208
  - lib/ecoportal/api/v2/page/component/images_field.rb
209
+ - lib/ecoportal/api/v2/page/component/law.rb
209
210
  - lib/ecoportal/api/v2/page/component/law_field.rb
210
211
  - lib/ecoportal/api/v2/page/component/number_field.rb
211
212
  - lib/ecoportal/api/v2/page/component/people_field.rb
@@ -222,6 +223,7 @@ files:
222
223
  - lib/ecoportal/api/v2/page/force/binding.rb
223
224
  - lib/ecoportal/api/v2/page/force/bindings.rb
224
225
  - lib/ecoportal/api/v2/page/forces.rb
226
+ - lib/ecoportal/api/v2/page/mould_counter.rb
225
227
  - lib/ecoportal/api/v2/page/permission_flags.rb
226
228
  - lib/ecoportal/api/v2/page/permit.rb
227
229
  - lib/ecoportal/api/v2/page/section.rb