ecoportal-api-v2 0.8.13 → 0.8.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 146b0998371f28683143b8a95ae1b68e11f8f079698502bede31c8e29369fc97
4
- data.tar.gz: 4ce0f3dd75e4e1d822d4540fa0ff1e3e18a7c7dca1c54d7030bdb475adc21a93
3
+ metadata.gz: b34fee0d135768fa89e14303a3f7d334eb51c961c29759d471d3151bf7f4c973
4
+ data.tar.gz: 32ed7cdfb74f7278d938a98ff730edd545391a1304fb369864400a1cccebaf62
5
5
  SHA512:
6
- metadata.gz: 21605169ab88cb159ee32a2f6f36e3100b183a03a7f9c895b33631934811bb9e3f16c6bc6101ddfac562854f8762f545a743b68c55d662c97be54ff35fc5b9e8
7
- data.tar.gz: d2a66296e4b9194667983ba5c37c646fd6a12e037138870aa2771c743fc75dbf9b2ee91d07af7b1e4b501ad1afd846b427a8b92f5dc99ee4551200cc742dcd20
6
+ metadata.gz: 3cfce53a0eeff5e7bd1d5256638a53e4537118f6b77e36c36cac3ceb89d9fb16b8765c583ba771f970ba888f4eac2081ecda3f94d592822d90724c51999a9d4f
7
+ data.tar.gz: b59bfa83a0c4ea3ab05a02ff305208d26fd8986d8ef995701fcb1ca730571d44d1198a3e03a51f1842d51d3232c40af1317ce3f73edd04f18864319604b01a47
data/CHANGELOG.md CHANGED
@@ -1,12 +1,60 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [0.8.13] - 2021-08-xx
4
+ ## [0.8.17] - 2021-09-29
5
5
 
6
6
  ### Added
7
7
  ### Changed
8
8
  ### Fixed
9
- - `Ecoportal::API::V2::Stage::Sections`
9
+ - Typo in `Section#attached?`
10
+
11
+ ## [0.8.15] - 2021-09-29
12
+
13
+ ### Fixed
14
+ - Typo in `Section#component?`
15
+
16
+ ## [0.8.14] - 2021-09-28
17
+
18
+ ### Added
19
+ - `Ecoportal::API::Common::Content::CollectionModel`
20
+ - `#_doc_pos` for clarity
21
+ - `#include?` to check if an element is present in the collection
22
+ - `Ecoportal::API::V2::Page::Stage#section?` check if section belongs to stage
23
+ - `Ecoportal::API::V2::Page::Sections`
24
+ - `#get_by_id`
25
+ - `#unattached` sections that are not attached to any stage
26
+ - `Ecoportal::API::V2::Page::Section`
27
+ - `#add_component` **added** parameter `before`: to cover case where you want to add it at the beginning
28
+ - `#component?` **widened** parameter type
29
+ - `#stages` stages where this section is attached
30
+ - `attached?` whether or not the section is attached
31
+ - `Ecoportal::API::V2::Page::Component`
32
+ - `#attached?` whether or not the field is attached to some section
33
+ - `#multi_section?` if the field is attached to more than one section :/
34
+ - **added** support for `forces`
35
+ - `Ecoportal::API::V2::Page::Force`
36
+ - `Ecoportal::API::V2::Page::Forces`
37
+ - `Ecoportal::API::V2::Page::Force::Binding`
38
+ - `Ecoportal::API::V2::Page::Force::Bindings`
39
+ - **added** shortcut to `#ooze` throughout all the model
40
+ - **validations** in some methods
41
+ - `Ecoportal::API::V2::Page::Stage#add_section`: section should be in `ooze.sections`
42
+ - `Ecoportal::API::V2::Page::Section#add_component`: component should be in `ooze.components`
43
+ - `Ecoportal::API::V2::Page::Force::Bindings#add`:
44
+ - section to be in `ooze.sections`
45
+ - component to be in `ooze.components`
46
+ - `Ecoportal::API::V2::Pages::PageStage#as_update` on page instances, it checks that
47
+ - Fields do not belong to more than one section
48
+ - Fields belong at least to one section
49
+ - Sections belong to at least one stage
50
+
51
+ ### Fixed
52
+ - `Ecoportal::API::Common::Content::ArrayModel#insert_one` was not inserting when not found. Should insert at least at the end.
53
+
54
+ ## [0.8.13] - 2021-09-03
55
+
56
+ ### Fixed
57
+ - `Ecoportal::API::V2::Page::Sections`
10
58
  - `weight` fixing should only happen on entire page, **not** on stage sections that could change the order of section shared with other stages
11
59
  - `#scope_weight` was not excluding the section when using `weight` of the last one
