rdstation-ruby-client 2.2.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ade7306767c00b8d39afdeb149d4aaebe84dfd35b389e2bf1435e623dfabfb7
4
- data.tar.gz: 3bdc3dc84ff1395fa65dc86e172b5ca967696e88b60bf9774723fcd33c785fbe
3
+ metadata.gz: 97ef40283572e980be5fee4c7d98d02d267a48e2eca8c948b8d51be95f5e807b
4
+ data.tar.gz: ebba8f50fef8eaa254c1187f6f2e5e0e9bbf393ad94e185870f250cb2f9bd14d
5
5
  SHA512:
6
- metadata.gz: fddd4b51c76c965cbd44bda5e36712f26f694fbabd59a7c0b008174cfcacd4225b73ce7640b32e9aeaed2495950ff0c19b70a555b5d8bf0dab79eaf2ce060136
7
- data.tar.gz: 90d96ef3c8d917deb7adbfe0aff6e2625b7f4f1d925d6b54e806df9aa3fd3de6378358521bbfce024eb32af06695f0974ca0f0dd8b9684ed1c537f2d228c97de
6
+ metadata.gz: 467b42ba1b17c256dba0ed6ab2ed632e83c437ae1067d043ccb97c4274244376cc26dd770ef112c8b81eb31c40fd37486bfb4b28f83b16f9dc0a47730a3d6e07
7
+ data.tar.gz: 6bdcada4a7418e8fd4cab9d4b121d3192667ebccac2869f9fdae759966e291e0698cc914dd1681c6c8493f78717599d063ac868a5ea5e9e23e13da003215563e
@@ -1,3 +1,80 @@
1
+ ## 2.5.1
2
+
3
+ - Fixed checking `empty?` for nil values inside of InvalidRefreshToken class
4
+
5
+ ## 2.5.0
6
+
7
+ - InvalidRefreshToken error added. This error will be raised when the refresh token is invalid or it was revoked. When you get this error, you can safely disconnect the user from RD Station.
8
+
9
+ Usage example:
10
+
11
+ ```ruby
12
+ begin
13
+ rdstation.update_access_token(refresh_token)
14
+ rescue RDStation::Error::InvalidRefreshToken
15
+ # Disconnect user
16
+ end
17
+ ```
18
+
19
+ ## 2.4.0
20
+
21
+ - Add the TooManyRequests errors in case of rate limit exceeded. See [API request limit](https://developers.rdstation.com/en/request-limit) for more details
22
+
23
+ ## 2.3.1
24
+
25
+ - Fixed a bug when no error is found in the known errors list (issue [#52](https://github.com/ResultadosDigitais/rdstation-ruby-client/issues/52))
26
+
27
+ ## 2.3.0
28
+
29
+ ### Additions
30
+
31
+ #### 1. New Field methods
32
+
33
+ The following methods were added to "Fields" client:
34
+
35
+ - create
36
+ - update
37
+ - delete
38
+
39
+ Besides reading, this client is now capable of create, update or delete a field.
40
+
41
+ Usage example:
42
+
43
+ ```ruby
44
+ client = RDStation::Client.new(access_token: 'ACCESS_TOKEN', refresh_token: 'REFRESH_TOKEN')
45
+ client.fields.delete('FIELD_UUID')
46
+ ```
47
+
48
+ #### 2. New format of errors supported
49
+
50
+ Two new formats of errors are now supported by the error handler:
51
+
52
+ ##### `HASH_OF_HASHES`
53
+
54
+ When the error message is a hash containing other hashes as values, for example:
55
+
56
+ ```ruby
57
+ {
58
+ 'error' => {
59
+ 'field1' => {...},
60
+ 'field2' => {...}
61
+ }
62
+ }
63
+ ```
64
+
65
+ ##### `HASH_OF_MULTIPLE_TYPES`
66
+
67
+ When the error message is a hash that could contain multiple data types as values, for example:
68
+
69
+ ```ruby
70
+ {
71
+ 'error' => {
72
+ 'field1' => [...] # Array,
73
+ 'field2' => {...} # Hash
74
+ }
75
+ }
76
+ ```
77
+
1
78
  ## 2.2.0
2
79
 
3
80
  ### Additions
@@ -37,7 +114,7 @@ end
37
114
 
38
115
  Providing `client_id` and `client_secret` directly to `RDStation::Authentication.new` is deprecated and will be removed in future versions. Use `RDStation.configure` instead.
39
116
 
40
- Specifying refresh_token in `RDStation::Client.new(access_token: 'at', refresh_token: 'rt')` is optional right now, but will be mandatory in future versions.
117
+ Specifying refresh_token in `RDStation::Client.new(access_token: 'at', refresh_token: 'rt')` is optional right now, but will be mandatory in future versions.
41
118
 
42
119
  ## 2.1.1
43
120
 
@@ -94,7 +171,7 @@ In case of a Bad Request (400), the following specific errors may be raised (tho
94
171
  - `RDStation::Error::ConflictingField`
95
172
  - `RDStation::Error::InvalidEventType`
96
173
 
97
- In cause of Unahtorized (401), the following specific errors may be raised (those are subclasses of `RDStation::Error::Unauthorized`):
174
+ In cause of Unauthorized (401), the following specific errors may be raised (those are subclasses of `RDStation::Error::Unauthorized`):
98
175
  - `RDStation::Error::ExpiredAccessToken`
99
176
  - `RDStation::Error::ExpiredCodeGrant`
100
177
  - `RDStation::Error::InvalidCredentials`
data/README.md CHANGED
@@ -93,7 +93,7 @@ RDStation.configure do |config|
93
93
  # authorization.access_token_expires_in is the time (in seconds for with the token is valid)
94
94
  # authorization.access_token is the new token
95
95
  # authorization.refresh_token is the existing refresh_token
96
- #
96
+ #
97
97
  # If you are using ActiveRecord, you may want to update the stored access_token, like in the following code:
98
98
  MyStoredAuth.where(refresh_token: authorization.refresh_token).update_all(access_token: authorization.access_token)
99
99
  end
@@ -206,6 +206,55 @@ client = RDStation::Client.new(access_token: 'access_token', refresh_token: 'ref
206
206
  client.fields.all
207
207
  ```
208
208
 
209
+ #### Create a field
210
+
211
+ ```ruby
212
+ payload = {} # hash representing the payload
213
+ client = RDStation::Client.new(access_token: 'access_token', refresh_token: 'refresh_token')
214
+ client.fields.create payload
215
+ ```
216
+ Or you can use the new `RDStation::Builder::Field`
217
+
218
+ ```ruby
219
+ payload = {} # hash representing the payload
220
+ builder = RDStation::Builder::Field.new payload['api_identifier']
221
+ builder.data_type(payload['data_type'])
222
+ builder.presentation_type(payload['presentation_type'])
223
+ builder.name('pt-BR', payload['name'])
224
+ builder.label('pt-BR', payload['label'])
225
+
226
+ client = RDStation::Client.new(access_token: 'access_token', refresh_token: 'refresh_token')
227
+ client.fields.create builder.build
228
+ ```
229
+
230
+ #### Update a field
231
+
232
+ ```ruby
233
+ payload = {} # hash representing the payload
234
+ client = RDStation::Client.new(access_token: 'access_token', refresh_token: 'refresh_token')
235
+ client.fields.update('FIELD_UUID', payload)
236
+ ```
237
+ Or you can use the new `RDStation::Builder::Field`
238
+
239
+ ```ruby
240
+ payload = {} # hash representing the payload
241
+ builder = RDStation::Builder::Field.new payload['api_identifier']
242
+ builder.data_type(payload['data_type'])
243
+ builder.presentation_type(payload['presentation_type'])
244
+ builder.name('pt-BR', payload['name'])
245
+ builder.label('pt-BR', payload['label'])
246
+
247
+ client = RDStation::Client.new(access_token: 'access_token', refresh_token: 'refresh_token')
248
+ client.fields.update('FIELD_UUID', builder.build)
249
+ ```
250
+ #### Deleting a field
251
+
252
+ ```ruby
253
+ client = RDStation::Client.new(access_token: 'access_token', refresh_token: 'refresh_token')
254
+ client.fields.delete('FIELD_UUID')
255
+ ```
256
+
257
+
209
258
  ### Webhooks
210
259
 
211
260
  Webhooks provide the ability to receive real-time data updates about your contact activity.
@@ -266,6 +315,7 @@ Each endpoint may raise errors accoording to the HTTP response code from RDStati
266
315
  - `RDStation::Error::Conflict` (409)
267
316
  - `RDStation::Error::UnsupportedMediaType` (415)
268
317
  - `RDStation::Error::UnprocessableEntity` (422)
318
+ - `RDStation::Error::TooManyRequests` (429)
269
319
  - `RDStation::Error::InternalServerError` (500)
270
320
  - `RDStation::Error::NotImplemented` (501)
271
321
  - `RDStation::Error::BadGateway` (502)
data/Rakefile CHANGED
@@ -5,3 +5,7 @@ RSpec::Core::RakeTask.new
5
5
 
6
6
  task :default => :spec
7
7
  task :test => :spec
8
+
9
+ task :console do
10
+ exec 'pry -r rdstation-ruby-client -I ./lib'
11
+ end
@@ -17,3 +17,6 @@ require 'rdstation/webhooks'
17
17
  # Error handling
18
18
  require 'rdstation/error'
19
19
  require 'rdstation/error_handler'
20
+
21
+ # Builders
22
+ require 'rdstation/builder/field'
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RDStation
4
+ class Builder
5
+ # More info: https://developers.rdstation.com/pt-BR/reference/fields#methodPostDetails
6
+ class Field
7
+ DATA_TYPES = %w(STRING INTEGER BOOLEAN STRING[]).freeze
8
+ PRESENTATION_TYPES = %w[TEXT_INPUT TEXT_AREA URL_INPUT PHONE_INPUT
9
+ EMAIL_INPUT CHECK_BOX NUMBER_INPUT COMBO_BOX
10
+ RADIO_BUTTON MULTIPLE_CHOICE].freeze
11
+
12
+ REQUIRED_FIELDS = %w[api_identifier data_type presentation_type label name].freeze
13
+
14
+ def initialize(api_identifier)
15
+ raise 'api_identifier required' unless api_identifier
16
+ unless valid_identifier(api_identifier)
17
+ raise 'api_identifier is not in a valid format, need start with "cf_"'
18
+ end
19
+
20
+ @values = {}
21
+ @values['api_identifier'] = api_identifier
22
+ end
23
+
24
+ def data_type(data_type)
25
+ raise "Not valid data_type - #{DATA_TYPES}" unless DATA_TYPES.include? data_type
26
+
27
+ @values['data_type'] = data_type
28
+ end
29
+
30
+ def presentation_type(presentation_type)
31
+ unless PRESENTATION_TYPES.include? presentation_type
32
+ raise "Not valid presentation_type - #{PRESENTATION_TYPES}"
33
+ end
34
+
35
+ @values['presentation_type'] = presentation_type
36
+ end
37
+
38
+ def label(language, label)
39
+ @values['label'] = { language.to_s => label }
40
+ end
41
+
42
+ def name(language, name)
43
+ @values['name'] = { language.to_s => name }
44
+ end
45
+
46
+ def validation_rules(validation_rules)
47
+ @values['validation_rules'] = validation_rules
48
+ end
49
+
50
+ def valid_options(valid_options)
51
+ @values['valid_options'] = valid_options
52
+ end
53
+
54
+ def build
55
+ empty_fields = REQUIRED_FIELDS.select { |field| @values[field].nil? }
56
+ unless empty_fields.empty?
57
+ raise "Required fields are missing - #{empty_fields}"
58
+ end
59
+
60
+ @values
61
+ end
62
+
63
+ private
64
+
65
+ def valid_identifier(api_identifier)
66
+ api_identifier.start_with? 'cf_'
67
+ end
68
+ end
69
+ end
70
+ end
@@ -19,11 +19,13 @@ module RDStation
19
19
  class Conflict < Error; end
20
20
  class UnsupportedMediaType < Error; end
21
21
  class UnprocessableEntity < Error; end
22
+ class TooManyRequests < Error; end
22
23
  class InternalServerError < Error; end
23
24
  class NotImplemented < Error; end
24
25
  class BadGateway < Error; end
25
26
  class ServiceUnavailable < Error; end
26
27
  class ServerError < Error; end
28
+ class UnknownError < Error; end
27
29
 
28
30
  # 400 - Bad Request
29
31
  class ConflictingField < BadRequest; end
@@ -33,5 +35,6 @@ module RDStation
33
35
  class ExpiredAccessToken < Unauthorized; end
34
36
  class ExpiredCodeGrant < Unauthorized; end
35
37
  class InvalidCredentials < Unauthorized; end
38
+ class InvalidRefreshToken < Unauthorized; end
36
39
  end
37
40
  end
@@ -1,9 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RDStation
2
4
  class Error
3
5
  class Format
4
- FLAT_HASH = 'FLAT_HASH'.freeze
5
- HASH_OF_ARRAYS = 'HASH_OF_ARRAYS'.freeze
6
- ARRAY_OF_HASHES = 'ARRAY_OF_HASHES'.freeze
6
+ FLAT_HASH = 'FLAT_HASH'
7
+ HASH_OF_ARRAYS = 'HASH_OF_ARRAYS'
8
+ ARRAY_OF_HASHES = 'ARRAY_OF_HASHES'
9
+ HASH_OF_MULTIPLE_TYPES = 'HASH_OF_MULTIPLE_TYPES'
10
+ HASH_OF_HASHES = 'HASH_OF_HASHES'
11
+ SINGLE_HASH = 'SINGLE_HASH'
7
12
 
8
13
  def initialize(errors)
9
14
  @errors = errors
@@ -11,20 +16,41 @@ module RDStation
11
16
 
12
17
  def format
13
18
  return FLAT_HASH if flat_hash?
19
+ return SINGLE_HASH if single_hash?
14
20
  return HASH_OF_ARRAYS if hash_of_arrays?
21
+ return HASH_OF_HASHES if hash_of_hashes?
22
+ return HASH_OF_MULTIPLE_TYPES if hash_of_multiple_types?
23
+
15
24
  ARRAY_OF_HASHES
16
25
  end
17
26
 
18
27
  private
19
28
 
29
+ def single_hash?
30
+ return unless @errors.is_a?(Hash)
31
+
32
+ @errors.key?('error')
33
+ end
34
+
20
35
  def flat_hash?
21
36
  return unless @errors.is_a?(Hash)
37
+
22
38
  @errors.key?('error_type')
23
39
  end
24
40
 
25
41
  def hash_of_arrays?
26
42
  @errors.is_a?(Hash) && @errors.values.all? { |error| error.is_a? Array }
27
43
  end
44
+
45
+ def hash_of_hashes?
46
+ @errors.is_a?(Hash) && @errors.values.all? { |error| error.is_a? Hash }
47
+ end
48
+
49
+ def hash_of_multiple_types?
50
+ @errors.is_a?(Hash) &&
51
+ @errors.values.any? { |error| error.is_a? Hash } &&
52
+ @errors.values.any? { |error| error.is_a? Array }
53
+ end
28
54
  end
29
55
  end
30
56
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './format'
2
4
 
3
5
  module RDStation
@@ -11,27 +13,61 @@ module RDStation
11
13
  return @error_response unless @error_response.is_a?(Hash)
12
14
 
13
15
  case error_format.format
16
+ when RDStation::Error::Format::SINGLE_HASH
17
+ return from_single_hash
14
18
  when RDStation::Error::Format::FLAT_HASH
15
19
  return from_flat_hash
16
20
  when RDStation::Error::Format::HASH_OF_ARRAYS
17
21
  return from_hash_of_arrays
22
+ when RDStation::Error::Format::HASH_OF_HASHES
23
+ return from_hash_of_hashes
24
+ when RDStation::Error::Format::HASH_OF_MULTIPLE_TYPES
25
+ return from_hash_of_multiple_types
18
26
  end
19
27
 
20
28
  errors
21
29
  end
22
30
 
31
+ def from_single_hash
32
+ error_hash = @error_response.dup
33
+ error_message = error_hash.delete('error')
34
+
35
+ [
36
+ {
37
+ 'error_type' => 'TOO_MANY_REQUESTS',
38
+ 'error_message' => error_message,
39
+ 'details' => error_hash
40
+ }
41
+ ]
42
+ end
43
+
23
44
  def from_flat_hash
24
45
  [errors]
25
46
  end
26
47
 
27
- def from_hash_of_arrays
28
- errors.each_with_object([]) do |errors, array_of_errors|
29
- attribute_name = errors.first
30
- attribute_errors = errors.last
31
- path = { 'path' => "body.#{attribute_name}" }
32
- errors = attribute_errors.map { |error| error.merge(path) }
33
- array_of_errors.push(*errors)
48
+ def from_hash_of_multiple_types
49
+ array_of_errors = []
50
+ errors.each do |attribute_name, errors|
51
+ if errors.is_a? Array
52
+ result = build_error_from_array(attribute_name, errors)
53
+ end
54
+ if errors.is_a? Hash
55
+ result = build_error_from_multilingual_hash(attribute_name, errors)
56
+ end
57
+ array_of_errors.push(*result)
34
58
  end
59
+
60
+ array_of_errors
61
+ end
62
+
63
+ def from_hash_of_hashes
64
+ array_of_errors = []
65
+ errors.each do |attribute_name, errors|
66
+ result = build_error_from_multilingual_hash(attribute_name, errors)
67
+ array_of_errors.push(*result)
68
+ end
69
+
70
+ array_of_errors
35
71
  end
36
72
 
37
73
  def error_format
@@ -39,7 +75,32 @@ module RDStation
39
75
  end
40
76
 
41
77
  def errors
42
- @errors ||= @error_response['errors']
78
+ @errors ||= @error_response.fetch('errors', @error_response)
79
+ end
80
+
81
+ private
82
+
83
+ def build_error_from_array(attribute_name, attribute_errors)
84
+ path = { 'path' => "body.#{attribute_name}" }
85
+ attribute_errors.map { |error| error.merge(path) }
86
+ end
87
+
88
+ def build_error_from_multilingual_hash(attribute_name, errors_by_language)
89
+ array_of_errors = []
90
+ errors_by_language.each do |language, errors|
91
+ result = build_error_from_array("#{attribute_name}.#{language}", errors)
92
+ array_of_errors.push(*result)
93
+ end
94
+ array_of_errors
95
+ end
96
+
97
+ def from_hash_of_arrays
98
+ errors.each_with_object([]) do |errors, array_of_errors|
99
+ attribute_name = errors.first
100
+ attribute_errors = errors.last
101
+ errors = build_error_from_array(attribute_name, attribute_errors)
102
+ array_of_errors.push(*errors)
103
+ end
43
104
  end
44
105
  end
45
106
  end
@@ -32,11 +32,14 @@ module RDStation
32
32
  when 409 then RDStation::Error::Conflict
33
33
  when 415 then RDStation::Error::UnsupportedMediaType
34
34
  when 422 then RDStation::Error::UnprocessableEntity
35
+ when 429 then RDStation::Error::TooManyRequests
35
36
  when 500 then RDStation::Error::InternalServerError
36
37
  when 501 then RDStation::Error::NotImplemented
37
38
  when 502 then RDStation::Error::BadGateway
38
39
  when 503 then RDStation::Error::ServiceUnavailable
39
40
  when 500..599 then RDStation::Error::ServerError
41
+ else
42
+ RDStation::Error::UnknownError
40
43
  end
41
44
  end
42
45
 
@@ -55,7 +58,7 @@ module RDStation
55
58
  end
56
59
 
57
60
  def additional_error_attributes
58
- {
61
+ attrs = {
59
62
  'headers' => response.headers,
60
63
  'body' => JSON.parse(response.body),
61
64
  'http_status' => response.code,
@@ -0,0 +1,25 @@
1
+ module RDStation
2
+ class ErrorHandler
3
+ class InvalidRefreshToken
4
+ attr_reader :errors
5
+
6
+ ERROR_CODE = 'INVALID_REFRESH_TOKEN'.freeze
7
+
8
+ def initialize(errors)
9
+ @errors = errors
10
+ end
11
+
12
+ def raise_error
13
+ return unless invalid_refresh_token_error
14
+
15
+ raise RDStation::Error::InvalidRefreshToken, invalid_refresh_token_error
16
+ end
17
+
18
+ private
19
+
20
+ def invalid_refresh_token_error
21
+ errors.find { |error| error['error_type'] == ERROR_CODE }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,6 +1,7 @@
1
1
  require_relative 'expired_access_token'
2
2
  require_relative 'expired_code_grant'
3
3
  require_relative 'invalid_credentials'
4
+ require_relative 'invalid_refresh_token'
4
5
 
5
6
  module RDStation
6
7
  class ErrorHandler
@@ -9,6 +10,7 @@ module RDStation
9
10
  ErrorHandler::ExpiredAccessToken,
10
11
  ErrorHandler::ExpiredCodeGrant,
11
12
  ErrorHandler::InvalidCredentials,
13
+ ErrorHandler::InvalidRefreshToken,
12
14
  ].freeze
13
15
 
14
16
  def initialize(array_of_errors)
@@ -12,16 +12,8 @@ module RDStation
12
12
  def create(payload)
13
13
  retryable_request(@authorization) do |authorization|
14
14
  response = self.class.post(EVENTS_ENDPOINT, headers: authorization.headers, body: payload.to_json)
15
- response_body = JSON.parse(response.body)
16
- return response_body unless errors?(response_body)
17
- RDStation::ErrorHandler.new(response).raise_error
15
+ ApiResponse.build(response)
18
16
  end
19
17
  end
20
-
21
- private
22
-
23
- def errors?(response_body)
24
- response_body.is_a?(Array) || response_body['errors']
25
- end
26
18
  end
27
19
  end
@@ -1,12 +1,12 @@
1
1
  # encoding: utf-8
2
2
  module RDStation
3
- # More info: https://developers.rdstation.com/pt-BR/reference/contacts
3
+ # More info: https://developers.rdstation.com/pt-BR/reference/fields
4
4
  class Fields
5
5
  include HTTParty
6
6
  include ::RDStation::RetryableRequest
7
7
 
8
8
  BASE_URL = 'https://api.rd.services/platform/contacts/fields'.freeze
9
-
9
+
10
10
  def initialize(authorization:)
11
11
  @authorization = authorization
12
12
  end
@@ -18,5 +18,31 @@ module RDStation
18
18
  end
19
19
  end
20
20
 
21
+ def create(payload)
22
+ retryable_request(@authorization) do |authorization|
23
+ response = self.class.post(BASE_URL, headers: authorization.headers, body: payload.to_json)
24
+ ApiResponse.build(response)
25
+ end
26
+ end
27
+
28
+ def update(uuid, payload)
29
+ retryable_request(@authorization) do |authorization|
30
+ response = self.class.patch(base_url(uuid), headers: authorization.headers, body: payload.to_json)
31
+ ApiResponse.build(response)
32
+ end
33
+ end
34
+
35
+ def delete(uuid)
36
+ retryable_request(@authorization) do |authorization|
37
+ response = self.class.delete(base_url(uuid), headers: authorization.headers)
38
+ ApiResponse.build(response)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def base_url(path = '')
45
+ "#{BASE_URL}/#{path}"
46
+ end
21
47
  end
22
48
  end
@@ -1,3 +1,3 @@
1
1
  module RDStation
2
- VERSION = '2.2.0'.freeze
2
+ VERSION = '2.5.1'.freeze
3
3
  end
@@ -217,19 +217,32 @@ RSpec.describe RDStation::Authentication do
217
217
  end
218
218
 
219
219
  context 'when the refresh token is invalid' do
220
+ let(:invalid_refresh_token_response) do
221
+ {
222
+ status: 401,
223
+ headers: { 'Content-Type' => 'application/json' },
224
+ body: {
225
+ errors: {
226
+ error_type: 'INVALID_REFRESH_TOKEN',
227
+ error_message: 'The provided refresh token is invalid or was revoked.'
228
+ }
229
+ }.to_json
230
+ }
231
+ end
232
+
220
233
  before do
221
234
  stub_request(:post, token_endpoint)
222
235
  .with(
223
236
  headers: request_headers,
224
237
  body: token_request_with_invalid_refresh_token.to_json
225
238
  )
226
- .to_return(invalid_code_response)
239
+ .to_return(invalid_refresh_token_response)
227
240
  end
228
241
 
229
242
  it 'returns an auth error' do
230
243
  expect do
231
244
  authentication.update_access_token('invalid_refresh_token')
232
- end.to raise_error(RDStation::Error::InvalidCredentials)
245
+ end.to raise_error(RDStation::Error::InvalidRefreshToken)
233
246
  end
234
247
  end
235
248
 
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe RDStation::Builder::Field do
6
+ def valid_builder
7
+ described_class.new('cf_identifier')
8
+ end
9
+
10
+ describe 'when create a builder' do
11
+ context 'valid' do
12
+ let(:initial_parameters) do
13
+ 'cf_api_identifier'
14
+ end
15
+
16
+ let(:builder) { described_class.new(initial_parameters) }
17
+
18
+ let(:expected_result) do
19
+ {
20
+ 'api_identifier' => 'cf_api_identifier',
21
+ 'data_type' => 'STRING',
22
+ 'presentation_type' => 'TEXT_INPUT',
23
+ 'label' => { 'pt-BR' => 'My label' },
24
+ 'name' => { 'pt-BR' => 'My name' }
25
+ }
26
+ end
27
+
28
+ it 'returns an hash of required values' do
29
+ builder.label 'pt-BR', 'My label'
30
+ builder.name 'pt-BR', 'My name'
31
+ builder.data_type 'STRING'
32
+ builder.presentation_type 'TEXT_INPUT'
33
+
34
+ result = builder.build
35
+ expect(result).to eq(expected_result)
36
+ end
37
+ end
38
+
39
+ context 'invalid' do
40
+ it 'using invalid api_identifier ' do
41
+ expect { described_class.new('invald_identifier') }.to raise_error(
42
+ 'api_identifier is not in a valid format, need start with "cf_"'
43
+ )
44
+ end
45
+
46
+ it 'using invalid data_type ' do
47
+ expect { valid_builder.data_type('invalid_data_type') }.to raise_error(
48
+ 'Not valid data_type - ["STRING", "INTEGER", "BOOLEAN", "STRING[]"]'
49
+ )
50
+ end
51
+
52
+ it 'using invalid presentation_type ' do
53
+ expect { valid_builder.presentation_type('invalid presentation_type') }.to raise_error(
54
+ 'Not valid presentation_type - ["TEXT_INPUT", "TEXT_AREA", "URL_INPUT", "PHONE_INPUT", "EMAIL_INPUT", "CHECK_BOX", "NUMBER_INPUT", "COMBO_BOX", "RADIO_BUTTON", "MULTIPLE_CHOICE"]'
55
+ )
56
+ end
57
+
58
+ it 'without api_identifier' do
59
+ expect { described_class.new(nil) }.to raise_error('api_identifier required')
60
+ end
61
+
62
+ it 'without required fields' do
63
+ expect { valid_builder.build }.to raise_error(
64
+ 'Required fields are missing - ["data_type", "presentation_type", "label", "name"]'
65
+ )
66
+ end
67
+ end
68
+ end
69
+ end
@@ -52,5 +52,68 @@ RSpec.describe RDStation::Error::Format do
52
52
  expect(result).to eq(RDStation::Error::Format::ARRAY_OF_HASHES)
53
53
  end
54
54
  end
55
+
56
+ context 'when receives a mixed type of errors' do
57
+ let(:errors) do
58
+ {
59
+ 'label': {
60
+ 'pt-BR': [
61
+ {
62
+ 'error_type': 'CANNOT_BE_BLANK',
63
+ 'error_message': 'cannot be blank'
64
+ }
65
+ ]
66
+ },
67
+ 'api_identifier': [
68
+ {
69
+ 'error_type': 'CANNOT_BE_BLANK',
70
+ 'error_message': 'cannot be blank'
71
+ }
72
+ ]
73
+ }
74
+ end
75
+
76
+ it 'returns the HASH_OF_MULTIPLE_TYPES format' do
77
+ result = error_format.format
78
+ expect(result).to eq(RDStation::Error::Format::HASH_OF_MULTIPLE_TYPES)
79
+ end
80
+ end
81
+
82
+ context 'when receives a hash of hashes errors' do
83
+ let(:errors) do
84
+ {
85
+ label: {
86
+ 'pt-BR': [
87
+ {
88
+ 'error_type': 'CANNOT_BE_BLANK',
89
+ 'error_message': 'cannot be blank'
90
+ }
91
+ ]
92
+ }
93
+ }
94
+ end
95
+
96
+ it 'returns the HASH_OF_MULTILINGUAL format' do
97
+ result = error_format.format
98
+ expect(result).to eq(RDStation::Error::Format::HASH_OF_HASHES)
99
+ end
100
+ end
101
+
102
+ context 'when receives a single hash with error' do
103
+ let(:errors) do
104
+ {
105
+ 'error' => "'lead_limiter' rate limit exceeded for 86400 second(s) period for key ...",
106
+ 'max' => 24,
107
+ 'usage' => 55,
108
+ 'remaining_time' => 20745,
109
+ }
110
+ end
111
+
112
+ it 'returns the SINGLE_HASH format' do
113
+ result = error_format.format
114
+ expect(result).to eq(RDStation::Error::Format::SINGLE_HASH)
115
+ end
116
+
117
+ end
55
118
  end
56
119
  end
@@ -132,5 +132,118 @@ RSpec.describe RDStation::Error::Formatter do
132
132
  expect(result).to eq(expected_result)
133
133
  end
134
134
  end
135
+
136
+ context 'when receives a hash of multiple type errors' do
137
+ let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::HASH_OF_MULTIPLE_TYPES) }
138
+
139
+ let(:error_response) do
140
+ {
141
+ 'errors' => {
142
+ 'label' => {
143
+ 'pt-BR' => [
144
+ {
145
+ 'error_type' => 'CANNOT_BE_BLANK',
146
+ 'error_message' => 'cannot be blank'
147
+ }
148
+ ]
149
+ },
150
+ 'api_identifier' => [
151
+ {
152
+ 'error_type' => 'CANNOT_BE_BLANK',
153
+ 'error_message' => 'cannot be blank'
154
+ }
155
+ ]
156
+ }
157
+ }
158
+ end
159
+
160
+ let(:error_formatter) { described_class.new(error_response) }
161
+
162
+ let(:expected_result) do
163
+ [
164
+ {
165
+ 'error_type' => 'CANNOT_BE_BLANK',
166
+ 'error_message' => 'cannot be blank',
167
+ 'path' => 'body.label.pt-BR'
168
+ },
169
+ {
170
+ 'error_type' => 'CANNOT_BE_BLANK',
171
+ 'error_message' => 'cannot be blank',
172
+ 'path' => 'body.api_identifier'
173
+ }
174
+ ]
175
+ end
176
+
177
+ it 'returns an array of errors' do
178
+ result = error_formatter.to_array
179
+ expect(result).to eq(expected_result)
180
+ end
181
+ end
182
+
183
+ context 'when receives a hash of hashes type errors' do
184
+ let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::HASH_OF_HASHES) }
185
+
186
+ let(:error_response) do
187
+ {
188
+ 'errors' => {
189
+ 'label' => {
190
+ 'pt-BR' => [
191
+ {
192
+ 'error_type' => 'CANNOT_BE_BLANK',
193
+ 'error_message' => 'cannot be blank'
194
+ }
195
+ ]
196
+ }
197
+ }
198
+ }
199
+ end
200
+
201
+ let(:error_formatter) { described_class.new(error_response) }
202
+
203
+ let(:expected_result) do
204
+ [
205
+ {
206
+ 'error_type' => 'CANNOT_BE_BLANK',
207
+ 'error_message' => 'cannot be blank',
208
+ 'path' => 'body.label.pt-BR'
209
+ }
210
+ ]
211
+ end
212
+
213
+ it 'returns an array of errors' do
214
+ result = error_formatter.to_array
215
+ expect(result).to eq(expected_result)
216
+ end
217
+ end
218
+
219
+ context 'when receives a single hash of errors' do
220
+ let(:error_format) { instance_double(RDStation::Error::Format, format: RDStation::Error::Format::SINGLE_HASH) }
221
+
222
+ let(:error_response) do
223
+ {
224
+ 'error' => "'lead_limiter' rate limit exceeded for 86400 second(s) period for key",
225
+ 'max' => 24,
226
+ 'usage' => 55,
227
+ 'remaining_time' => 20745
228
+ }
229
+ end
230
+
231
+ let(:error_formatter) { described_class.new(error_response) }
232
+
233
+ let(:expected_result) do
234
+ [
235
+ {
236
+ 'error_type' => 'TOO_MANY_REQUESTS',
237
+ 'error_message' => "'lead_limiter' rate limit exceeded for 86400 second(s) period for key",
238
+ 'details' => { 'max' => 24, 'usage' => 55, 'remaining_time' => 20745 }
239
+ }
240
+ ]
241
+ end
242
+
243
+ it 'returns an array of errors' do
244
+ result = error_formatter.to_array
245
+ expect(result).to eq(expected_result)
246
+ end
247
+ end
135
248
  end
136
249
  end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RDStation::ErrorHandler::InvalidRefreshToken do
4
+ describe '#raise_error' do
5
+ subject(:invalid_refresh_token) { described_class.new(errors) }
6
+
7
+ context 'when the refresh token is invalid or was revoked' do
8
+ let(:errors) do
9
+ [
10
+ {
11
+ 'error_type' => 'INVALID_REFRESH_TOKEN',
12
+ 'error_message' => 'Error Message',
13
+ }
14
+ ]
15
+ end
16
+
17
+ it 'raises an InvalidRefreshToken error' do
18
+ expect do
19
+ invalid_refresh_token.raise_error
20
+ end.to raise_error(RDStation::Error::InvalidRefreshToken, 'Error Message')
21
+ end
22
+ end
23
+
24
+ context 'when none of the errors are invalid refresh token errors' do
25
+ let(:errors) do
26
+ [
27
+ {
28
+ 'error_message' => 'Error Message',
29
+ 'error_type' => 'RANDOM_ERROR_TYPE'
30
+ },
31
+ {
32
+ 'error_message' => 'Another Error Message',
33
+ 'error_type' => 'ANOTHER_RANDOM_ERROR_TYPE'
34
+ }
35
+ ]
36
+ end
37
+
38
+ it 'does not raise an InvalidRefreshToken error' do
39
+ result = invalid_refresh_token.raise_error
40
+ expect(result).to be_nil
41
+ end
42
+ end
43
+
44
+ context 'when there are no errors' do
45
+ let(:errors) { [] }
46
+
47
+ it 'does not raise an InvalidRefreshToken error' do
48
+ result = invalid_refresh_token.raise_error
49
+ expect(result).to be_nil
50
+ end
51
+ end
52
+ end
53
+ end
@@ -151,6 +151,7 @@ RSpec.describe RDStation::ErrorHandler do
151
151
  expect { error_handler.raise_error }.to raise_error(RDStation::Error::ServiceUnavailable, 'Error Message')
152
152
  end
153
153
  end
154
+
154
155
  context 'with 5xx error' do
155
156
  let(:http_status) { 505 }
156
157
 
@@ -172,5 +173,13 @@ RSpec.describe RDStation::ErrorHandler do
172
173
  expect { error_handler.raise_error }.to raise_error(RDStation::Error::BadGateway, '<html><body>HTML error response</body></html>')
173
174
  end
174
175
  end
176
+
177
+ context 'with an unknown error' do
178
+ let(:http_status) { 123 }
179
+
180
+ it 'raises a unknown error' do
181
+ expect { error_handler.raise_error }.to raise_error(RDStation::Error::UnknownError, 'Error Message')
182
+ end
183
+ end
175
184
  end
176
185
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdstation-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo L F Casaretto
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-13 00:00:00.000000000 Z
11
+ date: 2020-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -143,6 +143,7 @@ files:
143
143
  - lib/rdstation/api_response.rb
144
144
  - lib/rdstation/authentication.rb
145
145
  - lib/rdstation/authorization.rb
146
+ - lib/rdstation/builder/field.rb
146
147
  - lib/rdstation/client.rb
147
148
  - lib/rdstation/contacts.rb
148
149
  - lib/rdstation/error.rb
@@ -155,6 +156,7 @@ files:
155
156
  - lib/rdstation/error_handler/expired_code_grant.rb
156
157
  - lib/rdstation/error_handler/invalid_credentials.rb
157
158
  - lib/rdstation/error_handler/invalid_event_type.rb
159
+ - lib/rdstation/error_handler/invalid_refresh_token.rb
158
160
  - lib/rdstation/error_handler/unauthorized.rb
159
161
  - lib/rdstation/events.rb
160
162
  - lib/rdstation/fields.rb
@@ -166,6 +168,7 @@ files:
166
168
  - spec/lib/rdstation/api_response_spec.rb
167
169
  - spec/lib/rdstation/authentication_spec.rb
168
170
  - spec/lib/rdstation/authorization_spec.rb
171
+ - spec/lib/rdstation/builder/field_spec.rb
169
172
  - spec/lib/rdstation/client_spec.rb
170
173
  - spec/lib/rdstation/contacts_spec.rb
171
174
  - spec/lib/rdstation/error/format_spec.rb
@@ -175,6 +178,7 @@ files:
175
178
  - spec/lib/rdstation/error_handler/expired_code_grant_spec.rb
176
179
  - spec/lib/rdstation/error_handler/invalid_credentials_spec.rb
177
180
  - spec/lib/rdstation/error_handler/invalid_event_type_spec.rb
181
+ - spec/lib/rdstation/error_handler/invalid_refresh_token_spec.rb
178
182
  - spec/lib/rdstation/error_handler/unauthorized_spec.rb
179
183
  - spec/lib/rdstation/error_handler_spec.rb
180
184
  - spec/lib/rdstation/error_spec.rb
@@ -188,7 +192,7 @@ homepage: http://resultadosdigitais.com.br
188
192
  licenses:
189
193
  - MIT
190
194
  metadata: {}
191
- post_install_message:
195
+ post_install_message:
192
196
  rdoc_options: []
193
197
  require_paths:
194
198
  - lib
@@ -203,8 +207,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
207
  - !ruby/object:Gem::Version
204
208
  version: '0'
205
209
  requirements: []
206
- rubygems_version: 3.0.6
207
- signing_key:
210
+ rubygems_version: 3.0.8
211
+ signing_key:
208
212
  specification_version: 4
209
213
  summary: Ruby API wrapper for RD Station
210
214
  test_files:
@@ -212,6 +216,7 @@ test_files:
212
216
  - spec/lib/rdstation/api_response_spec.rb
213
217
  - spec/lib/rdstation/authentication_spec.rb
214
218
  - spec/lib/rdstation/authorization_spec.rb
219
+ - spec/lib/rdstation/builder/field_spec.rb
215
220
  - spec/lib/rdstation/client_spec.rb
216
221
  - spec/lib/rdstation/contacts_spec.rb
217
222
  - spec/lib/rdstation/error/format_spec.rb
@@ -221,6 +226,7 @@ test_files:
221
226
  - spec/lib/rdstation/error_handler/expired_code_grant_spec.rb
222
227
  - spec/lib/rdstation/error_handler/invalid_credentials_spec.rb
223
228
  - spec/lib/rdstation/error_handler/invalid_event_type_spec.rb
229
+ - spec/lib/rdstation/error_handler/invalid_refresh_token_spec.rb
224
230
  - spec/lib/rdstation/error_handler/unauthorized_spec.rb
225
231
  - spec/lib/rdstation/error_handler_spec.rb
226
232
  - spec/lib/rdstation/error_spec.rb