ecoportal-api 0.9.8 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,12 @@
1
+ # rubocop:disable Naming/PredicateName
1
2
  module Ecoportal
2
3
  module API
3
4
  module Common
4
5
  class BaseModel
5
- class UnlinkedModel < Exception
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
6
+ class UnlinkedModel < StandardError
7
+ def initialize(msg = "Something went wrong when linking the document.", from: nil, key: nil)
8
+ msg << " From: #{from}." if from
9
+ msg << " key: #{key}." if key
9
10
  super(msg)
10
11
  end
11
12
  end
@@ -25,10 +26,11 @@ module Ecoportal
25
26
  end
26
27
  end
27
28
 
28
- def embeds_one(method, key: method, nullable: false, klass:)
29
+ def embeds_one(method, klass:, key: method, nullable: false)
29
30
  method = method.to_s.freeze
30
31
  var = "@#{method}".freeze
31
32
  key = key.to_s.freeze
33
+
32
34
  define_method(method) do
33
35
  if instance_variable_defined?(var)
34
36
  value = instance_variable_get(var)
@@ -36,7 +38,9 @@ module Ecoportal
36
38
  return value if (value && doc[key]) || (!value && !doc[key])
37
39
  remove_instance_variable(var)
38
40
  end
41
+
39
42
  doc[key] ||= {} unless nullable
43
+
40
44
  return instance_variable_set(var, nil) unless doc[key]
41
45
 
42
46
  self.class.resolve_class(klass).new(
@@ -44,7 +48,6 @@ module Ecoportal
44
48
  ).tap {|obj| instance_variable_set(var, obj)}
45
49
  end
46
50
  end
47
-
48
51
  end
49
52
 
50
53
  attr_reader :_parent, :_key
@@ -52,28 +55,32 @@ module Ecoportal
52
55
  def initialize(doc = {}, parent: self, key: nil)
53
56
  @_parent = parent
54
57
  @_key = key
55
- if !_parent || !_key
56
- @doc = JSON.parse(doc.to_json)
57
- @original_doc = JSON.parse(@doc.to_json)
58
- @initial_doc = JSON.parse(@doc.to_json)
59
- end
58
+
59
+ return unless !_parent || !_key
60
+
61
+ @doc = JSON.parse(doc.to_json)
62
+ @original_doc = JSON.parse(@doc.to_json)
63
+ @initial_doc = JSON.parse(@doc.to_json)
60
64
  end
61
65
 
62
66
  def doc
63
- raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
67
+ raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
64
68
  return @doc if is_root?
69
+
65
70
  _parent.doc.dig(*[_key].flatten)
66
71
  end
67
72
 
68
73
  def original_doc
69
- raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
74
+ raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
70
75
  return @original_doc if is_root?
76
+
71
77
  _parent.original_doc&.dig(*[_key].flatten)
72
78
  end
73
79
 
74
80
  def initial_doc
75
- raise UnlinkedModel.new(from: "#{self.class}#initial_doc", key: _key) unless linked?
81
+ raise UnlinkedModel.new(from: "#{self.class}#initial_doc", key: _key) unless linked?
76
82
  return @initial_doc if is_root?
83
+
77
84
  _parent.initial_doc&.dig(*[_key].flatten)
78
85
  end
79
86
 
@@ -81,6 +88,7 @@ module Ecoportal
81
88
  # @return [Hash] `doc` before change
82
89
  def replace_doc!(new_doc)
83
90
  raise UnlinkedModel.new(from: "#{self.class}#replace_doc", key: _key) unless linked?
91
+
84
92
  @doc.tap do
85
93
  @doc = new_doc
86
94
  end
@@ -90,6 +98,7 @@ module Ecoportal
90
98
  # @return [Hash] `original_doc` before change
91
99
  def replace_original_doc!(new_doc)
92
100
  raise UnlinkedModel.new(from: "#{self.class}#replace_original_doc", key: _key) unless linked?
101
+
93
102
  @original_doc.tap do
94
103
  @original_doc = new_doc
95
104
  end
