smartcar 3.2.0 → 3.3.1

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: af85a8f04bb5ecfd37182ae539ef60e5ca4e9487edf5db544109417df43d82d0
4
- data.tar.gz: 5f2ccac9657e5e5b122b32943fa48845aa0acd5319dccc8836fd6b3cbf063ced
3
+ metadata.gz: fe729c83b0d759f2d787090e3f815ec9d97cd0b283585f8775ebe16e61b16e56
4
+ data.tar.gz: '029284bb31e8363b2cd0fe751705749e19365fb5692cbc3054325d648440117e'
5
5
  SHA512:
6
- metadata.gz: 47abd5b611ddc7089be88614c2b79a4d2c33db498f1254eea55f2ed1426b795752b47b7e08e9ac8825086790313738f16affdf536ebed450963b36fd0d1305e3
7
- data.tar.gz: 3ffef0a6f8f06da4c9f70a6798a9f701521831cdc30bbc183e613515b2b9520a492bd2d9e686a5c4cca0421d42def98bc0ccb6c4239cabd1d7b250ba5416f31d
6
+ metadata.gz: 6e469fcb92c39256e4a779476217fdb7cd5cce276af14d61ac9a51054e5d5e485f70e8f7886fb1852d2fb9d8128edd9b85164303f7c36fdca9d919f50bb0f4cb
7
+ data.tar.gz: faf78f8b977e3548e9f44fa45a59ce3b26cc89de53e6d85f3a8bc5391ced3031bdb2801696cb237cc2bb8c801bf85f7d2dd5bb6f15ccf2904430c65549c8ac86
data/.rubocop.yml CHANGED
@@ -12,7 +12,7 @@ Naming/AccessorMethodName:
12
12
  Enabled: false
13
13
 
14
14
  # Disabling this until we figure out a better way than using openstruct
15
- # Currently we use open struct because this gives us an object representing the JSON
15
+ # Currently we use open struct because this gives us an object representing the JSON
16
16
  # with accessor style methods.
17
17
  Style/OpenStructUse:
18
18
  Enabled: false
@@ -30,3 +30,9 @@ Metrics/MethodLength:
30
30
 
31
31
  Metrics/ClassLength:
32
32
  Max: 200
33
+
34
+ Metrics/CyclomaticComplexity:
35
+ Max: 10
36
+
37
+ Metrics/PerceivedComplexity:
38
+ Max: 10
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smartcar (3.2.0)
4
+ smartcar (3.3.1)
5
5
  oauth2 (~> 1.4)
6
6
  recursive-open-struct (~> 1.1.3)
7
7
 
data/README.md CHANGED
@@ -31,6 +31,7 @@ not have access to the dashboard, please
31
31
 
32
32
  - Create a new `AuthClient` object with your `client_id`, `client_secret`,
33
33
  `redirect_uri`.
34
+ -
34
35
  - Redirect the user to Smartcar Connect using `get_auth_url` with required `scope` or with one
35
36
  of our frontend SDKs.
36
37
  - The user will login, and then accept or deny your `scope`'s permissions.
@@ -76,6 +77,9 @@ Setup the environment variables for SMARTCAR_CLIENT_ID, SMARTCAR_CLIENT_SECRET a
76
77
  export SMARTCAR_CLIENT_ID=<client id>
77
78
  export SMARTCAR_CLIENT_SECRET=<client secret>
78
79
  export SMARTCAR_REDIRECT_URI=<redirect URI>
80
+ # Optional ENV variables
81
+ export SMARTCAR_CONNECT_ORIGIN=(default_value: connect.smartcar.com): Used as the host for the URL that starts the Connect/OAuth2 flow
82
+ export SMARTCAR_AUTH_ORIGIN=(default_value: auth.smartcar.com): Used as the host for the token exchange requests
79
83
  ```
80
84
 
81
85
  Example Usage for calling the reports API with oAuth token
@@ -101,7 +105,7 @@ Example Usage for calling the reports API with oAuth token
101
105
  Example Usage for oAuth -
102
106
  ```ruby
103
107
  # To get the redirect URL :
104
- 2.5.5 :002 > options = {test_mode: true}
108
+ 2.5.5 :002 > options = {mode: 'test'}
105
109
  2.5.5 :003 > require 'smartcar'
106
110
  2.5.5 :004 > client = Smartcar::AuthClient.new(options)
107
111
  2.5.5 :005 > url = client.get_auth_url(["read_battery","read_charge","read_fuel","read_location","control_security","read_odometer","read_tires","read_vin","read_vehicle_info"], {flags: ["country:DE"]})