12
60
  - Several classes with `embeds_many` were performing the `ordering` of those elements in the wrong way
@@ -224,25 +224,18 @@ module Ecoportal
224
224
  i = index(value)
225
225
  return i if (i && uniq?)
226
226
  pos = case
227
- when used_param?(pos)
228
- pos || length
229
- when used_param?(before)
230
- before ? index(before) : length
231
- when used_param?(after)
232
- if after
233
- if i = index(after) then i + 1 end
234
- else
235
- length
236
- end
237
- else
238
- length
227
+ when used_param?(pos) && pos
228
+ pos
229
+ when used_param?(before) && before
230
+ index(before)
231
+ when used_param?(after) && after
232
+ if i = index(after) then i + 1 end
239
233
  end
240
234
 
235
+ pos ||= length
241
236
  pos.tap do |i|
242
- unless !i
243
- _items.insert(pos, value)
244
- on_change
245
- end
237
+ _items.insert(pos, value)
238
+ on_change
246
239
  end
247
240
  end
248
241
 
@@ -109,6 +109,10 @@ module Ecoportal
109
109
  self.class.klass
110
110
  end
111
111
 
112
+ def _doc_pos(value)
113
+ _doc_key(value)
114
+ end
115
+
112
116
  # Transforms `value` into the actual `key` to access the object in the doc `Array`
113
117
  # @note
114
118
  # - The name of the method is after the paren't class method
@@ -152,6 +156,13 @@ module Ecoportal
152
156
  items_by_key[get_key(value)]
153
157
  end
154
158
 
159
+ # Checks if an element exists in the collection
160
+ # @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
161
+ # @return [Boolean] whether or not it is included
162
+ def include?(value)
163
+ items_by_key.key?(get_key(value))
164
+ end
165
+
155
166
  # @return [Array<Object>] the `items_class` element object
156
167
  def values_at(*keys)
157
168
  keys.map {|key| self[key]}
@@ -60,7 +60,7 @@ module Ecoportal
60
60
  a == b
61
61
  end
62
62
 
63
- # Compares `a` as charring changes of `b`
63
+ # Compares `a` as carrying changes of `b`
64
64
  # @return [Hash] patch data object with only changes
65
65
  def patch_data(a, b = nil, delete: false)
66
66
  {}.tap do |data_hash|
@@ -93,6 +93,10 @@ module Ecoportal
93
93
  passboolean :hide_view, :hidden_on_reports, :hidden_on_mobile
94
94
  passarray :refs
95
95
 
96
+ def ooze
97
+ self._parent.ooze
98
+ end
99
+
96
100
  def ref_backend
97
101
  refs.first
98
102
  end
@@ -103,10 +107,23 @@ module Ecoportal
103
107
  end
104
108
  end
105
109
 
110
+ # Looks up the section that this component belongs to.
111
+ # @return [Ecoportal::API::V2::Page::Section, nil] the section where this field is attached to.
106
112
  def section
107
113
  root.sections.find {|sec| sec.component?(id)}
108
114
  end
109
115
 
116
+ # @return [Boolean] whether or not this field is attached to any section.
117
+ def attached?
118
+ !!section
119
+ end
120
+
121
+ # @return [Boolean] whether or not the component has been attached to more than one section.
122
+ def multi_section?
123
+ secs = ooze.sections.select {|sec| sec.component?(id)}
124
+ secs.length > 1
125
+ end
126
+
110
127
  def indexable_label
111
128
  self.class.indexable_label(label)
112
129
  end
@@ -13,18 +13,27 @@ module Ecoportal
13
13
 
14
14
  order_matters = true
15
15
 
16
+ def ooze
17
+ self._parent.ooze
18
+ end
19
+
20
+ # @return [Ecoportal::API::V2::Page::Component] the field with `id`
16
21
  def get_by_id(id)
17
22
  self.find do |comp|
18
23
  comp.id == id
19
24
  end
20
25
  end
21
26
 
27
+ # @return [Array<Ecoportal::API::V2::Page::Component>] the fields of that `type`
22
28
  def get_by_type(type)
23
29
  self.select do |comp|
24
30
  comp.type.downcase == type.to_s.strip.downcase
25
31
  end
26
32
  end
27
33
 
34
+ # @param name [String, Regexp] the `name` to search the field based on their `label`
35
+ # @param type [String] the `type` of the fields to be included
36
+ # @return [Array<Ecoportal::API::V2::Page::Component>] the fields that match `name`.
28
37
  def get_by_name(name, type: nil)
29
38
  pool = type ? get_by_type(type) : self
30
39
  pool.select do |comp|
@@ -32,6 +41,12 @@ module Ecoportal
32
41
  end
33
42
  end
34
43
 
