ecoportal-api-v2 0.8.5 → 0.8.9

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