ecoportal-api 0.7.4 → 0.8.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 275ffcb5e9bfe17f44295a7c4438b9e169dc87f22afe19591752425ef008cdba
4
- data.tar.gz: aeb53e930f75dc7299fc400a8a00624428dfe496b77a5fdf1af1075b144a6944
3
+ metadata.gz: dc651f2474f74b8f767c9df5b4611bd8adefdff75f8e25365135c89561229738
4
+ data.tar.gz: cb7a8ff5c0c03ba7e371f987d6b277c001b33e57716ab6cf03628d28bac53b61
5
5
  SHA512:
6
- metadata.gz: 2e2e4c03089ccf675057b335a9c9e46a5a40a92d3720b256fb9a679eec6431885889171960bf106e3586efbc77d9b2384262c9e4aa52cdf34b6c291be78b76dd
7
- data.tar.gz: c1df25f369172d215ba64bf932b63d78514871579540edabc991719a737999a5700828352bceca140d5715861b47cb6b2e4e56fab4b7b916fe5ef42627ec7e4f
6
+ metadata.gz: f89285565edeaa9cbe4a98970bae8602a943c7c865121a89782f512353a8be74529578eecb4f48e893f546f172425dd38af0759412f53b8fc3a91989d6dbe52a
7
+ data.tar.gz: 4f51e3e6d080745261c033acf511fdd341ebf9f97003f4dda5067c49c9ef51adf966c51cf268e4991e741b45c803fc6c1e821051832c090ba2c685f03c4eaa7d
data/CHANGELOG.md CHANGED
@@ -1,6 +1,101 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.8.4] - 2021-10-xx
5
+
6
+ ### Added
7
+ - `Ecoportal::API::Internal::Permissions` added abilities
8
+ - `visitor_management`, `cross_register_reporting` and `broadcast_notifications`
9
+ - Some yardocs too
10
+ - Some callbacks are done in a non-obvious way and the returned object type was not documented
11
+ - For this reason, some yardocs have been added to some of the parts that have been worked on.
12
+
13
+ ### Fixed
14
+ - `Ecoportal::API::V1::People#create_job`
15
+ - **Removed** call to `BatchOperation#process_response`
16
+ - The method was is already called by `job_result`
17
+ - As a consequence there was a double up of `callbacks`
18
+ - **Fixed** line in wrong position
19
+ - `Ecoportal::API::V1::People#batch`
20
+ - `Ecoportal::API::Common::ElasticApmIntegration#unexpected_server_error?`
21
+ - No code or code lesser than 100 is a server error as well
22
+
23
+ ### Changed
24
+ - `Ecoportal::API::Common::Client`: changed
25
+ - Logging the **response** of batches or batch jobs can be handy when debugging the back-end
26
+ - **removed** method `#without_response_logging`
27
+ - This change entailed to remove dependencies in `Ecoportal::API::V1::People`
28
+ - Specifically in methods `#batch`, `#job_result` and `#create_job`
29
+ - `@response_logging_enabled` to be set in initialization stage (added parameter for `.new`)
30
+
31
+ ## [0.8.3] - 2021-05-24
32
+
33
+ ### Added
34
+ - `Ecoportal::API::Errors` namespace
35
+ - `Ecoportal::API::Errors::Base` base error class.
36
+ - `Ecoportal::API::Errors::TimeOut` error when an api request fails with time out.
37
+ - This serves the purpose to allow a client script to re-start the process where it stopped by capturing this specific Error
38
+ - `Ecoportal::API::Common::BaseModel::UnlinkedModel` added more description to track down the source of the error.
39
+ - `Ecoportal::API::Common::BaseModel#reset!` added parameter `key`, which should try to recover `doc[key]` from `original_doc[key]`
40
+ - Thanks to this, you are supposed to be able to do things like:
41
+ - `person.account = nil && person.reset!("account")`
42
+ - `person.name = nil && person.reset!("name")`
43
+ - `Ecoportal::API::V1::People#job` methods to provide more information on failure.
44
+ - Specific changes due to eP **release `1.5.9.70`** (_Policy Group Abilities_)
45
+ - `Ecoportal::API::Internal::Account#permissions_merged`
46
+ - `Ecoportal::API::Internal::Permissions#person_abilities` (new ability)
47
+ - `Ecoportal::API::Internal::Account#user_id`
48
+
49
+ ### Fixed
50
+ - `Ecoportal::API::Internal::Account`: consistency in setting arrays (`uniq!` & `compact`)
51
+ - `#policy_group_ids=`, `#login_provider_ids=`, `#starred_ids=`
52
+ - `Ecoportal::API::Common::HashDiff.diff` was including empty `{}` objects
53
+ - This change sacrifices the case `account: {}` (which will be also removed from `as_update`), but it should be fine.
54
+
55
+ ### Changed
56
+ - `Ecoportal::API::V1::People#job` to raise specific error on time out `API::Errors::TimeOut`
57
+ - Specific changes due to eP **release `1.5.9.70`** (_Policy Group Abilities_)
58
+ - `Ecoportal::API::Internal::Account` **removed** methods: `#permissions_preset`, `#preset` and `#preset=`
59
+ - `Ecoportal::API::Internal::Person#account=` added support for `user_id` which should remain unchanged when existing
60
+ - **remove** from `as_update` **read-only** data
61
+ - `Ecoportal::API::Common::HashDiff.diff` added parameter `:ignore` (`Array`)
62
+ - `Ecoportal::API::Common::BaseModel#as_update` added parameter `:ignore`
63
+ - `Ecoportal::API::V1::Person#as_update` added method, which ignores `subordinates`
64
+ - `Ecoportal::API::Internal::Person#as_update` added method, which ignores `user_id`, `permissions_merged` and `prefilter`
65
+ - `Ecoportal::API::Internal::Account#as_update` added method, which ignores `user_id`, `permissions_merged` and `prefilter`
66
+ - `Ecoportal::API::Common::Client` native support for `elastic-apm`
67
+ - Via new module `Ecoportal::API::Common::ElasticApmIntegration` with method `log_unexpected_server_error`, which will only log an `UnexpectedServerError` to _ElasticAPM_ if
68
+ 1. There's a correct configuration: environmental variables `ELASTIC_APM_KEY` and `ELASTIC_APM_ACCOUNT_ID` are defined
69
+ 2. The `Response` from the server gave `code` in the range `5xx` (which are those under server responsibility)
70
+ - `Ecoportal::API::Common::Client` added retry logics when `response.status == 5xx`
71
+
72
+ ## [0.8.2] - 2021-02-24
73
+
74
+ ### Added
75
+
76
+ ### Fixed
77
+ - `Ecoportal::API::V1::Person#filter_tags=` should ignore `nil` values
78
+
79
+ ### Changed
80
+ - removed all the namespace under `Ecoportal::API::V2` as that is managed by `ecoportal-api-oozes` gem
81
+ - url: https://rubygems.org/gems/ecoportal-api-oozes
82
+ - `Ecoportal::API::V1::People.get` should return a `Person` object
83
+ - observe that it was returning the `WrappedResponse` (an `Enumerable` helper that works better when getting multiple people).
84
+
85
+ ## [0.7.5] - 2021-02-12
86
+
87
+ ### Added
88
+
89
+ ### Fixed
90
+ - `pretty_print` method was colliding with `pp` module:
91
+ - renamed to `Ecoportal::API::Common::BaseModel#print_pretty`
92
+ - renamed to `Ecoportal::API::Common::BatchReponse#print_pretty`
93
+ - renamed to `Ecoportal::API::Common::Reponse#print_pretty`
94
+ - renamed to `Ecoportal::API::Common::WrappedResponse#print_pretty`
95
+
96
+ ### Changed
97
+ - forgot to change `Ecoportal::API::VERSION` during last release
98
+
4
99
  ## [0.7.4] - 2021-01-2