@@ -6,7 +6,7 @@ module Smartcar
6
6
  class AuthClient
7
7
  include Smartcar::Utils
8
8
 
9
- attr_reader :redirect_uri, :client_id, :client_secret, :scope, :mode, :flags, :origin
9
+ attr_reader :redirect_uri, :client_id, :client_secret, :scope, :mode, :flags, :auth_origin, :connect_origin
10
10
 
11
11
  # Constructor for a client object
12
12
  #
@@ -14,15 +14,18 @@ module Smartcar
14
14
  # @option options[:client_id] [String] - Client ID, if not passed fallsback to ENV['SMARTCAR_CLIENT_ID']
15
15
  # @option options[:client_secret] [String] - Client Secret, if not passed fallsback to ENV['SMARTCAR_CLIENT_SECRET']
16
16
  # @option options[:redirect_uri] [String] - Redirect URI, if not passed fallsback to ENV['SMARTCAR_REDIRECT_URI']
17
- # @option options[:test_mode] [Boolean] - Setting this to 'true' runs it in test mode.
18
- #
17
+ # @option options[:test_mode] [Boolean] - [DEPRECATED], please use `mode` instead.
18
+ # Launch Smartcar Connect in [test mode](https://smartcar.com/docs/guides/testing/).
19
+ # @option options[:mode] [String] - Determine what mode Smartcar Connect should be launched in.
20
+ # Should be one of test, live or simulated.
19
21
  # @return [Smartcar::AuthClient] Returns a Smartcar::AuthClient Object that has other methods
20
22
  def initialize(options)
21
23
  options[:redirect_uri] ||= get_config('SMARTCAR_REDIRECT_URI')
22
24
  options[:client_id] ||= get_config('SMARTCAR_CLIENT_ID')
23
25
  options[:client_secret] ||= get_config('SMARTCAR_CLIENT_SECRET')
24
- options[:mode] = options[:test_mode].is_a?(TrueClass) ? TEST : LIVE
25
- options[:origin] = ENV['SMARTCAR_AUTH_ORIGIN'] || AUTH_ORIGIN
26
+ options[:auth_origin] = ENV['SMARTCAR_AUTH_ORIGIN'] || AUTH_ORIGIN
27
+ options[:connect_origin] = ENV['SMARTCAR_CONNECT_ORIGIN'] || CONNECT_ORIGIN
28
+ options[:mode] = determine_mode(options[:test_mode], options[:mode]) || 'live'
26
29
  super
27
30
  end
28
31
 
@@ -55,7 +58,7 @@ module Smartcar
55
58
  def get_auth_url(scope, options = {})
56
59
  initialize_auth_parameters(scope, options)
57
60
  add_single_select_options(options[:single_select])
58
- client.auth_code.authorize_url(@auth_parameters)
61
+ connect_client.auth_code.authorize_url(@auth_parameters)
59
62
  end
60
63
 
61
64
  # Generates the tokens hash using the code returned in oauth process.
@@ -68,9 +71,9 @@ module Smartcar
68
71
  def exchange_code(code, options = {})
69
72
  set_token_url(options[:flags])
70
73
 
71
- token_hash = client.auth_code
72
- .get_token(code, redirect_uri: redirect_uri)
73
- .to_hash
74
+ token_hash = auth_client.auth_code
75
+ .get_token(code, redirect_uri: redirect_uri)
76
+ .to_hash
74
77
 
75
78
  json_to_ostruct(token_hash)
76
79
  rescue OAuth2::Error => e
@@ -86,7 +89,7 @@ module Smartcar
86
89
  def exchange_refresh_token(token, options = {})
87
90
  set_token_url(options[:flags])
88
91
 
89
- token_object = OAuth2::AccessToken.from_hash(client, { refresh_token: token })
92
+ token_object = OAuth2::AccessToken.from_hash(auth_client, { refresh_token: token })
90
93
  token_object = token_object.refresh!
91
94
 
92
95
  json_to_ostruct(token_object.to_hash)
@@ -99,7 +102,7 @@ module Smartcar
99
102
  #
100
103
  # @return [Boolean]
101
104
  def expired?(expires_at)
102
- OAuth2::AccessToken.from_hash(client, { expires_at: expires_at }).expired?
105
+ OAuth2::AccessToken.from_hash(auth_client, { expires_at: expires_at }).expired?
103
106
  end
104
107
 
105
108
  private