44
+ # It creates a **new** component
45
+ # @param label [String, nil]
46
+ # @param type [String] the type of the field
47
+ # @yield [field] do some stuff with field
48
+ # @yieldparam [Ecoportal::API::V2::Page::Component] the created field
49
+ # @return [Ecoportal::API::V2::Page::Component] the created field.
35
50
  def add(label:, type:)
36
51
  fld_doc = component_class.new_doc(type: type)
37
52
  upsert!(fld_doc) do |fld|
@@ -40,6 +55,15 @@ module Ecoportal
40
55
  end
41
56
  end
42
57
 
58
+ # @return [Array<Ecoportal::API::V2::Page::Component>] **orphaned** fields (with no section).
59
+ def unattached
60
+ select {|comp| !comp.attached?}
61
+ end
62
+
63
+ # @return [Array<Ecoportal::API::V2::Page::Component>] fields belonging to more than one section.
64
+ def multi_section
65
+ select {|comp| comp.multi_section?}
66
+ end
43
67
  end
44
68
  end
45
69
  end
@@ -0,0 +1,54 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class Force
6
+ class Binding < Common::Content::DoubleModel
7
+ class << self
8
+ def new_doc
9
+ {
10
+ "id" => new_uuid
11
+ }
12
+ end
13
+ end
14
+ COMPONENT_TYPE = "membrane_binding"
15
+ SECTION_TYPE = "flow_node_binding"
16
+
17
+ passkey :id
18
+ passforced :patch_ver, default: 1
19
+ passthrough :name, :reference_id, :type
20
+
21
+ def ooze
22
+ self._parent.ooze
23
+ end
24
+
25
+ # @return [Boolean] whether or not this the binding refers to a Component
26
+ def component?
27
+ type == COMPONENT_TYPE
28
+ end
29
+
30
+ # @return [Boolean] whether or not this the binding refers to a Section
31
+ def section?
32
+ type == SECTION_TYPE
33
+ end
34
+
35
+ # @return [Ecoportal::API::V2::Page::Component] field referenced by this binding.
36
+ def component
37
+ raise "This is not a component binding, but a section binding" unless component?
38
+ ooze.components.get_by_id(reference_id)
39
+ end
40
+
41
+ # @return [Ecoportal::API::V2::Page::Section] section referenced by this binding.
42
+ def section
43
+ raise "This is not a section binding, but a component binding" unless section?
44
+ ooze.sections.get_by_id(reference_id)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ require 'ecoportal/api/v2/page/force/binding'
54
+ require 'ecoportal/api/v2/page/force/bindings'
@@ -0,0 +1,126 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class Force
6
+ class Bindings < Common::Content::CollectionModel
7
+ class_resolver :binding_class, "Ecoportal::API::V2::Page::Force::Binding"
8
+
9
+ self.klass = :binding_class
10
+ order_matters = true
11
+
12
+ def ooze
13
+ self._parent.ooze
14
+ end
15
+
16
+ # @param id [String] the `id` of the binding to find.
17
+ # @return [Ecoportal::API::V2::Page::Force::Binding] binding with `id`
18
+ def get_by_id(id)
19
+ self.find do |bind|
20
+ bind.id == id
21
+ end
22
+ end
23
+
24
+ # @param type [String] target `type` of binding
25
+ # 1. Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE
26
+ # 2. Ecoportal::API::V2::Page::Force::Binding::SECTION_TYPE
27
+ # @return [Array<Ecoportal::API::V2::Page::Force::Binding>] the bindings of type `type`
28
+ def get_by_type(type = Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE)
29
+ self.select do |bind|
30
+ bind.type.downcase == type.to_s.strip.downcase
31
+ end
32
+ end
33
+
34
+ # @param type [String] target `type` of binding
35
+ # 1. Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE
36
+ # 2. Ecoportal::API::V2::Page::Force::Binding::SECTION_TYPE
37
+ # @return [Array<Ecoportal::API::V2::Page::Force::Binding>] the bindings matching `name`
38
+ def get_by_name(name, type: nil)
39
+ pool = type ? get_by_type(type) : self
40
+ pool.select do |bind|
41
+ same_string?(bind.name, name)
42
+ end
43
+ end
44
+
45
+ # Creates a new `binding`
46
+ # @note
47
+ # - As there's no position property, it will upsert to the array of bindings
48
+ # @raise [ArgumentError] when `reference` is neither of Component or Section
49
+ # @raise [Exception] when
50
+ # 1. `reference` is a field missing in ooze.components
51
+ # 2. `reference` is a section missing in ooze.sections
52
+ # @param reference [Ecoportal::API::V2::Page::Component, Ecoportal::API::V2::Page::Section]
53
+ # The field or the section to bind.
54
+ # @yield [binding] do some stuff with binding
55
+ # @yieldparam binding [Ecoportal::API::V2::Page::Force::Binding] the created binding
56
+ # @return [Ecoportal::API::V2::Page::Force::Binding] the created binding.
57
+ def add(reference, name:, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
58
+ binding_doc = binding_class.new_doc
59
+
60
+ type = case reference
61
+ when Ecoportal::API::V2::Page::Component
62
+ unless ooze.components.include?(reference)
63
+ msg = "The field '#{reference.label}' (#{reference.id}) is not present in ooze.components.\n"
64
+ msg += "Review your script (i.e. @var where you store previous ooze runs)."
65
+ raise msg
66
+ end
67
+ Ecoportal::API::V2::Page::Force::Binding::COMPONENT_TYPE
68
+ when Ecoportal::API::V2::Page::Section
69
+ unless ooze.sections.include?(reference)
70
+ msg = "The section '#{reference.heading}' (#{reference.id}) is not present in ooze.sections.\n"
71
+ msg += "Review your script (i.e. @var where you store previous ooze runs)."
72
+ raise msg
73
+ end
74
+ Ecoportal::API::V2::Page::Force::Binding::SECTION_TYPE
75
+ else
76
+ msg = "You can only create bindings with Component and Section. Given: #{reference.class}"
77
+ raise ArgumentError.new(msg)
78
+ end
79
+
80
+ position = scope_position(pos: pos, before: before, after: after)
81
+ upsert!(binding_doc, pos: position) do |bind|
82
+ bind.name = name
83
+ bind.reference_id = reference.id
84
+ bind.type = type
85
+ yield(bind) if block_given?
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def scope_position(pos: NOT_USED, before: NOT_USED, after: NOT_USED)
92
+ case
93
+ when used_param?(pos)
94
+ if pos = to_binding(pos)
95
+ _doc_pos(pos) - 1
96
+ end
97
+ when used_param?(before)
98
+ if before = to_binding(before)
99
+ _doc_pos(before) - 1
100
+ end
101
+ when used_param?(after)
102
+ if after = to_binding(after)
103
+ _doc_pos(after) - 1
104
+ end
105
+ end.yield_self do |position|
106
+ position ||= self.count
107
+ end
108
+ end
109
+
110
+ def to_binding(value)
111
+ case value
112
+ when Ecoportal::API::V2::Page::Force::Binding
113
+ value
114
+ when Numeric
115
+ self[value]
116
+ else
117
+ get_by_name(value).first
118
+ end
119
+ end
120
+
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,34 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class Force < Common::Content::DoubleModel
6
+ INITIAL_WEIGHT = 9999
7
+
8
+ class << self
9
+ def new_doc
10
+ {
11
+ "id" => new_uuid,
12
+ "weight" => INITIAL_WEIGHT
13
+ }
14
+ end
15
+ end
16
+
17
+ class_resolver :bindings_class, "Ecoportal::API::V2::Page::Force::Bindings"
18
+
19
+ passkey :id
20
+ passforced :patch_ver, default: 1
21
+ passthrough :name, :weight, :script
22
+ embeds_many :bindings, enum_class: :bindings_class
23
+
24
+ def ooze
25
+ self._parent.ooze
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ require 'ecoportal/api/v2/page/force/binding'
34
+ require 'ecoportal/api/v2/page/force/bindings'
@@ -0,0 +1,103 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class Forces < Common::Content::CollectionModel
6
+ class_resolver :force_class, "Ecoportal::API::V2::Page::Force"
7
+
8
+ self.klass = :force_class
9
+ order_matters = true
10
+
11
+ def ooze
12
+ self._parent.ooze
13
+ end
14
+
15
+ # @return [Ecoportal::API::V2::Page::Force]
16
+ def get_by_id(id)
17
+ self.find do |force|
18
+ force.id == id
19
+ end
20
+ end
21
+
22
+ # @return [Array<Ecoportal::API::V2::Page::Force>]
23
+ def get_by_name(name)
24
+ self.select do |force|
25
+ same_string?(force.name, name)
26
+ end
27
+ end
28
+
29
+ # Creates a new `force`
30
+ # @note
31
+ # - It won't fix weights unless all the forces of the ooze are present
32
+ # - This means that it doesn't fix forces weights on stages,
33
+ # as shared forces could change order in other stages
34
+ # @yield [force] to do some stuff with the `force`
35
+ # @yieldparam force [Ecoportal::API::V2::Page::Force] the created force
36
+ # @return [Ecoportal::API::V2::Page::Force]
37
+ def add(name, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
38
+ force_doc = force_class.new_doc
39
+ upsert!(force_doc) do |force| #, pos: pos, before: before, after: after) do |section|
40
+ force.name = name
41
+ if weight = scope_weight(force, pos: pos, before: before, after: after)
42
+ force.weight = weight
43
+ end
44
+ fix_weights!
45
+ yield(force) if block_given?
46
+ end
47
+ end
48
+
49
+ # Gets the forces ordered by `weight` (as they appear in the page)
50
+ # @return [Array<Ecoportal::API::V2::Page::Force>] forces ordered by `weight`
51
+ def ordered
52
+ self.sort_by.with_index do |force, index|
53
+ [force.weight, index]
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def fix_weights!
60
+ unless self._parent.is_a?(Ecoportal::API::V2::Pages::PageStage)
61
+ ordered.each_with_index do |force, index|
62
+ force.weight = index
63
+ end
64
+ end
65
+ end
66
+
67
+ def scope_weight(force, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
68
+ case
69
+ when used_param?(pos)
70
+ if pos = to_force(pos)
71
+ pos.weight - 1
72
+ end
73
+ when used_param?(before)
74
+ if before = to_force(before)
75
+ before.weight - 1
76
+ end
77
+ when used_param?(after)
78
+ if after = to_force(after)
79
+ after.weight
80
+ end
81
+ end.yield_self do |weight|
82
+ weight = ordered.reject do |frc|
83
+ frc.id == force.id
84
+ end.last&.weight
85
+ weight ||= force_class.const_get(:INITIAL_WEIGHT)
86
+ end
87
+ end
88
+
89
+ def to_force(value)
90
+ case value
91
+ when Ecoportal::API::V2::Page::Force
92
+ value
93
+ when Numeric
94
+ ordered[value]
95
+ else
96
+ get_by_name(value).first
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -57,9 +57,7 @@ module Ecoportal
57
57
  end.yield_self do |unused|
58
58
  raise "Unknown configuaration options #{unused}" unless unused.empty?
59
59
  end
60
-
61
60
  end
62
-
63
61
  end
64
62
  end
65
63
  end
@@ -34,19 +34,48 @@ module Ecoportal
34
34
  passarray :component_ids, :left_component_ids, :right_component_ids
35
35
  passboolean :minimized
36
36
 
37
+ def ooze
38
+ self._parent.ooze
39
+ end
40
+
41
+ # @return [Array<Ecoportal::API::V2::Page::Stage>] the stage(s) this section belongs to.
42
+ def stages
43
+ ooze.stages.select {|stg| stg.section?(self)}
44
+ end
45
+
46
+ # @return [Boolean] whether or not the section appears in an ooze instance
47
+ def attached?
48
+ !ooze.stages? || stages.any?
49
+ end
50
+
51
+ # @return [Boolean] whether or not this section is a split section
37
52
  def split?
38
53
  doc && doc["type"] == "split"
39
54
  end
40
55
 
56
+ # @return [Array<String>] all the `ids` of the components/fields in this section
41
57
  def all_component_ids
42
58
  return component_ids.to_a unless split?
43
59
  left_component_ids.to_a | right_component_ids.to_a
44
60
  end
45
61
 
46
- def component?(id)
47
- all_component_ids.include?(id)
62
+ # @raise [ArgumentError] if `com_or_id` is not of any of the allowed types
63
+ # @param com_or_id [Ecoportal::API::V2::Page::Component, String] Component or `id` thereof
64
+ # @return [Boolean] whether or not a component/field belongs to this section.
65
+ def component?(com_or_id)
66
+ case com_or_id
67
+ when Ecoportal::API::V2::Page::Component
68
+ component?(com_or_id.id)
69
+ when String
70
+ all_component_ids.include?(id)
71
+ else
72
+ msg = "Missuse: com_or_id should be a Component or a String. Given: #{com_or_id.class}"
73
+ raise ArgumentError.new(msg)
74
+ end
48
75
  end
49
76
 
77
+ # It looks up the components that belong to this section.
78
+ # @return [Array<Ecoportal::API::V2::Page::Component>]
50
79
  def components(side: nil)
51
80
  case side
52
81
  when :right
@@ -60,11 +89,17 @@ module Ecoportal
60
89
  end
61
90
  end
62
91
 
92
+ # It looks up the components that belong to the `left` side of this section.
93
+ # @raise [Exception] if this is not a `split` section
94
+ # @return [Array<Ecoportal::API::V2::Page::Component>]
63
95
  def components_left
64
96
  raise "You are trying to retrieve side components in a Split Section" unless split?
65
97
  components_by_id(*left_component_ids)
66
98
  end
67
99
 
100
+ # It looks up the components that belong to the `right` side of this section.
101
+ # @raise [Exception] if this is not a `split` section
102
+ # @return [Array<Ecoportal::API::V2::Page::Component>]
68
103
  def components_right
69
104
  raise "You are trying to retrieve side components in a Split Section" unless split?
70
105
  components_by_id(*right_component_ids)
@@ -77,9 +112,20 @@ module Ecoportal
77
112
  # - If `after` is specified, it searches field
78
113
  # - On the specific `side`, if specified (and split section)
79
114
  # - And adds the `field` after it, when found, or at the end if `after` is not found
115
+ # @raise [ArgumentError] if `field` is not a Component
116
+ # @raise [Exception] if the field does not belong to ooze.components
117
+ # @raise [Exception] if the field belongs to another section
80
118
  # @param field [Ecoportal::API::V2::Page::Component] the field to be added.
81
- def add_component(field, after: nil, side: nil)
82
- raise "field should be a Ecoportal::API::V2::Page::Component. Given: #{field.class}" unless field.is_a?(Ecoportal::API::V2::Page::Component)
119
+ def add_component(field, before: nil, after: nil, side: nil)
120
+ unless field.is_a?(Ecoportal::API::V2::Page::Component)
121
+ msg = "Expected Ecoportal::API::V2::Page::Component. Given: #{field.class}"
122
+ raise ArgumentError.new(msg)
123
+ end
124
+ unless ooze.components.include?(field)
125
+ msg = "The field '#{field.label}' (#{field.id}) is not present in ooze.components.\n"
126
+ msg += "Review your script (i.e. @var where you store previous ooze runs)."
127
+ raise msg
128
+ end
83
129
  # IMPORTANT NOTE: The code below creates objects, because field.section does a search on section.component_ids
84
130
  if field.section == self
85
131
  puts "Field with id '#{field.id}' already belongs to this section"
@@ -88,24 +134,19 @@ module Ecoportal
88
134
  raise "Field with id '#{field.id}' belongs to section '#{sec.heading || "Unnamed"}' (id: '#{sec.id}')"
89
135
  end
90
136
 
137
+ if before
138
+ before_fld = to_component(before, side: side)
139
+ elsif after
140
+ after_fld = to_component(afterm, side: side)
141
+ end
142
+
91
143
  if split?
92
144
  ids_ary = side == :right ? right_component_ids : left_component_ids
93
- fields = components(side: side || :left)
94
145
  else
95
146
  ids_ary = component_ids
96
- fields = components
97
- end
98
-
99
- if after
100
- after_fld = fields.find do |fld|
101
- found = nil
102
- found ||= !!after if after.is_a?(Ecoportal::API::V2::Page::Component)
103
- found ||= fld.id == after
104
- found ||= same_string?(fld.label, after)
105
- end
106
147
  end
107
148
 
108
- ids_ary.insert_one(field.id, after: after_fld&.id)
149
+ ids_ary.insert_one(field.id, before: before_fld&.id, after: after_fld&.id)
109
150
  self
110
151
  end
111
152
 
@@ -118,6 +159,20 @@ module Ecoportal
118
159
  end
119
160
  end
120
161
 
162
+ def to_component(value, side: nil)
163
+ if split?
164
+ fields = components(side: side || :left)
165
+ else
166
+ fields = components
167
+ end
168
+
169
+ fields.find do |fld|
170
+ found = nil
171
+ found ||= !!value if value.is_a?(Ecoportal::API::V2::Page::Component)
172
+ found ||= fld.id == value
173
+ found ||= same_string?(fld.label, value)
174
+ end
175
+ end
121
176
  end
122
177
  end
123
178
  end
@@ -7,6 +7,10 @@ module Ecoportal
7
7
 
8
8
  self.klass = :section_class
9
9
 
10
+ def ooze
11
+ self._parent.ooze
12
+ end
13
+
10
14
  # Creates a new `section`
11
15
  # @note
12
16
  # - It won't fix weights unless all the sections of the ooze are present
@@ -24,12 +28,21 @@ module Ecoportal
24
28
  end
25
29
  end
26
30
 
31
+ # @return [Ecoportal::API::V2::Page::Section]
32
+ def get_by_id(id)
33
+ self.find do |sec|
34
+ sec.id == id
35
+ end
36
+ end
37
+
38
+ # @return [Array<Ecoportal::API::V2::Page::Section>]
27
39
  def get_by_type(type)
28
40
  ordered.select do |sec|
29
41
  sec.type == type
30
42
  end
31
43
  end
32
44
 
45
+ # @return [Array<Ecoportal::API::V2::Page::Section>]
33
46
  def get_by_heading(heading)
34
47
  ordered.select do |sec|
35
48
  value = heading == :unnamed ? nil : heading
@@ -38,6 +51,7 @@ module Ecoportal
38
51
  end
39
52
 
40
53
  # Gets all the sections between `sec1` and `sec2`
54
+ # @return [Array<Ecoportal::API::V2::Page::Section>]
41
55
  def between(sec1, sec2, included: false)
42
56
  sorted_secs = ordered
43
57
  pos1 = (sec1 = to_section(sec1)) && sorted_secs.index(sec1)
@@ -53,12 +67,18 @@ module Ecoportal
53
67
  end
54
68
 
55
69
  # Gets the sections ordered by `weight` (as they appear in the page)
70
+ # @return [Array<Ecoportal::API::V2::Page::Section>] section sorted by `weight`
56
71
  def ordered
57
72
  self.sort_by.with_index do |section, index|
58
73
  [section.weight, index]
59
74
  end
60
75
  end
61
76
 
77
+ # @return [Array<Ecoportal::API::V2::Page::Section>] sections not attached to any stage
78
+ def unattached
79
+ select {|sec| !sec.attached?}
80
+ end
81
+
62
82
  private
63
83
 
64
84
  def scope_weight(section, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
@@ -108,7 +128,6 @@ module Ecoportal
108
128
  return if pos < 0
109
129
  secs[pos]
110
130
  end
111
-
112
131
  end
113
132
  end
114
133
  end
@@ -17,6 +17,13 @@ module Ecoportal
17
17
  embeds_one :creator_flags, klass: "Ecoportal::API::V2::Page::PermissionFlags"
18
18
  passthrough :can
19
19
 
20
+ def ooze
21
+ self._parent.ooze
22
+ end
23
+
24
+ # @yield [section] do some stuff with section.
25
+ # @yieldparam section [Ecoportal::API::V2::Page::Section] one of the sections of this stage
26
+ # @return [Array<Ecoportal::API::V2::Page::Section>] sections attached to this stage.
20
27
  def sections
21
28
  sec_ids = section_ids.to_a
22
29
  root.sections.values_at(*sec_ids).select.with_index do |sec, i|
@@ -25,11 +32,40 @@ module Ecoportal
25
32
  end.sort_by.with_index {|sec, index| [sec.weight, index]}
26
33
  end
27
34
 
35
+ # Check if a section belongs to a stage
36
+ # @raise [ArgumentError] if none of the valid types of `sec_or_id` are used
37
+ # @param sec_or_id [String, Ecoportal::API::V2::Page::Section]
38
+ # @return [Boolean] whether or not the section belongs to the stage
39
+ def section?(sec_or_id)
40
+ case sec_or_id
41
+ when Ecoportal::API::V2::Page::Section
42
+ section?(sec_or_id.id)
43
+ when String
44
+ self.section_ids.include?(id)
45
+ else
46
+ raise ArgumentError.new("sec_or_id must be either a Section or a String. Given: #{sec_or_id.class}")
47
+ end
48
+ end
49
+
50
+ # Adds one or more sections to this stage
51
+ # @raise [ArgumentError] if any of the elements is not a Section
52
+ # @raise [Exception] if any of the sections does not belong to ooze.sections
53
+ # @param secs [Array<Ecoportal::API::V2::Page::Section>] sections to be added to this stage.
28
54
  def add_section(*secs)
29
- secs.each {|sec| section_ids.insert_one(sec.id)}
55
+ secs.each do |sec|
56
+ unless sec.is_a?(Ecoportal::API::V2::Page::Section)
57
+ msg = "Expected Ecoportal::API::V2::Page::Section. Given: #{sec.class}"
58
+ raise ArgumentError.new(msg)
59
+ end
60
+ unless ooze.sections.include?(sec)
61
+ msg = "The section '#{sec.heading}' (#{sec.id}) is not present in ooze.sections.\n"
62
+ msg += "Review your script (i.e. @var where you store previous ooze runs)."
63
+ raise msg
64
+ end
65
+ section_ids.insert_one(sec.id)
66
+ end
30
67
  self
31
68
  end
32
-
33
69
  end
34
70
  end
35
71
  end
@@ -7,6 +7,12 @@ module Ecoportal
7
7
 
8
8
  self.klass = :stage_class
9
9
 
10
+ def ooze
11
+ self._parent.ooze
12
+ end
13
+
14
+ # @param name [String, Regexp] the `name` of the stage to find.
15
+ # @return [Ecoportal::API::V2::Page::Stage, nil]
10
16
  def get_by_name(name)
11
17
  self.find do |stage|
12
18
  same_string?(stage.name, name)
@@ -10,7 +10,7 @@ module Ecoportal
10
10
  "permits", "mould_counter", "mould",
11
11
  "state", "task_priority",
12
12
  "votes_enabled", "upvotes", "downvotes",
13
- "force_errors", "subtags"
13
+ "forces", "force_errors", "subtags"
14
14
  ]
15
15
 
16
16
  passkey :id
@@ -24,15 +24,21 @@ module Ecoportal
24
24
  class_resolver :components_class, "Ecoportal::API::V2::Page::Components"
25
25
  class_resolver :sections_class, "Ecoportal::API::V2::Page::Sections"
26
26
  class_resolver :stages_class, "Ecoportal::API::V2::Page::Stages"
27
+ class_resolver :forces_class, "Ecoportal::API::V2::Page::Forces"
27
28
 
28
29
  embeds_many :components, enum_class: :components_class
29
30
  embeds_many :sections, enum_class: :sections_class
30
31
  embeds_many :stages, enum_class: :stages_class
32
+ embeds_many :forces, enum_class: :forces_class
31
33
 
32
34
  def initialize(doc = [], parent: self, key: nil)
33
35
  super(_doc_bug_fix(doc), parent: parent, key: key)
34
36
  end
35
37
 
38
+ def ooze
39
+ self
40
+ end
41
+
36
42
  def as_update
37
43
  super.tap do |hash|
38
44
  unless !hash
@@ -90,3 +96,5 @@ require 'ecoportal/api/v2/page/section'
90
96
  require 'ecoportal/api/v2/page/sections'
91
97
  require 'ecoportal/api/v2/page/stage'
92
98
  require 'ecoportal/api/v2/page/stages'
99
+ require 'ecoportal/api/v2/page/force'
100
+ require 'ecoportal/api/v2/page/forces'
@@ -10,7 +10,7 @@ module Ecoportal
10
10
  embeds_many :permits, klass: "Ecoportal::API::V2::Page::Permit"
11
11
  passarray :force_errors, :subtags, order_matters: false
12
12
 
13
- # `id` of the stage we got the data of.
13
+ # @return [String] `id` of the stage we got the data of.
14
14
  def current_stage_id
15
15
  doc.dig("active_stage", "id") || doc["current_stage_id"]
16
16
  end
@@ -22,6 +22,44 @@ module Ecoportal
22
22
  end
23
23
  end
24
24
 
25
+ # @raise [Exception] if for this page instance, there are any of:
26
+ # 1. orphaned components (fields not belonging to any section)
27
+ # 2. components multi-section (fields belonging to more than one section)
28
+ # 3. orphaned sections (sections not belonging to any stage)
29
+ def as_update(*args, **kargs)
30
+ validate.tap do |validation|
31
+ raise validation if validation.is_a?(String)
32
+ end
33
+ super(*args, **kargs)
34
+ end
35
+
36
+ private
37
+
38
+ def validate
39
+ msg = ""
40
+ if (orphans = components.unattached).length > 0
41
+ msg += "There are fields not attached to any sections:"
42
+ msg += orphans.map do |fld|
43
+ fld.label
44
+ end.join("\n • ") + "\n"
45
+ end
46
+
47
+ if (multi = components.multi_section).length > 0
48
+ msg += "There are fields attached to more than one section:"
49
+ msg += orphans.map do |fld|
50
+ fld.label
51
+ end.join("\n • ") + "\n"
52
+ end
53
+
54
+ if (orphans = sections.unattached).length > 0
55
+ msg += "There are sections not attached to any stage:"
56
+ msg += orphans.map do |sec|
57
+ "'#{sec.header}' (#{sec.id})"
58
+ end.join("\n • ") + "\n"
59
+ end
60
+ msg.empty?? true : msg
61
+ end
62
+
25
63
  end
26
64
  end
27
65
  end
@@ -1,5 +1,5 @@
1
1
  module Ecoportal
2
2
  module API
3
- GEM2_VERSION = "0.8.13"
3
+ GEM2_VERSION = "0.8.17"
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.13
4
+ version: 0.8.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-02 00:00:00.000000000 Z
11
+ date: 2021-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -218,6 +218,10 @@ files:
218
218
  - lib/ecoportal/api/v2/page/component/signature_field.rb
219
219
  - lib/ecoportal/api/v2/page/component/tag_field.rb
220
220
  - lib/ecoportal/api/v2/page/components.rb
221
+ - lib/ecoportal/api/v2/page/force.rb
222
+ - lib/ecoportal/api/v2/page/force/binding.rb
223
+ - lib/ecoportal/api/v2/page/force/bindings.rb
224
+ - lib/ecoportal/api/v2/page/forces.rb
221
225
  - lib/ecoportal/api/v2/page/permission_flags.rb
222
226
  - lib/ecoportal/api/v2/page/permit.rb
223
227
  - lib/ecoportal/api/v2/page/section.rb