5
100
 
6
101
  ### Added
@@ -62,6 +157,10 @@ All notable changes to this project will be documented in this file.
62
157
  ## [0.7.0] - 2020-09-11
63
158
 
64
159
  ### Added
160
+ - added hook, **private** method `body_data` for child classes to define behaviour on `response.body` to
161
+ - `Ecoportal::API::V1::People`
162
+ - `Ecoportal::API::Common::BatchOperation`
163
+
65
164
  ### Changed
66
165
  - `Ecoportal::API::Internal::Permissions`: **update for new abilities of ecoPortal release `1.5.2`**
67
166
  - decoupled abilities: `person_core` into `person_core_create`, `person_core_edit`
@@ -13,6 +13,8 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://www.ecoportal.com"
14
14
  spec.licenses = %w[MIT]
15
15
 
16
+ spec.required_ruby_version = '>= 2.4.4'
17
+
16
18
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
19
  f.match(%r{^(test|spec|features)/})
18
20
  end
@@ -20,13 +22,15 @@ Gem::Specification.new do |spec|
20
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
23
  spec.require_paths = ["lib"]
22
24
 
23
- spec.add_development_dependency "bundler", "~> 2.1", ">= 2.1.3"
24
- spec.add_development_dependency "rake", "~> 12.0"
25
- spec.add_development_dependency "rspec", "~> 3", ">= 3.9"
26
- spec.add_development_dependency "yard", "~> 0.9", ">= 0.9.18"
27
- spec.add_development_dependency "redcarpet", "~> 3.5", ">= 3.5.0"
28
- spec.add_development_dependency "pry" , "~> 0.13"
25
+ spec.add_development_dependency "bundler", ">= 2.2.17", "< 2.3"
26
+ spec.add_development_dependency "rspec", ">= 3.10.0", "< 3.11"
27
+ spec.add_development_dependency "rake", ">= 13.0.3", "< 13.1"
28
+ spec.add_development_dependency "yard", ">= 0.9.26", "< 0.10"
29
+ spec.add_development_dependency "redcarpet", ">= 3.5.1", "< 3.6"
30
+ spec.add_development_dependency "pry" , "~> 0.14"
29
31
 