@@ -115,7 +118,7 @@ module Smartcar
115
118
  params[:flags] = build_flags(flags) if flags
116
119
  # Note - The inbuild interface to get the token does not allow any way to pass additional
117
120
  # URL params. Hence building the token URL with the flags and setting it in client.
118
- client.options[:token_url] = client.connection.build_url('/oauth/token', params).request_uri
121
+ auth_client.options[:token_url] = auth_client.connection.build_url('/oauth/token', params).request_uri
119
122
  end
120
123
 
121
124
  def initialize_auth_parameters(scope, options)
@@ -142,13 +145,22 @@ module Smartcar
142
145
  end
143
146
  end
144
147
 
145
- # gets the Oauth Client object
148
+ # gets the Oauth Client object configured with auth.connect.smartcar.com
149
+ #
150
+ # @return [OAuth2::Client] A Oauth Client object.
151
+ def auth_client
152
+ @auth_client ||= OAuth2::Client.new(client_id,
153
+ client_secret,
154
+ site: auth_origin)
155
+ end
156
+
157
+ # gets the Oauth Client object configured with connect.smartcar.com
146
158
  #
147
159
  # @return [OAuth2::Client] A Oauth Client object.
148
- def client
149
- @client ||= OAuth2::Client.new(client_id,
150
- client_secret,
151
- site: origin)
160
+ def connect_client
161
+ @connect_client ||= OAuth2::Client.new(client_id,
162
+ client_secret,
163
+ site: connect_origin)
152
164
  end
153
165
  end
154
166
  end
data/lib/smartcar/base.rb CHANGED
@@ -22,7 +22,7 @@ module Smartcar
22
22
  # @param data [Hash] request body if needed.
23
23
  #
24
24
  # @return [Hash] The response Json parsed as a hash.
25
- define_method verb do |path, data = nil, headers = {}|
25
+ define_method verb do |path, query_params = {}, data = nil, headers = {}|
26
26
  response = service.send(verb) do |request|
27
27
  request_headers = {}
28
28
  request_headers['Authorization'] = auth_type == BASIC ? "Basic #{token}" : "Bearer #{token}"
@@ -32,6 +32,7 @@ module Smartcar
32
32
  "Smartcar/#{VERSION} (#{RbConfig::CONFIG['host_os']}; #{RbConfig::CONFIG['arch']}) Ruby v#{RUBY_VERSION}"
33
33
  request.headers = request_headers.merge(headers)
34
34
  complete_path = "/v#{version}#{path}"
35
+ complete_path += "?#{URI.encode_www_form(query_params.compact)}" unless query_params.empty?
35
36
  if verb == :get
36
37
  request.url complete_path, data
37
38
  else
@@ -46,17 +47,6 @@ module Smartcar
46
47
  end
47
48
  end
48
49
 
49
- # This requires a proc 'PATH' to be defined in the class
50
- # @param path [String] resource path
51
- # @param query_params [Hash] query params
52
- # @param auth [String] type of auth
53
- #
54
- # @return [Object]
55
- def fetch(path:, query_params: {})
56
- path += "?#{URI.encode_www_form(query_params)}" unless query_params.empty?
57
- get(path)
58
- end
59
-
60
50
  private
61
51
 
62
52
  # gets a smartcar API service/client
@@ -127,5 +127,25 @@ module Smartcar
127
127
 
128
128
  path.split('/').reject(&:empty?).join('_').to_sym
129
129
  end
130
+
131
+ # takes query parameters and returns them as a string
132
+ # EX - {'country': 'DE', 'flags': true} -> "county:DE flags:true"
133
+ def stringify_params(query_params)
134
+ query_params&.map { |key, value| "#{key}:#{value}" }&.join(' ')
135
+ end
136
+
137
+ def determine_mode(test_mode, mode)
138
+ unless mode.nil?
139
+ unless %w[test live simulated].include? mode
140
+ raise 'The "mode" parameter MUST be one of the following: \'test\', \'live\', \'simulated\''
141
+ end
142
+
143
+ return mode
144
+ end
145
+ return if test_mode.nil?
146
+
147
+ warn '[DEPRECATION] The "test_mode" parameter is deprecated, please use the "mode" parameter instead.'
148
+ test_mode.is_a?(TrueClass) ? 'test' : 'live'
149
+ end
130
150
  end
131
151
  end
@@ -11,6 +11,7 @@ module Smartcar
11
11
  # @attr [Hash] options
12
12
  # @attr unit_system [String] Unit system to represent the data in, defaults to Imperial