@@ -115,7 +124,8 @@ module Ecoportal
115
124
 
116
125
  # It consolidates all the changes carried by `doc` by setting it as `original_doc`.
117
126
  def consolidate!
118
- raise UnlinkedModel.new(from: "#{self.class}#consolidate!", key: _key) unless linked?
127
+ raise UnlinkedModel.new(from: "#{self.class}#consolidate!", key: _key) unless linked?
128
+
119
129
  new_doc = JSON.parse(doc.to_json)
120
130
  if is_root?
121
131
  @original_doc = new_doc
@@ -130,18 +140,19 @@ module Ecoportal
130
140
  # i.e. `parent.reset!("child")` # when parent.child is `nil`
131
141
  # 2. In such a case, only immediate childs are allowed to be reset
132
142
  # @param key [String, Array<String>, nil] if given, it only resets the specified property
133
- def reset!(key = nil)
134
- raise "'key' should be a String. Given #{key}" unless !key || key.is_a?(String)
135
- raise UnlinkedModel.new(from: "#{self.class}#reset!", key: _key) unless linked?
143
+ def reset!(key = nil) # rubocop:disable Metrics/AbcSize>
144
+ msg = "'key' should be a String. Given #{key}"
145
+ raise ArgumentError, msg unless !key || key.is_a?(String)
146
+ raise UnlinkedModel.new(from: "#{self.class}#reset!", key: _key) unless linked?
136
147
 
137
148
  if key
138
- if self.respond_to?(key) && child = self.send(key) && child.is_a?(Ecoportal::API::Common::BaseModel)
149
+ if respond_to?(key) && (child = send(key)) && child.is_a?(Ecoportal::API::Common::BaseModel)
139
150
  child.reset!
140
151
  else
141
152
  new_doc = original_doc && original_doc[key]
142
153
  dig_set(doc, [key], new_doc && JSON.parse(new_doc.to_json))
143
154
  # regenerate object if new_doc is null
144
- self.send(key) if !new_doc && self.respond_to?(key)
155
+ send(key) if !new_doc && respond_to?(key)
145
156
  end
146
157
  else
147
158
  new_doc = JSON.parse(original_doc.to_json)
@@ -179,17 +190,17 @@ module Ecoportal
179
190
  end
180
191
 
181
192
  def set_uniq_array_keep_order(key, value)
182
- unless value.is_a?(Array)
183
- raise "#{key}= needs to be passed an Array, got #{value.class}"
184
- end
185
- ini_vals = (original_doc && original_doc[key]) || []
193
+ msg = "#{key}= needs to be passed an Array, got #{value.class}"
194
+ raise ArgumentError, msg unless value.is_a?(Array)
186
195
 
196
+ ini_vals = (original_doc && original_doc[key]) || []
187
197
  value = value.uniq
188
198
  # preserve original order to avoid false updates
189
199
  doc[key] = ((ini_vals & value) + (value - ini_vals)).compact
190
200
  end
191
-
192
201
  end
193
202
  end
194
203
  end
195
204
  end
205
+
206
+ # rubocop:enable Naming/PredicateName
@@ -28,19 +28,21 @@ module Ecoportal
28
28
  log(:info) { "Processing batch responses" }
29
29
 
30
30
  body_data(response.body).each.with_index do |subresponse, idx|
31
- callback = @operations[idx][:callback]
32
31
  status = subresponse["status"]
33
- body = subresponse["response"]
34
32
  method = @operations[idx][:method]
33
+ body = subresponse["response"]
34
+ callback = @operations[idx][:callback]
35
35
 
36
36
  if status == 200 && method == "GET"
37
37
  batch_response = BatchResponse.new(status, body, @wrapper.new(body))
38
38
  log_batch_response(@operations[idx], batch_response)
39
- callback && callback.call(batch_response, batch_response.result)
39
+
40
+ callback&.call(batch_response, batch_response.result)
40
41
  else
41
42
  batch_response = BatchResponse.new(status, body)
42
43
  log_batch_response(@operations[idx], batch_response)