30
- spec.add_dependency 'http', '~> 4'
32
+ spec.add_dependency 'http', '~> 4.4.1', "< 5"
33
+ spec.add_dependency 'dotenv', '>= 2.7.6', "< 2.8"
34
+ spec.add_dependency 'elastic-apm', '>= 4.0.0', "< 4.1"
31
35
  spec.add_dependency 'hash-polyfill', '~> 0'
32
36
  end
@@ -3,7 +3,9 @@ module Ecoportal
3
3
  module Common
4
4
  class BaseModel
5
5
  class UnlinkedModel < Exception
6
- def initialize (msg = "Something went wrong when linking the document.")
6
+ def initialize (msg = "Something went wrong when linking the document.", from: nil, key: nil)
7
+ msg += " From: #{from}." if from
8
+ msg += " key: #{key}." if key
7
9
  super(msg)
8
10
  end
9
11
  end
@@ -28,7 +30,12 @@ module Ecoportal
28
30
  var = "@#{method}".freeze
29
31
  key = key.to_s.freeze
30
32
  define_method(method) do
31
- return instance_variable_get(var) if instance_variable_defined?(var)
33
+ if instance_variable_defined?(var)
34
+ value = instance_variable_get(var)
35
+ return value unless nullable
36
+ return value if (value && doc[key]) || (!value && !doc[key])
37
+ remove_instance_variable(var)
38
+ end
32
39
  doc[key] ||= {} unless nullable
33
40
  return instance_variable_set(var, nil) unless doc[key]
34
41
 
@@ -53,19 +60,19 @@ module Ecoportal
53
60
  end
54
61
 
55
62
  def doc
56
- raise UnlinkedModel.new unless linked?
63
+ raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
57
64
  return @doc if is_root?
58
65
  _parent.doc.dig(*[_key].flatten)
59
66
  end
60
67
 
61
68
  def original_doc
62
- raise UnlinkedModel.new unless linked?
69
+ raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
63
70
  return @original_doc if is_root?
64
71
  _parent.original_doc.dig(*[_key].flatten)
65
72
  end
66
73
 
67
74
  def initial_doc
68
- raise UnlinkedModel.new unless linked?
75
+ raise UnlinkedModel.new(from: "#{self.class}#initial_doc", key: _key) unless linked?
69
76
  return @initial_doc if is_root?
70
77
  _parent.initial_doc.dig(*[_key].flatten)
71
78
  end
