ecoportal-api-v2 0.8.5 → 0.8.9

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -25
  3. data/bin/console +1 -1
  4. data/ecoportal-api-v2.gemspec +5 -5
  5. data/lib/ecoportal/api-v2.rb +2 -2
  6. data/lib/ecoportal/api/common.v2.rb +8 -0
  7. data/lib/ecoportal/api/common/content.rb +1 -0
  8. data/lib/ecoportal/api/common/content/array_model.rb +8 -6
  9. data/lib/ecoportal/api/common/content/collection_model.rb +10 -4
  10. data/lib/ecoportal/api/common/content/double_model.rb +15 -4
  11. data/lib/ecoportal/api/common/content/hash_diff_patch.rb +31 -19
  12. data/lib/ecoportal/api/common/content/model_helpers.rb +36 -0
  13. data/lib/ecoportal/api/v2/page.rb +2 -0
  14. data/lib/ecoportal/api/v2/page/component.rb +33 -3
  15. data/lib/ecoportal/api/v2/page/component/action.rb +13 -5
  16. data/lib/ecoportal/api/v2/page/component/action_field.rb +37 -2
  17. data/lib/ecoportal/api/v2/page/component/chart_field.rb +43 -5
  18. data/lib/ecoportal/api/v2/page/component/chart_field/benchmark.rb +30 -0
  19. data/lib/ecoportal/api/v2/page/component/chart_field/config.rb +23 -0
  20. data/lib/ecoportal/api/v2/page/component/chart_field/frequency.rb +3 -4
  21. data/lib/ecoportal/api/v2/page/component/chart_field/heatmap.rb +1 -3
  22. data/lib/ecoportal/api/v2/page/component/chart_field/indicator.rb +4 -5
  23. data/lib/ecoportal/api/v2/page/component/chart_field/multiseries.rb +3 -5
  24. data/lib/ecoportal/api/v2/page/component/chart_field/sankey.rb +1 -3
  25. data/lib/ecoportal/api/v2/page/component/chart_field/serie.rb +3 -4
  26. data/lib/ecoportal/api/v2/page/component/chart_field/series_config.rb +5 -7
  27. data/lib/ecoportal/api/v2/page/component/chart_fr_field.rb +7 -5
  28. data/lib/ecoportal/api/v2/page/component/checklist_field.rb +1 -1
  29. data/lib/ecoportal/api/v2/page/component/checklist_item.rb +3 -2
  30. data/lib/ecoportal/api/v2/page/component/date_field.rb +71 -4
  31. data/lib/ecoportal/api/v2/page/component/file.rb +3 -2
  32. data/lib/ecoportal/api/v2/page/component/gauge_field.rb +2 -2
  33. data/lib/ecoportal/api/v2/page/component/geo_coordinates.rb +13 -0
  34. data/lib/ecoportal/api/v2/page/component/geo_field.rb +4 -1
  35. data/lib/ecoportal/api/v2/page/component/images_field.rb +57 -1
  36. data/lib/ecoportal/api/v2/page/component/people_field.rb +104 -6
  37. data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +34 -2
  38. data/lib/ecoportal/api/v2/page/component/reference_field.rb +32 -3
  39. data/lib/ecoportal/api/v2/page/component/selection_field.rb +71 -4
  40. data/lib/ecoportal/api/v2/page/component/selection_option.rb +12 -2
  41. data/lib/ecoportal/api/v2/page/component/tag_field.rb +31 -1
  42. data/lib/ecoportal/api/v2/page/components.rb +8 -3
  43. data/lib/ecoportal/api/v2/page/permission_flags.rb +67 -0
  44. data/lib/ecoportal/api/v2/page/permit.rb +14 -0
  45. data/lib/ecoportal/api/v2/page/section.rb +65 -5
  46. data/lib/ecoportal/api/v2/page/sections.rb +64 -6
  47. data/lib/ecoportal/api/v2/page/stage.rb +11 -3
  48. data/lib/ecoportal/api/v2/page/stages.rb +7 -7
  49. data/lib/ecoportal/api/v2/pages/page_stage.rb +3 -3
  50. data/lib/ecoportal/api/v2_version.rb +5 -0
  51. metadata +16 -10
  52. data/lib/ecoportal/api/common.rb +0 -18
  53. data/lib/ecoportal/api/v2/version.rb +0 -7