43
- callback && callback.call(batch_response)
44
+
45
+ callback&.call(batch_response)
44
46
  end
45
47
  end
46
48
  end
@@ -48,9 +50,9 @@ module Ecoportal
48
50
  def get(doc, &block)
49
51
  id = get_id(doc)
50
52
  @operations << {
51
- path: @base_path + "/" + CGI::escape(id),
53
+ path: "#{@base_path}/#{CGI.escape(id)}",
52
54
  method: "GET",
53
- callback: block_given? && block
55
+ callback: block
54
56
  }
55
57
  end
56
58
 
@@ -58,10 +60,10 @@ module Ecoportal
58
60
  id = get_id(doc)
59
61
  body = get_body(doc)
60
62
  @operations << {
61
- path: @base_path + "/" + CGI::escape(id),
63
+ path: "#{@base_path}/#{CGI.escape(id)}",
62
64
  method: "PATCH",
63
65
  body: body,
64
- callback: block_given? && block
66
+ callback: block
65
67
  }
66
68
  end
67
69
 
@@ -69,19 +71,19 @@ module Ecoportal
69
71
  id = get_id(doc)
70
72
  body = get_body(doc)
71
73
  @operations << {
72
- path: @base_path + "/" + CGI::escape(id),
74
+ path: "#{@base_path}/#{CGI.escape(id)}",
73
75
  method: "POST",
74
76
  body: body,
75
- callback: block_given? && block
77
+ callback: block
76
78
  }
77
79
  end
78
80
 
79
81
  def delete(doc, &block)
80
82
  id = get_id(doc)
81
83
  @operations << {
82
- path: @base_path + "/" + CGI::escape(id),
84
+ path: "#{@base_path}/#{CGI.escape(id)}",
83
85
  method: "DELETE",
84
- callback: block_given? && block
86
+ callback: block
85
87
  }
86
88
  end
87
89
 
@@ -91,7 +93,7 @@ module Ecoportal
91
93
  path: @base_path,
92
94
  method: "POST",
93
95
  body: body,
94
- callback: block_given? && block
96
+ callback: block
95
97
  }
96
98
  end
97
99
 
@@ -104,14 +106,15 @@ module Ecoportal
104
106
  end
105
107
 
106
108
  def log_batch_response(operation, response)
107
- level = response.success?? :debug : :warn
108
109
  log(:info) { "BATCH #{operation[:method]} #{operation[:path]}" }
109
110
  log(:info) { "Status #{response.status}" }
111
+
112
+ level = response.success?? :debug : :warn
110
113
  log(level) { "Response: #{JSON.pretty_generate(response.body)}" }
111
114
  end
112
115
 
113
116
  def log(level, &block)
114
- @logger.send(level, &block) if @logger
117
+ @logger&.send(level, &block)
115
118
  end
116
119
  end
117
120
  end
@@ -2,7 +2,6 @@ module Ecoportal
2
2
  module API
3
3
  module Common
4
4
  class BatchResponse
5
-
6
5
  attr_reader :status, :body, :result
7
6
 
8
7
  def initialize(status, body, result = nil)
@@ -15,10 +14,8 @@ module Ecoportal
15
14
  status.success?
16
15
  end
17
16
 
18
- def each
19
- [*@result].each do |doc|
20
- yield doc
21
- end
17
+ def each(&block)
18
+ [*@result].each(&block)
22
19
  end
23
20
 
24
21
  def print_pretty
@@ -3,11 +3,16 @@ module Ecoportal
3
3
  module API
4
4
  module Common
5
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))
6
+ # - You can see the documentation of the `HTTP` module in
7
+ # [the repository](https://github.com/httprb/http)
8
+ # - it does `extend` the module `Chainable`
9
+ # ([chainable.rb](https://github.com/httprb/http/blob/master/lib/http/chainable.rb)),
10
+ # - where all the http requests are dev by using `HTTP::Client#request`
11
+ # ([client.rb](https://github.com/httprb/http/blob/master/lib/http/client.rb))
12
+ # - which calls `build_request` (new `HTTP::Request`) and `perform`
13
+ # (new `HTTP::Connection`)
14
+ # - to return `HTTP::Response`
15
+ # ([response.rb](https://github.com/httprb/http/blob/master/lib/http/response.rb))
11
16
  # @attr_reader logger [Logger] the logger.
