ecoportal-api-v2 0.8.11 → 0.8.15

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -0
  3. data/lib/ecoportal/api/common/content/array_model.rb +10 -17
  4. data/lib/ecoportal/api/common/content/collection_model.rb +23 -6
  5. data/lib/ecoportal/api/common/content/doc_helpers.rb +2 -2
  6. data/lib/ecoportal/api/common/content/double_model.rb +15 -5
  7. data/lib/ecoportal/api/common/content/hash_diff_patch.rb +1 -1
  8. data/lib/ecoportal/api/v2/page/component/action.rb +1 -1
  9. data/lib/ecoportal/api/v2/page/component/action_field.rb +3 -3
  10. data/lib/ecoportal/api/v2/page/component/checklist_field.rb +3 -3
  11. data/lib/ecoportal/api/v2/page/component/file.rb +1 -1
  12. data/lib/ecoportal/api/v2/page/component/files_field.rb +3 -3
  13. data/lib/ecoportal/api/v2/page/component/gauge_field.rb +3 -3
  14. data/lib/ecoportal/api/v2/page/component/selection_field.rb +3 -3
  15. data/lib/ecoportal/api/v2/page/component.rb +17 -0
  16. data/lib/ecoportal/api/v2/page/components.rb +24 -0
  17. data/lib/ecoportal/api/v2/page/force/binding.rb +54 -0
  18. data/lib/ecoportal/api/v2/page/force/bindings.rb +126 -0
  19. data/lib/ecoportal/api/v2/page/force.rb +34 -0
  20. data/lib/ecoportal/api/v2/page/forces.rb +103 -0
  21. data/lib/ecoportal/api/v2/page/permission_flags.rb +0 -2
  22. data/lib/ecoportal/api/v2/page/section.rb +77 -17
  23. data/lib/ecoportal/api/v2/page/sections.rb +36 -6
  24. data/lib/ecoportal/api/v2/page/stage.rb +39 -3
  25. data/lib/ecoportal/api/v2/page/stages.rb +9 -3
  26. data/lib/ecoportal/api/v2/page.rb +42 -1
  27. data/lib/ecoportal/api/v2/pages/page_stage.rb +46 -1
  28. data/lib/ecoportal/api/v2/pages.rb +3 -4
  29. data/lib/ecoportal/api/v2/registers.rb +2 -2
  30. data/lib/ecoportal/api/v2_version.rb +1 -1
  31. metadata +6 -2
@@ -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
@@ -3,12 +3,14 @@ module Ecoportal
3
3
  class V2
4
4
  class Page
5
5
  class Section < Common::Content::DoubleModel
6
+ INITIAL_WEIGHT = 9999
7
+
6
8
  class << self
7
9
  def new_doc(split: false)
8
10
  {
9
11
  "id" => new_uuid,
10
12
  "type" => split ? "split" : "content",
11
- "weight" => 800
13
+ "weight" => INITIAL_WEIGHT
12
14
  }.tap do |out|
13
15
  component_ids = if split
14
16
  {
@@ -32,19 +34,48 @@ module Ecoportal
32
34
  passarray :component_ids, :left_component_ids, :right_component_ids
33
35
  passboolean :minimized
34
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.has_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
35
52
  def split?
36
53
  doc && doc["type"] == "split"
37
54
  end
38
55
 
56
+ # @return [Array<String>] all the `ids` of the components/fields in this section
39
57
  def all_component_ids
40
58
  return component_ids.to_a unless split?
41
59
  left_component_ids.to_a | right_component_ids.to_a
42
60
  end
43
61
 
44
- def component?(id)
45
- 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
46
75
  end
47
76
 
77
+ # It looks up the components that belong to this section.
78
+ # @return [Array<Ecoportal::API::V2::Page::Component>]
48
79
  def components(side: nil)
49
80
  case side
50
81
  when :right
@@ -58,11 +89,17 @@ module Ecoportal
58
89
  end
59
90
  end
60
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>]
61
95
  def components_left
62
96
  raise "You are trying to retrieve side components in a Split Section" unless split?
63
97
  components_by_id(*left_component_ids)
64
98
  end
65
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>]
66
103
  def components_right
67
104
  raise "You are trying to retrieve side components in a Split Section" unless split?
68
105
  components_by_id(*right_component_ids)
@@ -75,32 +112,41 @@ module Ecoportal
75
112
  # - If `after` is specified, it searches field
76
113
  # - On the specific `side`, if specified (and split section)
77
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
78
118
  # @param field [Ecoportal::API::V2::Page::Component] the field to be added.