@@ -4,11 +4,22 @@ module Ecoportal
4
4
  class Page
5
5
  class Component
6
6
  class SelectionField < Page::Component
7
- passthrough :multiple, :flat
8
- passthrough :other, :other_desc
7
+ passboolean :multiple, :flat, :other
8
+ passthrough :other_desc
9
+ passthrough :data_type
9
10
 
10
11
  embeds_many :options, klass: "Ecoportal::API::V2::Page::Component::SelectionOption", order_key: :weight
11
12
 
13
+ def numeric!(&block)
14
+ ordered_options.each {|opt| opt.numeric!(&block)}
15
+ self.data_type = "num"
16
+ end
17
+
18
+ def text!(&block)
19
+ ordered_options.each {|opt| opt.text!(&block)}
20
+ self.data_type = "str"
21
+ end
22
+
12
23
  def select(value)
13
24
  opt = options.find {|opt| opt.value == value}
14
25
  sel = selected
@@ -33,8 +44,8 @@ module Ecoportal
33
44
  end
34
45
  end
35
46
 
36
- def add_option(name:, value:, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
37
- opt_doc = options.items_class.new_doc
47
+ def add_option(value:, name: nil, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
48
+ opt_doc = options.items_class.new_doc
38
49
  options.upsert!(opt_doc, pos: pos, before: before, after: after) do |option|
39
50
  option.name = name
40
51
  option.value = value
@@ -52,8 +63,64 @@ module Ecoportal
52
63
  end.map(&:first)
53
64
  end
54
65
 
66
+ # Quick config helper
67
+ # @param conf [Symbol, Array<Symbol>]
68
+ # - `:flat` to display in flat mode
69
+ # - `:multiple` to allow multiple selection
70
+ # - `:single` to set to singular selection
71
+ # - `:other` to enable `other` button
72
+ # - `:options` to add options (`Hash<value, name>`)
73
+ # - `:type` to define the type
74
+ # - `:num`
75
+ # - `:str`
76
+ def configure(*conf)
77
+ conf.each_with_object([]) do |cnf, unused|
78
+ case cnf
79
+ when :flat
80
+ self.flat = true
81
+ when :multiple
82
+ self.multiple = true
83
+ when :single
84
+ self.multiple = false
85
+ when :other
86
+ self.other = true
87
+ when Hash
88
+ supported = [:flat, :options, :type]
89
+ unless (rest = hash_except(cnf.dup, *supported)).empty?
90
+ unused.push(rest)
91
+ end
92
+
93
+ if cnf.key?(:flat) then self.flat = cnf[:flat] end
94
+ if cnf.key?(:options)
95
+ if opts = cnf[:options]
96
+ configure_options opts
97
+ end
98
+ end
99
+ if cnf.key?(:type)
100
+ if cnf[:type] == :str
101
+ self.text!
102
+ elsif cnf[:type] == :num
103
+ self.numeric!
104
+ else
105
+ # Unknown type
106
+ end
107
+ end
108
+ else
109
+ unused.push(cnf)
110
+ end
111
+ end.yield_self do |unused|
112
+ super(*unused)
113
+ end
114
+ end
115
+
55
116
  private
56
117
 
118
+ def configure_options(opts)
119
+ opts.each do |val, nm|
120
+ add_option(value: val, name: nm)
121
+ end
122
+ end
123
+
57
124
  def fix_option_weights!
58
125
  ordered_options.each_with_index do |option, index|
59
126
  option.weight = index
@@ -4,7 +4,7 @@ module Ecoportal
4
4
  class Page
5
5
  class Component
6
6
  class SelectionOption < Common::Content::DoubleModel
7
-
7
+
8
8
  class << self
9
9
  def new_doc
10
10
  {
@@ -16,7 +16,17 @@ module Ecoportal
16
16
 
17
17
  passkey :id
18
18
  passthrough :patch_ver, :name, :value
19
- passthrough :weight, :selected
19
+ passthrough :weight
20
+ passboolean :selected
21
+
22
+ def numeric!
23
+ self.value = block_given?? yield(value) : value.to_i
24
+ end
25
+
26
+ def text!
27
+ self.value = block_given?? yield(value) : value.to_s
28
+ end
29
+
20
30
  end
21
31
  end
22
32
  end
@@ -4,8 +4,38 @@ module Ecoportal
4
4
  class Page
5
5
  class Component
6
6
  class TagField < Page::Component
7
- passthrough :single_select, :use_defaults
7
+ passboolean :single_select, :use_defaults
8
8
  passthrough :tag_tree_id, :button_text
9
+
10
+ # Quick config helper
11
+ # @param conf [Symbol, Array<Symbol>]
12
+ # - `:multiple` to allow multiple selection
13
+ # - `:single` to set to singular selection
14
+ # - `:default_tag` to prepopulate using users's `default_tag`
15
+ # - `:button_text` to define the button description
16
+ def configure(*conf)
17
+ conf.each_with_object([]) do |cnf, unused|
18
+ case cnf
19
+ when :single
20
+ self.single_select = true
21
+ when :multiple
22
+ self.single_select = false
23
+ when :default_tag
24
+ self.use_defaults = true
25
+ when Hash
26
+ supported = [:button_text]
27
+ unless (rest = hash_except(cnf.dup, *supported)).empty?
28
+ unused.push(rest)
29
+ end
30
+ if cnf.key?(:button_text) then self.button_text = cnf[:button_text] end
31
+ else
32
+ unused.push(cnf)
33
+ end
34
+ end.yield_self do |unused|
35
+ super(*unused)
36
+ end
37
+ end
38
+
9
39
  end
10
40
  end
11
41
  end
@@ -13,6 +13,12 @@ module Ecoportal
13
13
 
14
14
  order_matters = true
15
15
 
16
+ def get_by_id(id)
17
+ self.find do |comp|
18
+ comp.id == id
19
+ end
20
+ end
21
+
16
22
  def get_by_type(type)
17
23
  self.select do |comp|
18
24
  comp.type.downcase == type.to_s.strip.downcase
@@ -21,10 +27,9 @@ module Ecoportal
21
27
 
22
28
  def get_by_name(name, type: nil)
23
29
  pool = type ? get_by_type(type) : self
24
-
25
30
  pool.select do |comp|
26
- comp.label.to_s.strip.downcase == name.to_s.strip.downcase
27
- end.first
31
+ same_string?(comp.label, name)
32
+ end
28
33
  end
29
34
 
30
35
  def add(label:, type:)
@@ -0,0 +1,67 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class PermissionFlags < Common::Content::DoubleModel
6
+ class << self
7
+ def new_doc
8
+ {
9
+ "can_restructure" => false,
10
+ "can_configure" => false,
11
+ "can_permission" => false,
12
+ "can_create_actions" => false,
13
+ "can_administrate_actions" => false,
14
+ "subscribed" => false,
15
+ "subscribed_to_tasks" => false
16
+ }
17
+ end
18
+ end
19
+
20
+ passboolean :can_restructure, :can_configure
21
+ passboolean :can_permission, :can_create_actions, :can_administrate_actions
22
+ passboolean :subscribed, :subscribed_to_tasks
23
+
24
+ def reset!
25
+ doc.merge!(self.class.new_doc)
26
+ end
27
+
28
+ # Quick config helper
29
+ # @param conf [Symbol, Array<Symbol>]
30
+ # - `:restructure`
31
+ # - `:configure`
32
+ # - `:can_permission`
33
+ # - `:create_actions`
34
+ # - `:admin_actions`
35
+ # - `:subscribed`
36
+ # - `:subscribed_to_tasks`
37
+ def configure(*conf)
38
+ conf.each_with_object([]) do |cnf, unused|
39
+ case cnf
40
+ when :restructure
41
+ self.can_restructure = true
42
+ when :configure
43
+ self.can_configure = true
44
+ when :can_permission
45
+ self.can_permission = true
46
+ when :create_actions
47
+ self.can_create_actions = true
48
+ when :admin_actions
49
+ self.can_administrate_actions = true
50
+ when :subscribed
51
+ self.subscribed = true
52
+ when :subscribed_to_tasks
53
+ self.subscribed_to_tasks = true
54
+ else
55
+ unused.push(cnf)
56
+ end
57
+ end.yield_self do |unused|
58
+ raise "Unknown configuaration options #{unused}" unless unused.empty?
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,14 @@
1
+ module Ecoportal
2
+ module API
3
+ class V2
4
+ class Page
5
+ class Permit < Common::Content::DoubleModel
6
+ passkey :id
7
+ passthrough :patch_ver
8
+ passthrough :user_id, :user_name
9
+ passthrough :editable, :flags
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -8,7 +8,7 @@ module Ecoportal
8
8
  {
9
9
  "id" => new_uuid,
10
10
  "type" => split ? "split" : "content",
11
- "weight" => 9999
11
+ "weight" => 800
12
12
  }.tap do |out|
13
13
  component_ids = if split
14
14
  {
@@ -44,10 +44,70 @@ module Ecoportal
44
44
  all_component_ids.include?(id)
45
45
  end
46
46
 
47
- def components
48
- fld_ids = all_component_ids
49
- root.components.values_at(*fld_ids).select.with_index do |fld, i|
50
- puts "Warning: field #{id} points to missing field #{fld_ids[i]}" if !fld
47
+ def components(side: nil)
48
+ case side
49
+ when :right
50
+ components_right
51
+ when :left
52
+ components_left
53
+ when NilClass
54
+ components_by_id(*all_component_ids)
55
+ else
56
+ raise "Side should be one of [nil, :right, :left]. Given: #{side}"
57
+ end
58
+ end
59
+
60
+ def components_left
61
+ raise "You are trying to retrieve side components in a Split Section" unless split?
62
+ components_by_id(*left_component_ids)
63
+ end
64
+
65
+ def components_right
66
+ raise "You are trying to retrieve side components in a Split Section" unless split?
67
+ components_by_id(*right_component_ids)
68
+ end
69
+
70
+ # Adds `field` to the section
71
+ # @note
72
+ # - To the specified `side`, when split section (default `:left`)
73
+ # - To the end if `after` is not specified
74
+ # - If `after` is specified, it searches field
75
+ # - On the specific `side`, if specified (and split section)
76
+ # - And adds the `field` after it, when found, or at the end if `after` is not found
77
+ # @param field [Ecoportal::API::V2::Page::Component] the field to be added.
78
+ def add_component(field, after: nil, side: nil)
79
+ raise "field should be a Ecoportal::API::V2::Page::Component. Given: #{field.class}" unless field.is_a?(Ecoportal::API::V2::Page::Component)
80
+ if field.section == self
81
+ raise "Field with id '#{field.id}' already belongs to this section"
82
+ elsif sec = field.section
83
+ # Field belongs to another section
84
+ raise "Field with id '#{field.id}' belongs to section '#{sec.heading || "Unnamed"}' (id: '#{sec.id}')"
85
+ end
86
+
87
+ if split?
88
+ ids_ary = side == :right ? right_component_ids : left_component_ids
89
+ fields = components(side: side || :left)
90
+ else
91
+ ids_ary = component_ids
92
+ fields = components
93
+ end
94
+ if after
95
+ after_fld = fields.find do |fld|
96
+ found = nil
97
+ found ||= !!after if after.is_a?(Ecoportal::API::V2::Page::Component)
98
+ found ||= fld.id == after
99
+ found ||= same_string?(fld.label, after)
100
+ end
101
+ end
102
+ ids_ary.insert_one(field.id, after: after_fld&.id)
103
+ self
104
+ end
105
+
106
+ private
107
+
108
+ def components_by_id(*ids)
109
+ root.components.values_at(*ids).select.with_index do |fld, i|
110
+ puts "Warning: field id #{ids[i]} points to missing field" if !fld
51
111
  fld && (!block_given? || yield(fld))
52
112
  end
53
113
  end
@@ -7,26 +7,84 @@ module Ecoportal
7
7
 
8
8
  self.klass = :section_class
9
9
 
10
+ # Creates a new `section`
10
11
  def add(name: nil, split: false, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
11
12
  sec_doc = section_class.new_doc(split: split)
12
- upsert!(sec_doc, pos: pos, before: before, after: after) do |section|
13
+ upsert!(sec_doc) do |section| #, pos: pos, before: before, after: after) do |section|
13
14
  section.heading = name
14
- if prev = previous_section(section)
15
- section.weight = prev.weight
15
+ if weight = scope_weight(pos: pos, before: before, after: after)
16
+ section.weight = weight
16
17
  end
18
+ fix_weights!
17
19
  yield(section) if block_given?
18
- #fix_weights! # a server bug prevents to set the weight of existing sections
19
20
  end
20
21
  end
21
22
 
23
+ def get_by_type(type)
24
+ ordered.select do |sec|
25
+ sec.type == type
26
+ end
27
+ end
28
+
29
+ def get_by_heading(heading)
30
+ ordered.select do |sec|
31
+ value = heading == :unnamed ? nil : heading
32
+ same_string?(sec.heading, value)
33
+ end
34
+ end
35
+
36
+ # Gets all the sections between `sec1` and `sec2`
37
+ def between(sec1, sec2, included: false)
38
+ sorted_secs = ordered
39
+ pos1 = (sec1 = to_section(sec1)) && sorted_secs.index(sec1)
40
+ pos2 = (sec2 = to_section(sec2)) && sorted_secs.index(sec2)
41
+ if included
42
+ pos1 = pos1 ? pos1 : 0
43
+ pos2 = pos2 ? pos2 : -1
44
+ else
45
+ pos1 = pos1 ? (pos1 + 1) : 0
46
+ pos2 = pos2 ? (pos2 - 1) : -1
47
+ end
48
+ sorted_secs[pos1..pos2]
49
+ end
50
+
51
+ # Gets the sections ordered by `weight` (as they appear in the page)
22
52
  def ordered
23
- each_with_index.sort_by do |section, index|
53
+ self.sort_by.with_index do |section, index|
24
54
  (section.weight >= 9999) ? [index, index] : [section.weight, index]
25
- end.map(&:first)
55
+ end
26
56
  end
27
57
 
28
58
  private
29
59
 
60
+ def scope_weight(pos: NOT_USED, before: NOT_USED, after: NOT_USED)
61
+ case
62
+ when used_param?(pos)
63
+ if pos = to_section(pos)
64
+ pos.weight - 1
65
+ end
66
+ when used_param?(before)
67
+ if before = to_section(before)
68
+ before.weight - 1
69
+ end
70
+ when used_param?(after)
71
+ if after = to_section(after)
72
+ after.weight
73
+ end
74
+ end
75
+ end
76
+
77
+ def to_section(value)
78
+ case value
79
+ when Ecoportal::API::V2::Page::Section
80
+ value
81
+ when Numeric
82
+ ordered[value]
83
+ else
84
+ get_by_heading(value).first
85
+ end
86
+ end
87
+
30
88
  def fix_weights!
31
89
  ordered.each_with_index do |section, index|
32
90
  section.weight = index