12
17
  # @attr_reader host [String] the remote target server.
13
18
  class Client
@@ -31,15 +36,17 @@ module Ecoportal
31
36
  @logger = logger
32
37
  @host = host
33
38
  @response_logging_enabled = response_logging
39
+
34
40
  if host.match(/^localhost|^127\.0\.0\.1/)
35
41
  @base_uri = "http://#{host}/api/"
36
42
  else
37
43
  @base_uri = "https://#{host}/api/"
38
44
  end
39
45
  log(:info) { "#{version} client initialized pointing at #{host}" }
40
- if @api_key.nil? || @api_key.match(/\A\W*\z/)
41
- log(:error) { "Api-key missing!" }
42
- end
46
+
47
+ return unless @api_key.nil? || @api_key.match(/\A\W*\z/)
48
+
49
+ log(:error) { "Api-key missing!" }
43
50
  end
44
51
 
45
52
  # Logger interface.
@@ -52,7 +59,7 @@ module Ecoportal
52
59
  # @yield [] generates the message.
53
60
  # @yieldreturn [String] the generated message.
54
61
  def log(level, &block)
55
- logger.send(level, &block) if logger
62
+ logger&.send(level, &block)
56
63
  end
57
64
 
58
65
  # Sends an http `GET` request against the api version using `path` to complete the base url,
@@ -127,18 +134,18 @@ module Ecoportal
127
134
  Ecoportal::API::Common::Response.new(response)
128
135
  end
129
136
 
130
- # Creates a HTTP object adding the `X-ApiKey` or `X-ECOPORTAL-API-KEY` param to the header, depending on the API version.
137
+ # Creates a HTTP object adding the `X-ApiKey` or `X-ECOPORTAL-API-KEY` param
138
+ # to the header, depending on the API version.
131
139
  # @note It configures HTTP so it only allows body data in json format.
132
140
  # @return [HTTP] HTTP object.
133
141
  def base_request
134
- @base_request ||= begin
142
+ @base_request ||=
135
143
  case @version
136
144
  when "v2"
137
145
  HTTP.headers("X-ECOPORTAL-API-KEY" => @api_key).accept(:json)
138
146
  else
139
147
  HTTP.headers("X-ApiKey" => @api_key).accept(:json)
140
148
  end
141
- end
142
149
  end
143
150
 
144
151
  # Full URl builder of the request
@@ -151,19 +158,23 @@ module Ecoportal
151
158
  private
152
159
 
153
160
  def instrument(method, path, data = nil, &block)
154
- raise "Expected block" unless block
161
+ raise "Expected block" unless block_given?
162
+
155
163
  start_time = Time.now.to_f
156
164
  log(:info) { "#{method} #{url_for(path)}" }
157
165
  log(:debug) { "Data: #{JSON.pretty_generate(data)}" }
158
166
 
159
167
  with_retry(&block).tap do |result|
160
168
  end_time = Time.now.to_f
161
- log(result.success?? :info : :warn) do
162
- "Took %.2fs, Status #{result.status}" % (end_time - start_time)
163
- end
164
- log(result.success?? :debug : :warn) do
169
+ log(result.success?? :info : :warn) {
170
+ "Took %.2fs, Status #{result.status}" % (end_time - start_time) # rubocop:disable Style/FormatString
171
+ }
172
+
173
+ next unless @response_logging_enabled
174
+
175
+ log(result.success?? :debug : :warn) {
165
176
  "Response: #{JSON.pretty_generate(result.body)}"
166
- end if @response_logging_enabled
177
+ }
167
178
  end
168
179
  end
169
180
 
@@ -190,9 +201,11 @@ module Ecoportal
190
201
  puts "re-attempting (remaining: #{remaining} attempts out of #{attempts})"