79
- def add_component(field, after: nil, side: nil)
80
- 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
129
+ # IMPORTANT NOTE: The code below creates objects, because field.section does a search on section.component_ids
81
130
  if field.section == self
82
- raise "Field with id '#{field.id}' already belongs to this section"
131
+ puts "Field with id '#{field.id}' already belongs to this section"
83
132
  elsif sec = field.section
84
133
  # Field belongs to another section
85
134
  raise "Field with id '#{field.id}' belongs to section '#{sec.heading || "Unnamed"}' (id: '#{sec.id}')"
86
135
  end
87
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
+
88
143
  if split?
89
144
  ids_ary = side == :right ? right_component_ids : left_component_ids
90
- fields = components(side: side || :left)
91
145
  else
92
146
  ids_ary = component_ids
93
- fields = components
94
- end
95
- if after
96
- after_fld = fields.find do |fld|
97
- found = nil
98
- found ||= !!after if after.is_a?(Ecoportal::API::V2::Page::Component)
99
- found ||= fld.id == after
100
- found ||= same_string?(fld.label, after)
101
- end
102
147
  end
103
- ids_ary.insert_one(field.id, after: after_fld&.id)
148
+
149
+ ids_ary.insert_one(field.id, before: before_fld&.id, after: after_fld&.id)
104
150
  self
105
151
  end
106
152
 
@@ -113,6 +159,20 @@ module Ecoportal
113
159
  end
114
160
  end
115
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
116
176
  end
117
177
  end
118
178
  end
@@ -7,12 +7,20 @@ 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`
15
+ # @note
16
+ # - It won't fix weights unless all the sections of the ooze are present
17
+ # - This means that it doesn't fix section weights on stages,
18
+ # as shared sections could change order in other stages
11
19
  def add(name: nil, split: false, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
12
20
  sec_doc = section_class.new_doc(split: split)
13
21
  upsert!(sec_doc) do |section| #, pos: pos, before: before, after: after) do |section|
14
22
  section.heading = name
15
- if weight = scope_weight(pos: pos, before: before, after: after)
23
+ if weight = scope_weight(section, pos: pos, before: before, after: after)
16
24
  section.weight = weight
17
25
  end
18
26
  fix_weights!
@@ -20,12 +28,21 @@ module Ecoportal
20
28
  end
21
29
  end
22
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>]
23
39
  def get_by_type(type)
24
40
  ordered.select do |sec|
25
41
  sec.type == type
26
42
  end
27
43
  end
28
44
 
45
+ # @return [Array<Ecoportal::API::V2::Page::Section>]
29
46
  def get_by_heading(heading)
30
47
  ordered.select do |sec|
31
48
  value = heading == :unnamed ? nil : heading
@@ -34,6 +51,7 @@ module Ecoportal
34
51
  end
35
52
 
36
53
  # Gets all the sections between `sec1` and `sec2`
54
+ # @return [Array<Ecoportal::API::V2::Page::Section>]
37
55
  def between(sec1, sec2, included: false)
38
56
  sorted_secs = ordered
39
57
  pos1 = (sec1 = to_section(sec1)) && sorted_secs.index(sec1)
@@ -49,15 +67,21 @@ module Ecoportal
49
67
  end
50
68
 
51
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`
52
71
  def ordered
53
72
  self.sort_by.with_index do |section, index|
54
- (section.weight >= 9999) ? [index, index] : [section.weight, index]
73
+ [section.weight, index]
55
74
  end
56
75
  end
57
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
+
58
82
  private
59
83
 
60
- def scope_weight(pos: NOT_USED, before: NOT_USED, after: NOT_USED)
84
+ def scope_weight(section, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
61
85
  case
62
86
  when used_param?(pos)
63
87
  if pos = to_section(pos)
@@ -71,6 +95,11 @@ module Ecoportal
71
95
  if after = to_section(after)
72
96
  after.weight
73
97
  end
98
+ end.yield_self do |weight|
99
+ weight = ordered.reject do |sec|
100
+ sec.id == section.id
101
+ end.last&.weight
102
+ weight ||= section_class.const_get(:INITIAL_WEIGHT)
74
103
  end
75
104
  end
76
105
 
@@ -86,8 +115,10 @@ module Ecoportal
86
115
  end
87
116
 
88
117
  def fix_weights!
89
- ordered.each_with_index do |section, index|
90
- section.weight = index
118
+ unless self._parent.is_a?(Ecoportal::API::V2::Pages::PageStage)
119
+ ordered.each_with_index do |section, index|
120
+ section.weight = index
121
+ end
91
122
  end
92
123
  end
93
124
 
@@ -97,7 +128,6 @@ module Ecoportal
97
128
  return if pos < 0
98
129
  secs[pos]
99
130
  end
100
-
101
131
  end
102
132
  end
103
133
  end
@@ -17,19 +17,55 @@ 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|
23
30
  puts "Warning: section #{id} points to missing section #{sec_ids[i]}" if !sec
24
31
  fld && (!block_given? || yield(sec))
25
- end.sort_by {|sec| sec.weight}
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)
@@ -14,9 +20,9 @@ module Ecoportal
14
20
  end
