ecoportal-api 0.8.5 → 0.9.2

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +20 -20
  3. data/.rspec +3 -3
  4. data/.rubocop.yml +55 -55
  5. data/.travis.yml +5 -5
  6. data/.yardopts +10 -10
  7. data/CHANGELOG.md +257 -236
  8. data/Gemfile +6 -6
  9. data/LICENSE +21 -21
  10. data/README.md +34 -34
  11. data/Rakefile +27 -27
  12. data/bin/console +14 -14
  13. data/bin/setup +8 -8
  14. data/ecoportal-api.gemspec +36 -36
  15. data/lib/ecoportal/api/common/base_class.rb +33 -29
  16. data/lib/ecoportal/api/common/base_model.rb +195 -177
  17. data/lib/ecoportal/api/common/batch_operation.rb +119 -119
  18. data/lib/ecoportal/api/common/batch_response.rb +34 -34
  19. data/lib/ecoportal/api/common/client.rb +198 -196
  20. data/lib/ecoportal/api/common/doc_helpers.rb +29 -29
  21. data/lib/ecoportal/api/common/elastic_apm_integration.rb +112 -112
  22. data/lib/ecoportal/api/common/hash_diff.rb +41 -41
  23. data/lib/ecoportal/api/common/logging.rb +12 -12
  24. data/lib/ecoportal/api/common/response.rb +31 -31
  25. data/lib/ecoportal/api/common/wrapped_response.rb +54 -54
  26. data/lib/ecoportal/api/common.rb +18 -18
  27. data/lib/ecoportal/api/errors/base.rb +8 -8
  28. data/lib/ecoportal/api/errors/time_out.rb +8 -8
  29. data/lib/ecoportal/api/errors.rb +9 -9
  30. data/lib/ecoportal/api/internal/account.rb +99 -100
  31. data/lib/ecoportal/api/internal/login_provider.rb +9 -9
  32. data/lib/ecoportal/api/internal/login_providers.rb +33 -33
  33. data/lib/ecoportal/api/internal/people.rb +14 -14
  34. data/lib/ecoportal/api/internal/permissions.rb +14 -13
  35. data/lib/ecoportal/api/internal/person.rb +101 -53
  36. data/lib/ecoportal/api/internal/person_details.rb +9 -9
  37. data/lib/ecoportal/api/internal/person_schema.rb +10 -10
  38. data/lib/ecoportal/api/internal/person_schemas.rb +11 -11
  39. data/lib/ecoportal/api/internal/policy_group.rb +9 -9
  40. data/lib/ecoportal/api/internal/policy_groups.rb +32 -32
  41. data/lib/ecoportal/api/internal/preferences.rb +31 -31
  42. data/lib/ecoportal/api/internal/schema_field.rb +8 -8
  43. data/lib/ecoportal/api/internal/schema_field_value.rb +8 -8
  44. data/lib/ecoportal/api/internal.rb +31 -31
  45. data/lib/ecoportal/api/logger.rb +62 -62
  46. data/lib/ecoportal/api/v1/people.rb +218 -218
  47. data/lib/ecoportal/api/v1/person.rb +138 -135
  48. data/lib/ecoportal/api/v1/person_details.rb +94 -82
  49. data/lib/ecoportal/api/v1/person_schema.rb +53 -53
  50. data/lib/ecoportal/api/v1/person_schemas.rb +48 -48
  51. data/lib/ecoportal/api/v1/schema_field.rb +34 -34
  52. data/lib/ecoportal/api/v1/schema_field_value.rb +65 -65
  53. data/lib/ecoportal/api/v1.rb +49 -49
  54. data/lib/ecoportal/api/version.rb +5 -5
  55. data/lib/ecoportal/api.rb +16 -16
  56. metadata +3 -3