191
202
 
192
203
  log_unexpected_server_error(response)
204
+
193
205
  msg = "Got server error (#{response.status}): #{response.body}\n"
194
206
  msg += "Going to retry (#{i} out of #{attempts})"
195
207
  log(:error) { msg }
208
+
196
209
  sleep(delay) if i < attempts
197
210
  end
198
211
  response
@@ -13,7 +13,7 @@ module Ecoportal
13
13
  end
14
14
  end.join.to_s
15
15
 
16
- @body = JSON.parse(@src_body) rescue nil
16
+ @body = JSON.parse(@src_body) rescue nil # rubocop:disable Style/RescueModifier
17
17
  end
18
18
 
19
19
  def success?
@@ -10,26 +10,24 @@ module Ecoportal
10
10
  @response = response
11
11
  @klass = klass
12
12
 
13
- if @response.success?
14
- @result =
15
- if @response.body.is_a?(Array)
16
- @response.body.map do |doc|
17
- @klass.new(doc)
18
- end
19
- else
20
- @klass.new(@response.body)
13
+ return unless @response.success?
14
+
15
+ @result =
16
+ if @response.body.is_a?(Array)
17
+ @response.body.map do |doc|
18
+ @klass.new(doc)
21
19
  end
22
- end
20
+ else
21
+ @klass.new(@response.body)
22
+ end
23
23
  end
24
24
 
25
25
  def body
26
26
  response.body.to_s
27
27
  end
28
28
 
29
- def each
30
- [*result].each do |doc|
31
- yield doc
32
- end
29
+ def each(&block)
30
+ [*result].each(&block)
33
31
  end
34
32
 
35
33
  def status
@@ -41,13 +39,10 @@ module Ecoportal
41
39
  end
42
40
 
43
41
  def print_pretty
44
- if success?
45
- each(&:print_pretty)
46
- else
47
- puts "Request failed."
48
- end
49
- end
42
+ return each(&:print_pretty) if success?
50
43
 
44
+ "Request failed."
45
+ end
51
46
  end
52
47
  end
53
48
  end
@@ -2,13 +2,14 @@ module Ecoportal
2
2
  module API
3
3
  class Internal
4
4
  class Account < Common::BaseModel
5
- PROPERTIES = [
6
- "user_id", "policy_group_ids", "default_tag", "prefilter",
7
- "permissions_custom", "permissions_merged", "preferences",
8
- "login_provider_ids", "starred_ids", "landing_page_id",
9
- "accept_eula", "send_invites", "force_send_invites"
10
- ]
11
- passthrough *PROPERTIES.map(&:to_sym)
5
+ PROPERTIES = %w[
6
+ user_id policy_group_ids default_tag prefilter
7
+ permissions_custom permissions_merged preferences
8
+ login_provider_ids starred_ids landing_page_id
9
+ accept_eula send_invites force_send_invites
10
+ ].freeze
11
+
12
+ passthrough(*PROPERTIES.map(&:to_sym))
12
13
 
13
14
  class_resolver :preferences_class, "Ecoportal::API::Internal::Preferences"
14
15
  class_resolver :permissions_class, "Ecoportal::API::Internal::Permissions"
@@ -23,11 +24,11 @@ module Ecoportal
23
24
  # @return [String, nil] the value set in `default_tag`
24
25
  def default_tag=(value)
25
26
  unless !value || value.is_a?(String)
26
- raise ArgumentError.new("default_tag= needs to be passed a String or nil, got #{value.class}")
27
+ raise ArgumentError, "default_tag= needs to be passed a String or nil, got #{value.class}"
27
28
  end
28
29
  if value
29
30
  unless value.match(Ecoportal::API::V1::Person::VALID_TAG_REGEX)
30
- raise ArgumentError.new("Invalid default tag #{value.inspect}")
31
+ raise ArgumentError, "Invalid default tag #{value.inspect}"
31
32
  end
32
33
  value = value.upcase
33
34
  end
@@ -89,7 +90,7 @@ module Ecoportal
89
90
  end
90
91
 