13
13
  # @attr version [String] API version to be used.
14
+ # @attr flags [Hash] Object of flags where key is the name of the flag and value is string or boolean value.
14
15
  # @attr service [Faraday::Connection] An optional connection object to be used for requests.
15
16
  class Vehicle < Base
16
17
  attr_reader :id
@@ -77,6 +78,7 @@ module Smartcar
77
78
  @unit_system = options[:unit_system] || METRIC
78
79
  @version = options[:version] || Smartcar.get_api_version
79
80
  @service = options[:service]
81
+ @query_params = { flags: stringify_params(options[:flags]) }
80
82
 
81
83
  raise InvalidParameterValue.new, "Invalid Units provided : #{@unit_system}" unless UNITS.include?(@unit_system)
82
84
  raise InvalidParameterValue.new, 'Vehicle ID (id) is a required field' if id.nil?
@@ -177,11 +179,11 @@ module Smartcar
177
179
  define_method method do
178
180
  body, headers = case item[:type]
179
181
  when :post
180
- post(item[:path].call(id), item[:body])
182
+ post(item[:path].call(id), @query_params, item[:body])
181
183
  when :delete
182
- delete(item[:path].call(id))
184
+ delete(item[:path].call(id), @query_params)
183
185
  else
184
- fetch(path: item[:path].call(id))
186
+ get(item[:path].call(id), @query_params)
185
187
  end
186
188
  build_aliases(build_response(body, headers), item[:aliases])
187
189
  end
@@ -195,7 +197,7 @@ module Smartcar
195
197
  # @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#get-application-permissions
196
198
  # and a meta attribute with the relevant items from response headers.
197
199
  def permissions(paging = {})
198
- response, headers = fetch(path: METHODS.dig(:permissions, :path).call(id), query_params: paging)
200
+ response, headers = get(METHODS.dig(:permissions, :path).call(id), @query_params.merge(paging))
199
201
  build_response(response, headers)
200
202
  end
201
203
 
@@ -206,7 +208,7 @@ module Smartcar
206
208
  # @return [OpenStruct] An object representing the JSON response and a meta attribute
207
209
  # with the relevant items from response headers.
208
210
  def subscribe!(webhook_id)
209
- response, headers = post(METHODS.dig(:subscribe!, :path).call(id, webhook_id), {})
211
+ response, headers = post(METHODS.dig(:subscribe!, :path).call(id, webhook_id), @query_params)
210
212
  build_aliases(build_response(response, headers), METHODS.dig(:subscribe!, :aliases))
211
213
  end
212
214
 
@@ -220,7 +222,8 @@ module Smartcar
220
222
  # swapping off the token with amt for unsubscribe.
221
223
  access_token = token
222
224
  self.token = amt
223
- response, headers = delete(METHODS.dig(:unsubscribe!, :path).call(id, webhook_id))
225
+ response, headers = delete(METHODS.dig(:unsubscribe!, :path).call(id, webhook_id),
226
+ @query_params)
224
227
  self.token = access_token
225
228
  build_response(response, headers)
226
229
  end
@@ -233,7 +236,7 @@ module Smartcar
233
236
  # an OpenStruct object of the requested attribute or taises if it is an error.
234
237
  def batch(paths)
235
238
  request_body = { requests: paths.map { |path| { path: path } } }
236
- response, headers = post("/vehicles/#{id}/batch", request_body)
239
+ response, headers = post("/vehicles/#{id}/batch", @query_params, request_body)
237
240
  process_batch_response(response, headers)
238
241
  end
239
242
 
@@ -249,7 +252,7 @@ module Smartcar
249
252
  # response body and a "meta" attribute with the relevant items from response headers.
250
253
  def request(method, path, body = {}, headers = {})
251
254
  path = "/vehicles/#{id}/#{path}"
252
- raw_response, headers = send(method.downcase, path, body, headers)
255
+ raw_response, headers = send(method.downcase, path, @query_params, body, headers)
253
256
  meta = build_meta(headers)
254
257
  json_to_ostruct({ body: raw_response, meta: meta })
255
258
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Smartcar
4
4
  # Gem current version number
5
- VERSION = '3.2.0'
5
+ VERSION = '3.3.1'
6
6
  end
data/lib/smartcar.rb CHANGED
@@ -22,7 +22,8 @@ module Smartcar
22
22
  }.freeze
23
23
 
24
24
  # Path for smartcar oauth