@@ -78,18 +85,19 @@ module Ecoportal
78
85
  doc.to_json(*args)
79
86
  end
80
87
 
81
- def as_update(ref = :last)
88
+ def as_update(ref = :last, ignore: [])
82
89
  new_doc = as_json
83
90
  ref_doc = ref == :total ? initial_doc : original_doc
84
- Common::HashDiff.diff(new_doc, ref_doc)
91
+ Common::HashDiff.diff(new_doc, ref_doc, ignore: ignore)
85
92
  end
86
93
 
87
94
  def dirty?
88
95
  as_update != {}
89
96
  end
90
97
 
98
+ # It consolidates all the changes carried by `doc` by setting it as `original_doc`.
91
99
  def consolidate!
92
- raise UnlinkedModel.new unless linked?
100
+ raise UnlinkedModel.new(from: "#{self.class}#consolidate!", key: _key) unless linked?
93
101
  new_doc = JSON.parse(doc.to_json)
94
102
  if is_root?
95
103
  @original_doc = new_doc
@@ -98,20 +106,39 @@ module Ecoportal
98
106
  end
99
107
  end
100
108
 
101
- def reset!
102
- raise UnlinkedModel.new unless linked?
103
- new_doc = JSON.parse(original_doc.to_json)
104
- if is_root?
105
- @doc = new_doc
109
+ # It removes all the changes carried by `doc` by restoring `original_doc` into `doc`.
110
+ # @note
111
+ # 1. When there are nullable properties, it may be required to apply `reset!` from the parent
112
+ # i.e. `parent.reset!("child")` # when parent.child is `nil`
113
+ # 2. In such a case, only immediate childs are allowed to be reset
114
+ # @param key [String, Array<String>, nil] if given, it only resets the specified property
115
+ def reset!(key = nil)
116
+ raise "'key' should be a String. Given #{key}" unless !key || key.is_a?(String)
117
+ raise UnlinkedModel.new(from: "#{self.class}#reset!", key: _key) unless linked?
118
+
119
+ if key
120
+ if self.respond_to?(key) && child = self.send(key) && child.is_a?(Ecoportal::API::Common::BaseModel)
121
+ child.reset!
122
+ else
123
+ new_doc = original_doc && original_doc[key]
124
+ dig_set(doc, [key], new_doc && JSON.parse(new_doc.to_json))
125
+ # regenerate object if new_doc is null
126
+ self.send(key) if !new_doc && self.respond_to?(key)
127
+ end
106
128
  else
107
- dig_set(_parent.doc, [_key].flatten, new_doc)
129
+ new_doc = JSON.parse(original_doc.to_json)
130
+ if is_root?
131
+ @doc = new_doc
132
+ else
133
+ dig_set(_parent.doc, [_key].flatten, new_doc)
134
+ end
108
135
  end
109
136
  end
110
137
 
111
- # def pretty_print
112
- # puts JSON.pretty_generate(as_json)
113
- # self
114
- # end
138
+ def print_pretty
139
+ puts JSON.pretty_generate(as_json)
140
+ self
141
+ end
115
142
 
116
143
  protected
117
144
 
@@ -133,6 +160,17 @@ module Ecoportal
133
160
  end
134
161
  end
135
162
 
163
+ def set_uniq_array_keep_order(key, value)
164
+ unless value.is_a?(Array)
165
+ raise "#{key}= needs to be passed an Array, got #{value.class}"
166
+ end
167
+ ini_vals = (original_doc && original_doc[key]) || []
168
+
169
+ value = value.uniq
170
+ # preserve original order to avoid false updates
171
+ doc[key] = ((ini_vals & value) + (value - ini_vals)).compact
172
+ end
173
+
136
174
  end
137
175
  end
138
176
  end
@@ -27,7 +27,7 @@ module Ecoportal
27
27
 
28
28
  log(:info) { "Processing batch responses" }
29
29
 
30
- response.body.each.with_index do |subresponse, idx|
30
+ body_data(response.body).each.with_index do |subresponse, idx|
31
31
  callback = @operations[idx][:callback]
32
32
  status = subresponse["status"]
33
33
  body = subresponse["response"]