91
92
  def as_update(ref = :last, ignore: [])
92
- super(ref, ignore: ignore | ["user_id", "permissions_merged", "prefilter"])
93
+ super(ref, ignore: ignore | %w[user_id permissions_merged prefilter])
93
94
  end
94
95
  end
95
96
  end
@@ -3,12 +3,12 @@ module Ecoportal
3
3
  class Internal < V1
4
4
  include Common::Logging
5
5
 
6
- VERSION = "v0"
7
- class_resolver :people_class, "Ecoportal::API::Internal::People"
8
- class_resolver :person_schemas_class, "Ecoportal::API::Internal::PersonSchemas"
6
+ VERSION = "v0".freeze
7
+ class_resolver :people_class, "Ecoportal::API::Internal::People"
8
+ class_resolver :person_schemas_class, "Ecoportal::API::Internal::PersonSchemas"
9
9
 
10
- class_resolver :policy_groups_class, "Ecoportal::API::Internal::PolicyGroups"
11
- class_resolver :login_providers_class, "Ecoportal::API::Internal::LoginProviders"
10
+ class_resolver :policy_groups_class, "Ecoportal::API::Internal::PolicyGroups"
11
+ class_resolver :login_providers_class, "Ecoportal::API::Internal::LoginProviders"
12
12
 
13
13
  # Obtain specific object for policy groups api requests.
14
14
  # @return [PolicyGroups] an instance object ready to make policy groups api requests.
@@ -1,24 +1,26 @@
1
1
  module Ecoportal
2
2
  module API
3
3
  class Logger
4
- TIMESTAMP_PATTERN = "%Y-%m-%dT%H:%M:%S"
5
- STDOUT_FORMAT_PROC = proc do |severity, datetime, progname, msg|
6
- prefix = "%5s > " % severity
4
+ TIMESTAMP_PATTERN = "%Y-%m-%dT%H:%M:%S".freeze
5
+
6
+ STDOUT_FORMAT_PROC = proc do |severity, _datetime, _progname, msg|
7
+ prefix = "%5s > " % severity # rubocop:disable Style/FormatString
7
8
  msg.lines.map.with_index do |line, idx|
8
9
  if idx.zero?
9
10
  prefix + line.chomp
10
11
  else
11
- " "*prefix.length + line.chomp
12
+ (" " * prefix.length) + line.chomp
12
13
  end
13
14
  end.join("\n")+"\n"
14
15
  end
15
- FILE_FORMAT_PROC = proc do |severity, datetime, progname, msg|
16
- prefix = "%5s(%s) > " % [severity, datetime.strftime(TIMESTAMP_PATTERN)]
16
+
17
+ FILE_FORMAT_PROC = proc do |severity, datetime, _progname, msg|
18
+ prefix = "%5s(%s) > " % [severity, datetime.strftime(TIMESTAMP_PATTERN)] # rubocop:disable Style/FormatString, Style/FormatStringToken
17
19
  msg.lines.map.with_index do |line, idx|
18
20
  if idx.zero?
19
21
  prefix + line.chomp
20
22
  else
21
- " "*prefix.length + line.chomp
23
+ (" " * prefix.length) + line.chomp
22
24
  end
23
25
  end.join("\n")+"\n"
24
26
  end
@@ -34,7 +36,7 @@ module Ecoportal
34
36
  @file = make_file_logger(file_level, output_file)
35
37
  end
36
38
 
37
- %w(unknown fatal error warn info debug).each do |type|
39
+ %w[unknown fatal error warn info debug].each do |type|
38
40
  define_method(type) do |&block|
39
41
  @console.send(type, &block)
40
42
  @file&.send(type, &block)
@@ -44,7 +46,7 @@ module Ecoportal
44
46
  private
45
47
 
46
48
  def make_stdout_logger(level)
47
- ::Logger.new(STDOUT).tap do |logger|
49
+ ::Logger.new($stdout).tap do |logger|
48
50
  logger.formatter = STDOUT_FORMAT_PROC
49
51
  logger.level = level
50
52
  end