ecoportal-api-oozes 0.5.5
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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +3 -0
- data/.rubocop.yml +55 -0
- data/.travis.yml +5 -0
- data/.yardopts +10 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +20 -0
- data/Rakefile +27 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ecoportal-api-oozes.gemspec +31 -0
- data/lib/ecoportal/api-oozes.rb +10 -0
- data/lib/ecoportal/api/common.rb +18 -0
- data/lib/ecoportal/api/common/content.rb +18 -0
- data/lib/ecoportal/api/common/content/array_model.rb +287 -0
- data/lib/ecoportal/api/common/content/class_helpers.rb +111 -0
- data/lib/ecoportal/api/common/content/client.rb +40 -0
- data/lib/ecoportal/api/common/content/collection_model.rb +223 -0
- data/lib/ecoportal/api/common/content/doc_helpers.rb +67 -0
- data/lib/ecoportal/api/common/content/double_model.rb +334 -0
- data/lib/ecoportal/api/common/content/hash_diff_patch.rb +162 -0
- data/lib/ecoportal/api/common/content/string_digest.rb +22 -0
- data/lib/ecoportal/api/common/content/wrapped_response.rb +42 -0
- data/lib/ecoportal/api/v2.rb +48 -0
- data/lib/ecoportal/api/v2/page.rb +30 -0
- data/lib/ecoportal/api/v2/page/component.rb +105 -0
- data/lib/ecoportal/api/v2/page/component/action.rb +17 -0
- data/lib/ecoportal/api/v2/page/component/action_field.rb +16 -0
- data/lib/ecoportal/api/v2/page/component/checklist_field.rb +16 -0
- data/lib/ecoportal/api/v2/page/component/checklist_item.rb +15 -0
- data/lib/ecoportal/api/v2/page/component/date_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/file.rb +16 -0
- data/lib/ecoportal/api/v2/page/component/files_field.rb +14 -0
- data/lib/ecoportal/api/v2/page/component/gauge_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/geo_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/image.rb +16 -0
- data/lib/ecoportal/api/v2/page/component/images_field.rb +14 -0
- data/lib/ecoportal/api/v2/page/component/law_field.rb +12 -0
- data/lib/ecoportal/api/v2/page/component/number_field.rb +12 -0
- data/lib/ecoportal/api/v2/page/component/people_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/reference_field.rb +12 -0
- data/lib/ecoportal/api/v2/page/component/rich_text_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/selection_field.rb +18 -0
- data/lib/ecoportal/api/v2/page/component/selection_option.rb +15 -0
- data/lib/ecoportal/api/v2/page/component/signature_field.rb +14 -0
- data/lib/ecoportal/api/v2/page/component/tag_field.rb +12 -0
- data/lib/ecoportal/api/v2/page/components.rb +20 -0
- data/lib/ecoportal/api/v2/page/section.rb +36 -0
- data/lib/ecoportal/api/v2/page/sections.rb +14 -0
- data/lib/ecoportal/api/v2/page/stage.rb +16 -0
- data/lib/ecoportal/api/v2/page/stages.rb +14 -0
- data/lib/ecoportal/api/v2/pages.rb +63 -0
- data/lib/ecoportal/api/v2/register.rb +36 -0
- data/lib/ecoportal/api/v2/registers.rb +35 -0
- data/lib/ecoportal/api/v2/template.rb +10 -0
- data/lib/ecoportal/api/v2/version.rb +7 -0
- metadata +219 -0
@@ -0,0 +1,162 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module Content
|
5
|
+
module HashDiffPatch
|
6
|
+
ID_KEYS = %w[id]
|
7
|
+
META_KEYS = %w[id patch_ver]
|
8
|
+
NO_CHANGES = "%not-changed!%"
|
9
|
+
extend Content::DocHelpers
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# The `patch data` is built as follows:
|
13
|
+
# 1. detect changes that have occurred translate into one `operation` of `OP_TYPE`:
|
14
|
+
# * `changed`: meaning that the object has changed (existed and has not been removed)
|
15
|
+
# * `delete`: the object has been removed
|
16
|
+
# * `new`: the object is new
|
17
|
+
# 2. at the level of the target object of the model, the object is opened for change
|
18
|
+
# with `id` and `operation` as follows:
|
19
|
+
#
|
20
|
+
# ```json
|
21
|
+
# {
|
22
|
+
# "id": "objectID",
|
23
|
+
# "operation": "OP_TYPE",
|
24
|
+
# "data": {
|
25
|
+
# "patch_ver": "prev_patch_ver_+1",
|
26
|
+
# "property": "value",
|
27
|
+
# "...": "..."
|
28
|
+
# }
|
29
|
+
# }
|
30
|
+
# ```
|
31
|
+
# 3. the `data` property holds the specific changes of the object
|
32
|
+
# - the `patch_ver` (compulsory) is **incremental** (for data integrity)
|
33
|
+
# - the properties that have changed
|
34
|
+
# @param a [Hash] current hash model
|
35
|
+
# @param b [Hash] previous hash model
|
36
|
+
# @return [Hash] a `patch data`
|
37
|
+
def patch_diff(a, b)
|
38
|
+
case
|
39
|
+
when b.is_a?(Hash) && !empty?(b) && empty?(a)
|
40
|
+
patch_delete(b)
|
41
|
+
when a.is_a?(Hash) && !empty?(a) && empty?(b)
|
42
|
+
patch_new(a)
|
43
|
+
when a.is_a?(Hash) && b.is_a?(Hash)
|
44
|
+
patch_update(a, b)
|
45
|
+
when any_array?(a, b)
|
46
|
+
patch_data_array(a, b)
|
47
|
+
else
|
48
|
+
a
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def patch_data(a, b = nil)
|
55
|
+
{}.tap do |data_hash|
|
56
|
+
a.each do |key, a_value|
|
57
|
+
b_value = b[key] if b_has_key = b && b.key?(key)
|
58
|
+
is_meta_key = META_KEYS.include?(key)
|
59
|
+
skip_equals = b_has_key && a_value == b_value
|
60
|
+
next if is_meta_key || skip_equals
|
61
|
+
data_hash[key] = patch_diff(a_value, b_value)
|
62
|
+
data_hash.delete(key) if data_hash[key] == NO_CHANGES
|
63
|
+
end
|
64
|
+
if (data_hash.keys - META_KEYS).empty?
|
65
|
+
return NO_CHANGES
|
66
|
+
else
|
67
|
+
patch_ver = (b && b["patch_ver"]) || 1
|
68
|
+
data_hash["patch_ver"] = patch_ver
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def patch_delete(b)
|
74
|
+
return NO_CHANGES unless b.is_a?(Hash) && id = get_id(b, exception: false)
|
75
|
+
{
|
76
|
+
"id" => id,
|
77
|
+
"operation" => "delete"
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def patch_new(a)
|
82
|
+
return NO_CHANGES unless a.is_a?(Hash) && id = get_id(a, exception: false)
|
83
|
+
{
|
84
|
+
"id" => id,
|
85
|
+
"operation" => "new",
|
86
|
+
"data" => patch_data(a)
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def patch_update(a, b)
|
91
|
+
return NO_CHANGES unless a.is_a?(Hash) && id = get_id(a, exception: false)
|
92
|
+
{
|
93
|
+
"id" => id,
|
94
|
+
"operation" => "changed",
|
95
|
+
"data" => patch_data(a, b)
|
96
|
+
}.tap do |update_hash|
|
97
|
+
return nil unless update_hash["data"] != NO_CHANGES
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def patch_data_array(a, b)
|
102
|
+
a ||= []; b ||= []
|
103
|
+
if !nested_array?(a, b)
|
104
|
+
if a.length == b.length && (a & b).length == b.length
|
105
|
+
NO_CHANGES
|
106
|
+
else
|
107
|
+
a
|
108
|
+
end
|
109
|
+
else
|
110
|
+
a_ids = array_ids(a)
|
111
|
+
b_ids = array_ids(b)
|
112
|
+
|
113
|
+
del_ids = b_ids - a_ids
|
114
|
+
oth_ids = b_ids & a_ids
|
115
|
+
new_ids = a_ids - b_ids
|
116
|
+
|
117
|
+
arr_delete = del_ids.map do |id|
|
118
|
+
patch_delete(array_id_item(b, id))
|
119
|
+
end
|
120
|
+
|
121
|
+
arr_update = oth_ids.map do |id|
|
122
|
+
patch_update(array_id_item(a, id), array_id_item(b, id))
|
123
|
+
end
|
124
|
+
|
125
|
+
arr_new = new_ids.map do |id|
|
126
|
+
patch_new(array_id_item(a, id))
|
127
|
+
end
|
128
|
+
|
129
|
+
(arr_delete.concat(arr_update).concat(arr_new)).tap do |patch_array|
|
130
|
+
# remove data with no `id`
|
131
|
+
patch_array.reject! {|item| !item.is_a?(Hash)}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def nested_array?(*arr)
|
137
|
+
case
|
138
|
+
when arr.length > 1
|
139
|
+
arr.any? {|a| nested_array?(a)}
|
140
|
+
when arr.length == 1
|
141
|
+
arr = arr.first
|
142
|
+
arr.any? {|item| item.is_a?(Hash)}
|
143
|
+
else
|
144
|
+
false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def any_array?(a, b)
|
149
|
+
[a, b].any? {|item| item.is_a?(Array)}
|
150
|
+
end
|
151
|
+
|
152
|
+
def empty?(a)
|
153
|
+
bool = !a
|
154
|
+
bool ||= a.respond_to?(:empty?) && a.empty?
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module Ecoportal
|
4
|
+
module API
|
5
|
+
module Common
|
6
|
+
module Content
|
7
|
+
module StringDigest
|
8
|
+
MAX_HASH_LABEL = 64
|
9
|
+
|
10
|
+
# Calculates the Hash of the field based on label
|
11
|
+
def hash_label(str)
|
12
|
+
return false unless str
|
13
|
+
label = str.downcase.gsub(/[^A-Za-z]+/,"-").slice(0, MAX_HASH_LABEL)
|
14
|
+
return false unless label.length >= 3
|
15
|
+
return "z" + Digest::MD5.hexdigest(label).slice(0, 8);
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module Content
|
5
|
+
class WrappedResponse < Common::WrappedResponse
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_reader :response, :result
|
9
|
+
|
10
|
+
def initialize(response, klass, key: nil)
|
11
|
+
@response = response
|
12
|
+
@klass = klass
|
13
|
+
@key = key
|
14
|
+
|
15
|
+
if @response.success?
|
16
|
+
@result =
|
17
|
+
if data.is_a?(Array)
|
18
|
+
data.map do |doc|
|
19
|
+
@klass.new(doc)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
@klass.new(data)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def data
|
28
|
+
return @data if instance_variable_defined?(:@data)
|
29
|
+
@data = (response.body || {})["data"]
|
30
|
+
@data = @data[key] if @key && @data
|
31
|
+
@data
|
32
|
+
end
|
33
|
+
|
34
|
+
def body
|
35
|
+
data.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
# @attr_reader client [Common::Client] a `Common::Client` object that holds the configuration of the api connection.
|
4
|
+
# @attr_reader logger [Logger] the logger.
|
5
|
+
class V2
|
6
|
+
extend Common::BaseClass
|
7
|
+
include Common::Logging
|
8
|
+
|
9
|
+
VERSION = "v2"
|
10
|
+
|
11
|
+
class_resolver :registers_class, "Ecoportal::API::V2::Registers"
|
12
|
+
class_resolver :pages_class, "Ecoportal::API::V2::Pages"
|
13
|
+
|
14
|
+
attr_reader :client, :logger
|
15
|
+
|
16
|
+
# Creates an `V2` object to scope version specific api requests.
|
17
|
+
# @param api_key [String] the key version to stablish the api connection.
|
18
|
+
# @param host [String] api server domain.
|
19
|
+
# @param logger [Logger] an object with `Logger` interface to generate logs.
|
20
|
+
def initialize(api_key, host: "live.ecoportal.com", logger: default_logger)
|
21
|
+
@logger = logger
|
22
|
+
@client = Common::Content::Client.new(
|
23
|
+
api_key: api_key,
|
24
|
+
host: host,
|
25
|
+
version: self.class::VERSION,
|
26
|
+
logger: @logger
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Obtain specific object for schema api requests.
|
31
|
+
# @return [Registers] an instance object ready to make registers api requests.
|
32
|
+
def registers
|
33
|
+
registers_class.new(client)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Obtain specific object for pages api requests.
|
37
|
+
# @return [Pages] an instance object ready to make pages api requests.
|
38
|
+
def pages
|
39
|
+
pages_class.new(client)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
require 'ecoportal/api/v2/registers'
|
47
|
+
require 'ecoportal/api/v2/pages'
|
48
|
+
#require 'ecoportal/api/v2/stages'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
class V2
|
4
|
+
class Page < Common::Content::DoubleModel
|
5
|
+
passkey :id
|
6
|
+
passthrough :patch_ver
|
7
|
+
passthrough :name, :template_id
|
8
|
+
passarray :base_tags, :tags, order_matters: false
|
9
|
+
passthrough :time_zone
|
10
|
+
passdate :created_at, :updated_at, read_only: true
|
11
|
+
passthrough :can
|
12
|
+
|
13
|
+
class_resolver :components_class, "Ecoportal::API::V2::Page::Components"
|
14
|
+
class_resolver :sections_class, "Ecoportal::API::V2::Page::Sections"
|
15
|
+
class_resolver :stages_class, "Ecoportal::API::V2::Page::Stages"
|
16
|
+
|
17
|
+
embeds_one :components, multiple: true, klass: :components_class
|
18
|
+
embeds_one :sections, multiple: true, klass: :sections_class
|
19
|
+
embeds_one :stages, multiple: true, klass: :stages_class
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'ecoportal/api/v2/page/component'
|
26
|
+
require 'ecoportal/api/v2/page/components'
|
27
|
+
require 'ecoportal/api/v2/page/section'
|
28
|
+
require 'ecoportal/api/v2/page/sections'
|
29
|
+
require 'ecoportal/api/v2/page/stage'
|
30
|
+
require 'ecoportal/api/v2/page/stages'
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
class V2
|
4
|
+
class Page
|
5
|
+
class Component < Common::Content::DoubleModel
|
6
|
+
extend Ecoportal::API::Common::Content::StringDigest
|
7
|
+
|
8
|
+
class_resolver :tag_field_class, "Ecoportal::API::V2::Page::Component::TagField"
|
9
|
+
class_resolver :geo_field_class, "Ecoportal::API::V2::Page::Component::GeoField"
|
10
|
+
class_resolver :selection_field_class, "Ecoportal::API::V2::Page::Component::SelectionField"
|
11
|
+
class_resolver :date_field_class, "Ecoportal::API::V2::Page::Component::DateField"
|
12
|
+
class_resolver :number_field_class, "Ecoportal::API::V2::Page::Component::NumberField"
|
13
|
+
class_resolver :gauge_field_class, "Ecoportal::API::V2::Page::Component::GaugeField"
|
14
|
+
class_resolver :plain_text_field_class, "Ecoportal::API::V2::Page::Component::PlainTextField"
|
15
|
+
class_resolver :rich_text_field_class, "Ecoportal::API::V2::Page::Component::RichTextField"
|
16
|
+
class_resolver :people_field_class, "Ecoportal::API::V2::Page::Component::PeopleField"
|
17
|
+
class_resolver :checklist_field_class, "Ecoportal::API::V2::Page::Component::ChecklistField"
|
18
|
+
class_resolver :action_field_class, "Ecoportal::API::V2::Page::Component::ActionField"
|
19
|
+
class_resolver :files_field_class, "Ecoportal::API::V2::Page::Component::FilesField"
|
20
|
+
class_resolver :images_field_class, "Ecoportal::API::V2::Page::Component::ImagesField"
|
21
|
+
class_resolver :signature_field_class, "Ecoportal::API::V2::Page::Component::SignatureField"
|
22
|
+
class_resolver :reference_field_class, "Ecoportal::API::V2::Page::Component::ReferenceField"
|
23
|
+
class_resolver :law_field_class, "Ecoportal::API::V2::Page::Component::LawField"
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def get_class(doc)
|
27
|
+
if doc.is_a?(Hash)
|
28
|
+
case doc["type"]
|
29
|
+
when "tag_field"
|
30
|
+
tag_field_class
|
31
|
+
when "geo"
|
32
|
+
geo_field_class
|
33
|
+
when "select"
|
34
|
+
selection_field_class
|
35
|
+
when "date"
|
36
|
+
date_field_class
|
37
|
+
when "number"
|
38
|
+
number_field_class
|
39
|
+
when "gauge"
|
40
|
+
gauge_field_class
|
41
|
+
when "plain_text"
|
42
|
+
plain_text_field_class
|
43
|
+
when "rich_text"
|
44
|
+
rich_text_field_class
|
45
|
+
when "people"
|
46
|
+
people_field_class
|
47
|
+
when "checklist"
|
48
|
+
checklist_field_class
|
49
|
+
when "page_action"
|
50
|
+
action_field_class
|
51
|
+
when "file"
|
52
|
+
files_field_class
|
53
|
+
when "image_gallery"
|
54
|
+
images_field_class
|
55
|
+
when "signature"
|
56
|
+
signature_field_class
|
57
|
+
when "cross_reference"
|
58
|
+
reference_field_class
|
59
|
+
when "law"
|
60
|
+
law_field_class
|
61
|
+
else
|
62
|
+
self
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
passkey :id
|
69
|
+
passthrough :patch_ver, :undeletable
|
70
|
+
passthrough :type, :label, :tooltip, :global_binding
|
71
|
+
passthrough :hidden, :accent, :deindex
|
72
|
+
passthrough :hide_view, :hidden_on_reports, :hidden_on_mobile
|
73
|
+
|
74
|
+
def ref
|
75
|
+
if digest = self.class.hash_label(label)
|
76
|
+
[type, digest].join(".")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def section
|
81
|
+
root.sections.find {|sec| sec.component?(id)}
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
require 'ecoportal/api/v2/page/component/tag_field'
|
91
|
+
require 'ecoportal/api/v2/page/component/geo_field'
|
92
|
+
require 'ecoportal/api/v2/page/component/selection_field'
|
93
|
+
require 'ecoportal/api/v2/page/component/date_field'
|
94
|
+
require 'ecoportal/api/v2/page/component/number_field'
|
95
|
+
require 'ecoportal/api/v2/page/component/gauge_field'
|
96
|
+
require 'ecoportal/api/v2/page/component/plain_text_field'
|
97
|
+
require 'ecoportal/api/v2/page/component/rich_text_field'
|
98
|
+
require 'ecoportal/api/v2/page/component/people_field'
|
99
|
+
require 'ecoportal/api/v2/page/component/checklist_field'
|
100
|
+
require 'ecoportal/api/v2/page/component/action_field'
|
101
|
+
require 'ecoportal/api/v2/page/component/files_field'
|
102
|
+
require 'ecoportal/api/v2/page/component/images_field'
|
103
|
+
require 'ecoportal/api/v2/page/component/signature_field'
|
104
|
+
require 'ecoportal/api/v2/page/component/reference_field'
|
105
|
+
require 'ecoportal/api/v2/page/component/law_field'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
class V2
|
4
|
+
class Page
|
5
|
+
class Component
|
6
|
+
class Action < Common::Content::DoubleModel
|
7
|
+
passkey :id
|
8
|
+
passthrough :patch_ver, :name
|
9
|
+
passthrough :weight, :complete, :overdue, :other_information
|
10
|
+
passdate :due_date, :created_at #, :completed_at
|
11
|
+
passthrough :created_by, :assigned_person_member_id
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
class V2
|
4
|
+
class Page
|
5
|
+
class Component
|
6
|
+
class ActionField < Page::Component
|
7
|
+
class_resolver :action_class, "Ecoportal::API::V2::Page::Component::Action"
|
8
|
+
embeds_multiple :actions, klass: :action_class, order_key: :weight
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'ecoportal/api/v2/page/component/action'
|