@@ -97,6 +97,12 @@ module Ecoportal
97
97
 
98
98
  private
99
99
 
100
+ # Hook for other api versions to obtain the raw data of a response
101
+ # @note this was introduced to allow `v2` to reuse this class
102
+ def body_data(body)
103
+ body
104
+ end
105
+
100
106
  def log_batch_response(operation, response)
101
107
  level = response.success?? :debug : :warn
102
108
  log(:info) { "BATCH #{operation[:method]} #{operation[:path]}" }
@@ -21,9 +21,9 @@ module Ecoportal
21
21
  end
22
22
  end
23
23
 
24
- def pretty_print
24
+ def print_pretty
25
25
  if success?
26
- each(&:pretty_print)
26
+ each(&:print_pretty)
27
27
  else
28
28
  puts "Request failed."
29
29
  end
@@ -10,6 +10,9 @@ module Ecoportal
10
10
  # - to return `HTTP::Response` ([response.rb](https://github.com/httprb/http/blob/master/lib/http/response.rb))
11
11
  # @attr_reader logger [Logger] the logger.
12
12
  class Client
13
+ include Common::ElasticApmIntegration
14
+ DELAY_REQUEST_RETRY = 5
15
+
13
16
  attr_accessor :logger
14
17
 
15
18
  # @note the `api_key` will be automatically added as parameter `X-ApiKey` in the header of the http requests.
@@ -17,11 +20,14 @@ module Ecoportal
17
20
  # @param version [String] it is part of the base url and will determine the api version we query against.
18
21
  # @param host [String] api server domain.
19
22
  # @param logger [Logger] an object with `Logger` interface to generate logs.
23
+ # @param response_logging [Boolean] whether or not batch responses should be logged
20
24
  # @return [Client] an object that holds the configuration of the api connection.
21
- def initialize(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil)
25
+ def initialize(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil, response_logging: false)
22
26
  @version = version
23
27
  @api_key = api_key
24
28
  @logger = logger
29
+ @host = host
30
+ @response_logging_enabled = response_logging
25
31
  if host.match(/^localhost|^127\.0\.0\.1/)
26
32
  @base_uri = "http://#{host}/api/"
27
33
  else
@@ -31,7 +37,6 @@ module Ecoportal
31
37
  if @api_key.nil? || @api_key.match(/\A\W*\z/)
32
38
  log(:error) { "Api-key missing!" }
33
39
  end
34
- @response_logging_enabled = true
35
40
  end
36
41
 
37
42
  # Logger interface.
@@ -106,7 +111,7 @@ module Ecoportal
106
111
  # basic HTTP connection to the block.
107
112
  # @yield [http] launch specific http request.
108
113
  # @yieldparam http [HTTP] the http connection.
109
- # @yieldreturn [Common::Response] the basic custom reponse object.
114
+ # @yieldreturn [Common::Response] the basic custom response object.
110
115
  # @return [Common::Reponse] the basic custom response object.
111
116
  def request
112
117
  wrap_response yield(base_request)
@@ -140,22 +145,15 @@ module Ecoportal
140
145
  @base_uri+@version+path
141
146
  end
142
147
 
143
- def without_response_logging(&block)
144
- begin
145
- @response_logging_enabled = false
146
- yield self
147
- ensure
148
- @response_logging_enabled = true
149
- end
150
- end
151
-
152
148
  private
153
149
 
154
- def instrument(method, path, data = nil)
150
+ def instrument(method, path, data = nil, &block)
151
+ raise "Expected block" unless block
155
152
  start_time = Time.now.to_f
156
- log(:info) { "#{method} #{url_for(path)}" }
153
+ log(:info) { "#{method} #{url_for(path)}" }
157
154
  log(:debug) { "Data: #{JSON.pretty_generate(data)}" }
158
- yield.tap do |result|
155
+
156
+ with_retry(&block).tap do |result|
159
157
  end_time = Time.now.to_f
160
158
  log(result.success?? :info : :warn) do
161
159
  "Took %.2fs, Status #{result.status}" % (end_time - start_time)
@@ -165,6 +163,33 @@ module Ecoportal
165
163
  end if @response_logging_enabled
166
164
  end
167
165
  end