25
- AUTH_ORIGIN = 'https://connect.smartcar.com'
25
+ CONNECT_ORIGIN = 'https://connect.smartcar.com'
26
+ AUTH_ORIGIN = 'https://auth.smartcar.com'
26
27
  %w[success code test live force auto metric imperial].each do |constant|
27
28
  # Constant to represent the value
28
29
  const_set(constant.upcase, constant.freeze)
@@ -38,6 +39,7 @@ module Smartcar
38
39
  @api_version = '2.0'
39
40
 
40
41
  class << self
42
+ include Smartcar::Utils
41
43
  # Module method Used to set api version to be used.
42
44
  # This method can be used at the top to set the version and any
43
45
  # following request will use the version set here unless overridden
@@ -67,7 +69,10 @@ module Smartcar
67
69
  # @option options [String] :client_secret Client Secret that overrides ENV
68
70
  # @option options [String] :version API version to use, defaults to what is globally set
69
71
  # @option options [Hash] :flags A hash of flag name string as key and a string or boolean value.
70
- # @option options [Boolean] :test_mode Whether to use test mode or not.
72
+ # @option options[Boolean] :test_mode [DEPRECATED], please use `mode` instead.
73
+ # Launch Smartcar Connect in test mode(https://smartcar.com/docs/guides/testing/).
74
+ # @option options [String] :mode Determine what mode Smartcar Connect should be launched in.
75
+ # Should be one of test, live or simulated.
71
76
  # @option options [String] :test_mode_compatibility_level this is required argument while using
72
77
  # test mode with a real vin. For more information refer to docs.
73
78
  # @option options [Faraday::Connection] :service Optional connection object to be used for requests
@@ -88,9 +93,9 @@ module Smartcar
88
93
 
89
94
  base_object.token = generate_basic_auth(options, base_object)
90
95
 
91
- base_object.build_response(*base_object.fetch(
92
- path: PATHS[:compatibility],
93
- query_params: build_compatibility_params(vin, scope, country, options)
96
+ base_object.build_response(*base_object.get(
97
+ PATHS[:compatibility],
98
+ build_compatibility_params(vin, scope, country, options)
94
99
  ))
95
100
  end
96
101
 
@@ -112,7 +117,7 @@ module Smartcar
112
117
  service: options[:service]
113
118
  }
114
119
  )
115
- base_object.build_response(*base_object.fetch(path: PATHS[:user]))
120
+ base_object.build_response(*base_object.get(PATHS[:user]))
116
121
  end
117
122
 
118
123
  # Module method Returns a paged list of all vehicles connected to the application for the current authorized user.
@@ -134,9 +139,9 @@ module Smartcar
134
139
  service: options[:service]
135
140
  }
136
141
  )
137
- base_object.build_response(*base_object.fetch(
138
- path: PATHS[:vehicles],
139
- query_params: paging
142
+ base_object.build_response(*base_object.get(
143
+ PATHS[:vehicles],
144
+ paging
140
145
  ))
141
146
  end
142
147
 
@@ -169,15 +174,15 @@ module Smartcar
169
174
  scope: scope.join(' '),
170
175
  country: country
171
176
  }
172
- query_params[:flags] = options[:flags].map { |key, value| "#{key}:#{value}" }.join(' ') if options[:flags]
173
- query_params[:mode] = options[:test_mode].is_a?(TrueClass) ? 'test' : 'live' unless options[:test_mode].nil?
177
+ query_params[:flags] = stringify_params(options[:flags])
174
178
 
175
- if options[:test_mode_compatibility_level]
176
- query_params[:test_mode_compatibility_level] =
177
- options[:test_mode_compatibility_level]
178
- query_params[:mode] = 'test'
179
- end
179
+ mode = determine_mode(options[:test_mode], options[:mode])
180
180
 
181
+ unless options[:test_mode_compatibility_level].nil?
182
+ query_params[:test_mode_compatibility_level] = options[:test_mode_compatibility_level]
183
+ mode = 'test'
184
+ end
185
+ query_params[:mode] = mode unless mode.nil?
181
186
  query_params
182
187
  end
183
188
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartcar
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ashwin Subramanian
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-03 00:00:00.000000000 Z
11
+ date: 2023-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -235,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
235
  - !ruby/object:Gem::Version
236
236
  version: '0'
237
237
  requirements: []
238
- rubygems_version: 3.0.8
238
+ rubygems_version: 3.1.6
239
239
  signing_key:
240
240
  specification_version: 4
241
241
  summary: Ruby Gem to access smartcar APIs (https://smartcar.com/docs/)