@@ -1,196 +1,198 @@
1
- require 'http'
2
- module Ecoportal
3
- module API
4
- module Common
5
- # @note
6
- # - You can see the documentation of the `HTTP` module in [the repository](https://github.com/httprb/http)
7
- # - it does `extend` the module `Chainable` ([chainable.rb](https://github.com/httprb/http/blob/master/lib/http/chainable.rb)),
8
- # - where all the http requests are dev by using `HTTP::Client#request` ([client.rb](https://github.com/httprb/http/blob/master/lib/http/client.rb))
9
- # - which calls `build_request` (new `HTTP::Request`) and `perform` (new `HTTP::Connection`)
10
- # - to return `HTTP::Response` ([response.rb](https://github.com/httprb/http/blob/master/lib/http/response.rb))
11
- # @attr_reader logger [Logger] the logger.
12
- class Client
13
- include Common::ElasticApmIntegration
14
- DELAY_REQUEST_RETRY = 5
15
-
16
- attr_accessor :logger
17
-
18
- # @note the `api_key` will be automatically added as parameter `X-ApiKey` in the header of the http requests.
19
- # @param api_key [String] the key version to stablish the api connection.
20
- # @param version [String] it is part of the base url and will determine the api version we query against.
21
- # @param host [String] api server domain.
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
24
- # @return [Client] an object that holds the configuration of the api connection.
25
- def initialize(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil, response_logging: false)
26
- @version = version
27
- @api_key = api_key
28
- @logger = logger
29
- @host = host
30
- @response_logging_enabled = response_logging
31
- if host.match(/^localhost|^127\.0\.0\.1/)
32
- @base_uri = "http://#{host}/api/"
33
- else
34
- @base_uri = "https://#{host}/api/"
35
- end
36
- log(:info) { "#{version} client initialized pointing at #{host}" }
37
- if @api_key.nil? || @api_key.match(/\A\W*\z/)
38
- log(:error) { "Api-key missing!" }
39
- end
40
- end
41
-
42
- # Logger interface.
43
- # @example:
44
- # log(:info) {"General information on what's going on"}
45
- # log(:warn) {"This is a warning that something is likely to have gone amiss"}
46
- # log(:error) {"Something went wrong"}
47
- # log(:fatal) {"An unrecoverable error has happend"}
48
- # @param level [Symbol] the level that the message should be logged.
49
- # @yield [] generates the message.
50
- # @yieldreturn [String] the generated message.
51
- def log(level, &block)
52
- logger.send(level, &block) if logger
53
- end
54
-
55
- # Sends an http `GET` request against the api version using `path` to complete the base url,
56
- # and adding the key_value pairs of `params` in the http _header_.
57
- # @param path [String] the tail that completes the url of the request.
58
- # @param params [Hash] the header paramters of the http request (not including the api key).
59
- # @option params [String] :page the current page we are requesting with given the `:per_page` offset.
60
- # @option params [String] :per_page the offset or the number of entries you get per request.
61
- # @option params [String] :q some text to search. Omit this parameter to target all the entries.
62
- # @return [Common::Reponse] the basic custom response object.
63
- def get(path, params: {})
64
- instrument("GET", path, params) do
65
- request do |http|
66
- http.get(url_for(path), params: params)
67
- end
68
- end
69
- end
70
-
71
- # Sends an http `POST` request against the api version using `path` to complete the base url,
72
- # and the `data` as a body of the http request.
73
- # @note it automatically adds the http header param `Content-Type` as `application/json`
74
- # @param path [String] the tail that completes the url of the request.
75
- # @param data [String] the body of the query in json format.
76
- # @return [Common::Reponse] the basic custom response object.
77
- def post(path, data:)
78
- instrument("POST", path, data) do
79
- request do |http|
80
- http.post(url_for(path), json: data)
81
- end
82
- end
83
- end
84
-
85
- # Sends an http `PATCH` request against the api version using `path` to complete the base url,
86
- # and the `data` as a body of the http request.
87
- # @note it automatically adds the http header param `Content-Type` as `application/json`
88
- # @param path [String] the tail that completes the url of the request.
89
- # @param data [String] the body of the query in json format.
90
- # @return [Common::Reponse] the basic custom response object.
91
- def patch(path, data:)
92
- instrument("PATCH", path, data) do
93
- request do |http|
94
- http.patch(url_for(path), json: data)
95
- end
96
- end
97
- end
98
-
99
- # Sends an http `DELETE` request against the api version using `path` to complete the base url.
100
- # @param path [String] the tail that completes the url of the request.
101
- # @return [Common::Reponse] the basic custom response object.
102
- def delete(path)
103
- instrument("DELETE", path) do
104
- request do |http|
105
- http.delete(url_for(path))
106
- end
107
- end
108
- end
109
-
110
- # Allows to launch a different operation via `block`, providing the
111
- # basic HTTP connection to the block.
112
- # @yield [http] launch specific http request.
113
- # @yieldparam http [HTTP] the http connection.
114
- # @yieldreturn [Common::Response] the basic custom response object.
115
- # @return [Common::Reponse] the basic custom response object.
116
- def request
117
- wrap_response yield(base_request)
118
- end
119
-
120
- # Wrap with basic custom object of the gem for responses.
121
- # @param response [HTTP::Response]
122
- # @return [Common::Reponse] the basic custom response object.
123
- def wrap_response(response)
124
- Ecoportal::API::Common::Response.new(response)
125
- end
126
-
127
- # Creates a HTTP object adding the `X-ApiKey` or `X-ECOPORTAL-API-KEY` param to the header, depending on the API version.
128
- # @note It configures HTTP so it only allows body data in json format.
129
- # @return [HTTP] HTTP object.
130
- def base_request
131
- @base_request ||= begin
132
- case @version
133
- when "v2"
134
- HTTP.headers("X-ECOPORTAL-API-KEY" => @api_key).accept(:json)
135
- else
136
- HTTP.headers("X-ApiKey" => @api_key).accept(:json)
137
- end
138
- end
139
- end
140
-
141
- # Full URl builder of the request
142
- # @param path [String] the tail that completes the url of the request.
143
- # @return [String] the final url.
144
- def url_for(path)
145
- @base_uri+@version+path
146
- end
147
-
148
- private
149
-
150
- def instrument(method, path, data = nil, &block)
151
- raise "Expected block" unless block
152
- start_time = Time.now.to_f
153
- log(:info) { "#{method} #{url_for(path)}" }
154
- log(:debug) { "Data: #{JSON.pretty_generate(data)}" }
155
-
156
- with_retry(&block).tap do |result|
157
- end_time = Time.now.to_f
158
- log(result.success?? :info : :warn) do
159
- "Took %.2fs, Status #{result.status}" % (end_time - start_time)
160
- end
161
- log(result.success?? :debug : :warn) do
162
- "Response: #{JSON.pretty_generate(result.body)}"
163
- end if @response_logging_enabled
164
- end
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
-
193
- end
194
- end
195
- end
196
- end
1
+ require 'http'
2
+ module Ecoportal
3
+ module API
4
+ module Common
5
+ # @note
6
+ # - You can see the documentation of the `HTTP` module in [the repository](https://github.com/httprb/http)
7
+ # - it does `extend` the module `Chainable` ([chainable.rb](https://github.com/httprb/http/blob/master/lib/http/chainable.rb)),
8
+ # - where all the http requests are dev by using `HTTP::Client#request` ([client.rb](https://github.com/httprb/http/blob/master/lib/http/client.rb))
9
+ # - which calls `build_request` (new `HTTP::Request`) and `perform` (new `HTTP::Connection`)
10
+ # - to return `HTTP::Response` ([response.rb](https://github.com/httprb/http/blob/master/lib/http/response.rb))
11
+ # @attr_reader logger [Logger] the logger.
12
+ # @attr_reader host [String] the remote target server.
13
+ class Client
14
+ include Common::ElasticApmIntegration
15
+ DELAY_REQUEST_RETRY = 5
16
+
17
+ attr_accessor :logger
18
+ attr_reader :host
19
+
20
+ # @note the `api_key` will be automatically added as parameter `X-ApiKey` in the header of the http requests.
21
+ # @param api_key [String] the key version to stablish the api connection.
22
+ # @param version [String] it is part of the base url and will determine the api version we query against.
23
+ # @param host [String] api server domain.
24
+ # @param logger [Logger] an object with `Logger` interface to generate logs.
25
+ # @param response_logging [Boolean] whether or not batch responses should be logged
26
+ # @return [Client] an object that holds the configuration of the api connection.
27
+ def initialize(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil, response_logging: false)
28
+ @version = version
29
+ @api_key = api_key
30
+ @logger = logger
31
+ @host = host
32
+ @response_logging_enabled = response_logging
33
+ if host.match(/^localhost|^127\.0\.0\.1/)
34
+ @base_uri = "http://#{host}/api/"
35
+ else
36
+ @base_uri = "https://#{host}/api/"
37
+ end
38
+ log(:info) { "#{version} client initialized pointing at #{host}" }
39
+ if @api_key.nil? || @api_key.match(/\A\W*\z/)
40
+ log(:error) { "Api-key missing!" }
41
+ end
42
+ end
43
+
44
+ # Logger interface.
45
+ # @example:
46
+ # log(:info) {"General information on what's going on"}
47
+ # log(:warn) {"This is a warning that something is likely to have gone amiss"}
48
+ # log(:error) {"Something went wrong"}
49
+ # log(:fatal) {"An unrecoverable error has happend"}
50
+ # @param level [Symbol] the level that the message should be logged.
51
+ # @yield [] generates the message.
52
+ # @yieldreturn [String] the generated message.
53
+ def log(level, &block)
54
+ logger.send(level, &block) if logger
55
+ end
56
+
57
+ # Sends an http `GET` request against the api version using `path` to complete the base url,
58
+ # and adding the key_value pairs of `params` in the http _header_.
59
+ # @param path [String] the tail that completes the url of the request.
60
+ # @param params [Hash] the header paramters of the http request (not including the api key).
61
+ # @option params [String] :page the current page we are requesting with given the `:per_page` offset.
62
+ # @option params [String] :per_page the offset or the number of entries you get per request.
63
+ # @option params [String] :q some text to search. Omit this parameter to target all the entries.
64
+ # @return [Common::Reponse] the basic custom response object.
65
+ def get(path, params: {})
66
+ instrument("GET", path, params) do
67
+ request do |http|
68
+ http.get(url_for(path), params: params)
69
+ end
70
+ end
71
+ end
72
+
73
+ # Sends an http `POST` request against the api version using `path` to complete the base url,
74
+ # and the `data` as a body of the http request.
75
+ # @note it automatically adds the http header param `Content-Type` as `application/json`
76
+ # @param path [String] the tail that completes the url of the request.
77
+ # @param data [String] the body of the query in json format.
78
+ # @return [Common::Reponse] the basic custom response object.
79
+ def post(path, data:)
80
+ instrument("POST", path, data) do
81
+ request do |http|
82
+ http.post(url_for(path), json: data)
83
+ end
84
+ end
85
+ end
86
+
87
+ # Sends an http `PATCH` request against the api version using `path` to complete the base url,
88
+ # and the `data` as a body of the http request.
89
+ # @note it automatically adds the http header param `Content-Type` as `application/json`
90
+ # @param path [String] the tail that completes the url of the request.
91
+ # @param data [String] the body of the query in json format.
92
+ # @return [Common::Reponse] the basic custom response object.
93
+ def patch(path, data:)
94
+ instrument("PATCH", path, data) do
95
+ request do |http|
96
+ http.patch(url_for(path), json: data)
97
+ end
98
+ end
99
+ end
100
+
101
+ # Sends an http `DELETE` request against the api version using `path` to complete the base url.
102
+ # @param path [String] the tail that completes the url of the request.
103
+ # @return [Common::Reponse] the basic custom response object.
104
+ def delete(path)
105
+ instrument("DELETE", path) do
106
+ request do |http|
107
+ http.delete(url_for(path))
108
+ end
109
+ end
110
+ end
111
+
112
+ # Allows to launch a different operation via `block`, providing the
113
+ # basic HTTP connection to the block.
114
+ # @yield [http] launch specific http request.
115
+ # @yieldparam http [HTTP] the http connection.
116
+ # @yieldreturn [Common::Response] the basic custom response object.
117
+ # @return [Common::Reponse] the basic custom response object.
118
+ def request
119
+ wrap_response yield(base_request)
120
+ end
121
+
122
+ # Wrap with basic custom object of the gem for responses.
123
+ # @param response [HTTP::Response]
124
+ # @return [Common::Reponse] the basic custom response object.
125
+ def wrap_response(response)
126
+ Ecoportal::API::Common::Response.new(response)
127
+ end
128
+
129
+ # Creates a HTTP object adding the `X-ApiKey` or `X-ECOPORTAL-API-KEY` param to the header, depending on the API version.
130
+ # @note It configures HTTP so it only allows body data in json format.
131
+ # @return [HTTP] HTTP object.
132
+ def base_request
133
+ @base_request ||= begin
134
+ case @version
135
+ when "v2"
136
+ HTTP.headers("X-ECOPORTAL-API-KEY" => @api_key).accept(:json)
137
+ else
138
+ HTTP.headers("X-ApiKey" => @api_key).accept(:json)
139
+ end
140
+ end
141
+ end
142
+
143
+ # Full URl builder of the request
144
+ # @param path [String] the tail that completes the url of the request.
145
+ # @return [String] the final url.
146
+ def url_for(path)
147
+ @base_uri+@version+path
148
+ end
149
+
150
+ private
151
+
152
+ def instrument(method, path, data = nil, &block)
153
+ raise "Expected block" unless block
154
+ start_time = Time.now.to_f
155
+ log(:info) { "#{method} #{url_for(path)}" }
156
+ log(:debug) { "Data: #{JSON.pretty_generate(data)}" }
157
+
158
+ with_retry(&block).tap do |result|
159
+ end_time = Time.now.to_f
160
+ log(result.success?? :info : :warn) do
161
+ "Took %.2fs, Status #{result.status}" % (end_time - start_time)
162
+ end
163
+ log(result.success?? :debug : :warn) do
164
+ "Response: #{JSON.pretty_generate(result.body)}"
165
+ end if @response_logging_enabled
166
+ end
167
+ end
168
+
169
+ # Helper to ensure unexpected server errors do not bring client scripts immediately down
170
+ def with_retry(attempts = 3, delay = DELAY_REQUEST_RETRY, error_safe: true, &block)
171
+ response = nil
172
+ attempts.times do |i|
173
+ remaining = attempts - i - 1
174
+ begin
175
+ response = block.call
176
+ rescue HTTP::ConnectionError => e
177
+ raise unless error_safe && remaining > 0
178
+ log(:error) { "Got connection error: #{e.message}" }
179
+ response = with_retry(remaining, error_safe: error_safe, &block)
180
+ rescue IOError => e
181
+ raise unless error_safe && remaining > 0
182
+ log(:error) { "Got IO error: #{e.message}" }
183
+ response = with_retry(remaining, error_safe: error_safe, &block)
184
+ end
185
+ return response unless unexpected_server_error?(response.status)
186
+ log_unexpected_server_error(response)
187
+ msg = "Got server error (#{response.status}): #{response.body}\n"
188
+ msg += "Going to retry (#{i} out of #{attempts})"
189
+ log(:error) { msg }
190
+ sleep(delay) if i < attempts
191
+ end
192
+ response
193
+ end
194
+
195
+ end
196
+ end
197
+ end
198
+ end
@@ -1,29 +1,29 @@
1
- module Ecoportal
2
- module API
3
- module Common
4
- module DocHelpers
5
-
6
- def get_body(doc)
7
- if doc.respond_to?(:as_update)
8
- doc.as_update
9
- elsif doc.respond_to?(:as_json)
10
- doc.as_json
11
- else
12
- doc
13
- end
14
- end
15
-
16
- def get_id(doc)
17
- id = nil
18
- id ||= doc.id if doc.respond_to?(:id)
19
- id ||= doc.external_id if doc.respond_to?(:external_id)
20
- id ||= doc["id"] if doc.is_a?(Hash)
21
- id ||= doc["external_id"] if doc.is_a?(Hash)
22
- id ||= doc if doc.is_a?(String)
23
- id or raise "No ID has been given!"
24
- id
25
- end
26
- end
27
- end
28
- end
29
- end
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module DocHelpers
5
+
6
+ def get_body(doc)
7
+ if doc.respond_to?(:as_update)
8
+ doc.as_update
9
+ elsif doc.respond_to?(:as_json)
10
+ doc.as_json
11
+ else
12
+ doc
13
+ end
14
+ end
15
+
16
+ def get_id(doc)
17
+ id = nil
18
+ id ||= doc.id if doc.respond_to?(:id)
19
+ id ||= doc.external_id if doc.respond_to?(:external_id)
20
+ id ||= doc["id"] if doc.is_a?(Hash)
21
+ id ||= doc["external_id"] if doc.is_a?(Hash)
22
+ id ||= doc if doc.is_a?(String)
23
+ id or raise "No ID has been given!"
24
+ id
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end