166
+
167
+ # Helper to ensure unexpected server errors do not bring client scripts immediately down
168
+ def with_retry(attempts = 3, delay = DELAY_REQUEST_RETRY, error_safe: true, &block)
169
+ response = nil
170
+ attempts.times do |i|
171
+ remaining = attempts - i - 1
172
+ begin
173
+ response = block.call
174
+ rescue HTTP::ConnectionError => e
175
+ raise unless error_safe && remaining > 0
176
+ log(:error) { "Got connection error: #{e.message}" }
177
+ response = with_retry(remaining, error_safe: error_safe, &block)
178
+ rescue IOError => e
179
+ raise unless error_safe && remaining > 0
180
+ log(:error) { "Got IO error: #{e.message}" }
181
+ response = with_retry(remaining, error_safe: error_safe, &block)
182
+ end
183
+ return response unless unexpected_server_error?(response.status)
184
+ log_unexpected_server_error(response)
185
+ msg = "Got server error (#{response.status}): #{response.body}\n"
186
+ msg += "Going to retry (#{i} out of #{attempts})"
187
+ log(:error) { msg }
188
+ sleep(delay) if i < attempts
189
+ end
190
+ response
191
+ end
192
+
168
193
  end
169
194
  end
170
195
  end
@@ -0,0 +1,112 @@
1
+ require 'elastic-apm'
2
+ module Ecoportal
3
+ module API
4
+ module Common
5
+ module ElasticApmIntegration
6
+
7
+ class UnexpectedServerError < StandardError
8
+ def initialize(code, msg)
9
+ super("Code: #{code} -- Error: #{msg}")
10
+ end
11
+ end
12
+
13
+ APM_SERVICE_NAME = 'ecoportal-api-gem'
14
+
15
+ # Log only errors that are only server's responsibility
16
+ def log_unexpected_server_error(response)
17
+ raise "Expecting Ecoportal::API::Common::Response. Given: #{response.class}" unless response.is_a?(Common::Response)
18
+ return nil unless elastic_apm_service
19
+ return nil unless unexpected_server_error?(response.status)
20
+ if ElasticAPM.running?
21
+ ElasticAPM.report(UnexpectedServerError.new(response.status, response.body))
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def unexpected_server_error?(code)
28
+ !code || ((code >= 500) && (code <= 599)) || (code <= 99)
29
+ end
30
+
31
+ # finalizer to stop the agent
32
+ close_elastic_apm = Proc.new do |id|
33
+ begin
34
+ if ElasticAPM.running?
35
+ puts "Stopping ElasticAPM service"
36
+ ElasticAPM.stop
37
+ end
38
+ rescue StandardError => e
39
+ # Silent
40
+ end
41
+ end
42
+ ObjectSpace.define_finalizer("ElasticAPM", close_elastic_apm)
43
+
44
+ def elastic_apm_service
45
+ return false if @disable_apm
46
+ begin
47
+ ElasticAPM.start(**elastic_apm_options) unless ElasticAPM.running?
48
+ rescue StandardError => e
49
+ @disable_apm = true
50
+ puts "ElasticAPM services not available: #{e}"
51
+ end
52
+ end
53
+
54
+ def elastic_apm_options
55
+ {
56
+ service_name: APM_SERVICE_NAME,
57
+ server_url: elastic_apm_url,
58
+ secret_token: elastic_apm_key,
59
+ environment: environment,
60
+ #http_compression: false,
61
+ transaction_sample_rate: 0.1,
62
+ transaction_max_spans: 100,
63
+ span_frames_min_duration: "5ms"
64
+ }.tap do |options|
65
+ options.merge!({
66
+ log_level: Logger::DEBUG,
67
+ log_path: File.join(__dir__, "elastic_apm.log")
68
+ }) if false
69
+ end
70
+ end
71
+
72
+ def elastic_apm_url
73
+ @elastic_apm_url ||= "https://".tap do |url|
74
+ url << "#{elastic_apm_account_id}"
75
+ url << ".#{elastic_apm_base_url}"
76
+ url << ":#{elastic_apm_port}"
77
+ end
78
+ end
79
+
80
+ def elastic_apm_key
81
+ @elastic_apm_key ||= ENV['ELASTIC_APM_KEY']
82
+ end
83
+
84
+ def elastic_apm_account_id
85
+ @elastic_apm_account_id ||= ENV['ELASTIC_APM_ACCOUNT_ID']
86
+ end
87
+
88
+ def elastic_apm_base_url
89
+ @elastic_apm_base_url ||= "apm.#{elastic_apm_region}.aws.cloud.es.io"
90
+ end
91
+
92
+ def elastic_apm_region
93
+ @elastic_apm_region ||= ENV['ELASTIC_APM_REGION'] || "ap-southeast-2"
94
+ end
95
+
96
+
97
+ def elastic_apm_port
98
+ @elastic_apm_port ||= ENV['ELASTIC_APM_PORT'] || "443"
99
+ end
100
+
101
+ def environment
102
+ @environment ||= "unknown".tap do |value|
103
+ if instance_variable_defined?(:@host) && env = @host.gsub(".ecoportal.com", '')
104
+ value.clear << env
105
+ end
106
+ end
107
+ end
108
+
109
+ end
110
+ end
111
+ end
112
+ end
@@ -5,15 +5,16 @@ module Ecoportal
5
5
  ID_KEYS = %w[id]
