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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +60 -25
- data/bin/console +1 -1
- data/ecoportal-api-v2.gemspec +5 -5
- data/lib/ecoportal/api-v2.rb +2 -2
- data/lib/ecoportal/api/common.v2.rb +8 -0
- data/lib/ecoportal/api/common/content.rb +1 -0
- data/lib/ecoportal/api/common/content/array_model.rb +8 -6
- data/lib/ecoportal/api/common/content/collection_model.rb +10 -4
- data/lib/ecoportal/api/common/content/double_model.rb +15 -4
- data/lib/ecoportal/api/common/content/hash_diff_patch.rb +31 -19
- data/lib/ecoportal/api/common/content/model_helpers.rb +36 -0
- data/lib/ecoportal/api/v2/page.rb +2 -0
- data/lib/ecoportal/api/v2/page/component.rb +33 -3
- data/lib/ecoportal/api/v2/page/component/action.rb +13 -5
- data/lib/ecoportal/api/v2/page/component/action_field.rb +37 -2
- data/lib/ecoportal/api/v2/page/component/chart_field.rb +43 -5
- data/lib/ecoportal/api/v2/page/component/chart_field/benchmark.rb +30 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/config.rb +23 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/frequency.rb +3 -4
- data/lib/ecoportal/api/v2/page/component/chart_field/heatmap.rb +1 -3
- data/lib/ecoportal/api/v2/page/component/chart_field/indicator.rb +4 -5
- data/lib/ecoportal/api/v2/page/component/chart_field/multiseries.rb +3 -5
- data/lib/ecoportal/api/v2/page/component/chart_field/sankey.rb +1 -3
- data/lib/ecoportal/api/v2/page/component/chart_field/serie.rb +3 -4
- data/lib/ecoportal/api/v2/page/component/chart_field/series_config.rb +5 -7
- data/lib/ecoportal/api/v2/page/component/chart_fr_field.rb +7 -5
- data/lib/ecoportal/api/v2/page/component/checklist_field.rb +1 -1
- data/lib/ecoportal/api/v2/page/component/checklist_item.rb +3 -2
- data/lib/ecoportal/api/v2/page/component/date_field.rb +71 -4
- data/lib/ecoportal/api/v2/page/component/file.rb +3 -2
- data/lib/ecoportal/api/v2/page/component/gauge_field.rb +2 -2
- data/lib/ecoportal/api/v2/page/component/geo_coordinates.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/geo_field.rb +4 -1
- data/lib/ecoportal/api/v2/page/component/images_field.rb +57 -1
- data/lib/ecoportal/api/v2/page/component/people_field.rb +104 -6
- data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +34 -2
- data/lib/ecoportal/api/v2/page/component/reference_field.rb +32 -3
- data/lib/ecoportal/api/v2/page/component/selection_field.rb +71 -4
- data/lib/ecoportal/api/v2/page/component/selection_option.rb +12 -2
- data/lib/ecoportal/api/v2/page/component/tag_field.rb +31 -1
- data/lib/ecoportal/api/v2/page/components.rb +8 -3
- data/lib/ecoportal/api/v2/page/permission_flags.rb +67 -0
- data/lib/ecoportal/api/v2/page/permit.rb +14 -0
- data/lib/ecoportal/api/v2/page/section.rb +65 -5
- data/lib/ecoportal/api/v2/page/sections.rb +64 -6
- data/lib/ecoportal/api/v2/page/stage.rb +11 -3
- data/lib/ecoportal/api/v2/page/stages.rb +7 -7
- data/lib/ecoportal/api/v2/pages/page_stage.rb +3 -3
- data/lib/ecoportal/api/v2_version.rb +5 -0
- metadata +16 -10
- data/lib/ecoportal/api/common.rb +0 -18
- 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
|
-
|
8
|
-
passthrough :
|
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(
|
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
|
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
|
-
|
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
|
27
|
-
end
|
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
|
@@ -8,7 +8,7 @@ module Ecoportal
|
|
8
8
|
{
|
9
9
|
"id" => new_uuid,
|
10
10
|
"type" => split ? "split" : "content",
|
11
|
-
"weight" =>
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
13
|
+
upsert!(sec_doc) do |section| #, pos: pos, before: before, after: after) do |section|
|
13
14
|
section.heading = name
|
14
|
-
if
|
15
|
-
section.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
|
-
|
53
|
+
self.sort_by.with_index do |section, index|
|
24
54
|
(section.weight >= 9999) ? [index, index] : [section.weight, index]
|
25
|
-
end
|
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
|