15
21
 
16
22
  #def ordered
17
- # self.each_with_index.sort_by do |stage, index|
18
- # (stage.ordering >= 9999) ? [index, index] : [stage.ordering, index]
19
- # end.map(&:first)
23
+ # self.sort_by.with_index do |stage, index|
24
+ # [stage.ordering, index]
25
+ # end
20
26
  #end
21
27
 
22
28
  end
@@ -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,10 +24,20 @@ 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
33
+
34
+ def initialize(doc = [], parent: self, key: nil)
35
+ super(_doc_bug_fix(doc), parent: parent, key: key)
36
+ end
37
+
38
+ def ooze
39
+ self
40
+ end
31
41
 
32
42
  def as_update
33
43
  super.tap do |hash|
@@ -44,6 +54,35 @@ module Ecoportal
44
54
  self.stages.count > 0
45
55
  end
46
56
 
57
+ private
58
+
59
+ def _doc_bug_fix(hash)
60
+ hash.tap do |hash|
61
+ _fix_doc(hash["stages"], "flow_node_ids", "section_ids") if hash.key?("stages")
62
+ if hash.key?("sections")
63
+ _fix_doc(hash["sections"], "membrane_ids", "component_ids")
64
+ _fix_doc(hash["sections"], "left_membrane_ids", "left_component_ids")
65
+ _fix_doc(hash["sections"], "right_membrane_ids", "right_component_ids")
66
+ end
67
+ end
68
+ end
69
+
70
+ def _fix_doc(value, source, dest)
71
+ value.tap do |value|
72
+ case value
73
+ when Array
74
+ value.each {|v| _fix_doc(v, source, dest)}
75
+ when Hash
76
+ if value.key?(source) && !value.key?(dest)
77
+ value[dest] = value[source]
78
+ value.delete(source)
79
+ end
80
+ else
81
+ # Do nothing!
82
+ end
83
+ end
84
+ end
85
+
47
86
  end
48
87
  end
49
88
  end
@@ -57,3 +96,5 @@ require 'ecoportal/api/v2/page/section'
57
96
  require 'ecoportal/api/v2/page/sections'
58
97
  require 'ecoportal/api/v2/page/stage'
59
98
  require 'ecoportal/api/v2/page/stages'
99
+ require 'ecoportal/api/v2/page/force'
100
+ require 'ecoportal/api/v2/page/forces'
@@ -10,11 +10,56 @@ 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
17
17
 
18
+ # @return [Ecoportal::API::V2::Page::Stage]
19
+ def current_stage
20
+ if stage_id = current_stage_id
21
+ stages[stage_id]
22
+ end
23
+ end
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
+
18
63
  end
19
64
  end
20
65
  end
@@ -53,10 +53,9 @@ module Ecoportal
53
53
  def update(doc)
54
54
  body = get_body(doc) # , level: "page"
55
55
  # Launch only if there are changes
56
- if body && body["page"]
57
- id = get_id(doc)
58
- client.patch("/pages/#{CGI.escape(id)}", data: body)
59
- end
56
+ raise "Missing page object" unless body && body["page"]
57
+ id = get_id(doc)
58
+ client.patch("/pages/#{CGI.escape(id)}", data: body)
60
59
  end
61
60
 
62
61
  # Gets a `new` non-existing page via api with all the ids initialized.
@@ -82,8 +82,8 @@ module Ecoportal
82
82
  yield object
83
83
  end
84
84
 
85
- # break unless (cursor_id = data["cursor_id"])
86
- break if total == results
85
+ break if total <= results
86
+ break unless (cursor_id = data["cursor_id"])
87
87
  end
88
88
  self
89
89
  end
@@ -1,5 +1,5 @@
1
1
  module Ecoportal
2
2
  module API
3
- GEM2_VERSION = "0.8.11"
3
+ GEM2_VERSION = "0.8.15"
4
4
  end
5
5
  end