6
6
 
7
7
  class << self
8
- def diff(a, b)
9
- return a if a.class != b.class
8
+
9
+ def diff(a, b, ignore: [])
10
10
  case a
11
11
  when Hash
12
12
  {}.tap do |diffed|
13
13
  a.each do |key, a_value|
14
- b_value = b[key]
15
- next if a_value == b_value && !ID_KEYS.include?(key)
16
- diffed[key] = diff(a_value, b_value)
14
+ b_value = b && b[key]
15
+ no_changes = (a_value == b_value) || ignore.include?(key)
16
+ next if !ID_KEYS.include?(key) && no_changes
17
+ diffed[key] = diff(a_value, b_value, ignore: ignore)
17
18
  diffed.delete(key) if diffed[key] == {}
18
19
  end
19
20
  # All keys are IDs, so it's actually blank
@@ -22,10 +23,10 @@ module Ecoportal
22
23
  end
23
24
  end
24
25
  when Array
25
- return a unless a.length == b.length
26
+ return a unless b.is_a?(Array) && a.length == b.length
26
27
  a.map.with_index do |a_value, idx|
27
28
  b_value = b[idx]
28
- diff(a_value, b_value)
29
+ diff(a_value, b_value, ignore: ignore)
29
30
  end.reject do |el|
30
31
  el == {}
31
32
  end
@@ -20,7 +20,7 @@ module Ecoportal
20
20
  @status.success?
21
21
  end
22
22
 
23
- def pretty_print
23
+ def print_pretty
24
24
  puts "Status: #{@status.code}"
25
25
  puts "Body:"
26
26
  puts JSON.pretty_generate(@body)
@@ -40,9 +40,9 @@ module Ecoportal
40
40
  response.success?
41
41
  end
42
42
 
43
- def pretty_print
43
+ def print_pretty
44
44
  if success?
45
- each(&:pretty_print)
45
+ each(&:print_pretty)
46
46
  else
47
47
  puts "Request failed."
48
48
  end
@@ -10,6 +10,7 @@ require 'ecoportal/api/common/hash_diff'
10
10
  require 'ecoportal/api/common/base_model'
11
11
  require 'ecoportal/api/common/doc_helpers'
12
12
  require 'ecoportal/api/common/logging'
13
+ require 'ecoportal/api/common/elastic_apm_integration'
13
14
  require 'ecoportal/api/common/client'
14
15
  require 'ecoportal/api/common/response'
15
16
  require 'ecoportal/api/common/wrapped_response'
@@ -0,0 +1,8 @@
1
+ module Ecoportal
2
+ module API
3
+ module Errors
4
+ class Base < StandardError
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Ecoportal
2
+ module API
3
+ module Errors
4
+ class TimeOut < Errors::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module Ecoportal
2
+ module API
3
+ module Errors
4
+ end
5
+ end
6
+ end
7
+
8
+ require 'ecoportal/api/errors/base'
9
+ require 'ecoportal/api/errors/time_out'