smartcar 2.5.0 → 3.0.0

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: 3848d46ccf722b908e7b42acc1afebccc24fbf1362c36bd0b0a867cd8bdd5b85
4
- data.tar.gz: 3cfbf110c26177478a4ffad5373aeffcb73411b85f014c7af98293ea42739601
3
+ metadata.gz: 3f96ead76c474cc7bd2f579c79ae5457437b7826ea5738fc939e78e7fd15ad9a
4
+ data.tar.gz: 4ca101d8945328f524a4c4fe525eef8c0fa9ed5828a6d7fc1e7d96bccc299015
5
5
  SHA512:
6
- metadata.gz: f46fc77b3eafb462cfbd210d7509293368d9d2306ce8d16dbfbd4aad7a76339e53b689f06c2e50b3cc6eb56be5a390c805f8ae88384f6cfcdfa7e1ce27b34e91
7
- data.tar.gz: ee615279dc5c61e75ba1afd3ffa640b2df9ffafd4ea459cf22558d145e434b117814bd4279fcfd418643146eec4386911735f8f1066babd3ce494df44d15cfba
6
+ metadata.gz: c944b360628c97f3e78e6d1f7287e91c136a33cd8c696c0e8246c18839f97d790aea5457dc402ace57eda565f4937dbc72a51e5c66e70b12d24a1850674f6bcf
7
+ data.tar.gz: 73646b1545692c60714bd7581abef94f6271907587dc1ed2564dbae30adafb63b3c3d546b46f2188933fd2f4035a1eb8922fa4ef0c7e09a4fbd48a5d69c1cb11
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /.vscode/
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
data/.rubocop.yml CHANGED
@@ -7,6 +7,10 @@ AllCops:
7
7
  Metrics/AbcSize:
8
8
  Enabled: false
9
9
 
10
+ # Disabling this becuase we are using `set` and `get` prefixed methods to keep some commonality across SDKs
11
+ Naming/AccessorMethodName:
12
+ Enabled: false
13
+
10
14
  Metrics/BlockLength:
11
15
  Exclude:
12
16
  - '**/*.gemspec'
data/.travis.yml CHANGED
@@ -6,7 +6,6 @@ services:
6
6
  addons:
7
7
  firefox: latest
8
8
  rvm:
9
- - 2.5
10
9
  - 2.6
11
10
  - 2.7
12
11
  before_install:
@@ -25,5 +24,5 @@ deploy:
25
24
  on:
26
25
  tags: true
27
26
  branch: master
28
- rvm: 2.5
27
+ rvm: 2.6
29
28
  skip_cleanup: 'true'
data/Gemfile.lock CHANGED
@@ -1,22 +1,39 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smartcar (2.5.0)
4
+ smartcar (3.0.0)
5
5
  oauth2 (~> 1.4)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
+ addressable (2.7.0)
11
+ public_suffix (>= 2.0.2, < 5.0)
10
12
  ast (2.4.2)
13
+ backport (1.1.2)
11
14
  byebug (11.1.3)
12
15
  childprocess (3.0.0)
13
- diff-lcs (1.3)
14
- faraday (1.3.0)
16
+ codecov (0.5.2)
17
+ simplecov (>= 0.15, < 0.22)
18
+ crack (0.4.5)
19
+ rexml
20
+ diff-lcs (1.4.4)
21
+ docile (1.4.0)
22
+ faraday (1.4.2)
23
+ faraday-em_http (~> 1.0)
24
+ faraday-em_synchrony (~> 1.0)
25
+ faraday-excon (~> 1.1)
15
26
  faraday-net_http (~> 1.0)
27
+ faraday-net_http_persistent (~> 1.1)
16
28
  multipart-post (>= 1.2, < 3)
17
- ruby2_keywords
29
+ ruby2_keywords (>= 0.0.4)
30
+ faraday-em_http (1.0.0)
31
+ faraday-em_synchrony (1.0.0)
32
+ faraday-excon (1.1.0)
18
33
  faraday-net_http (1.0.1)
19
- jwt (2.2.2)
34
+ faraday-net_http_persistent (1.1.0)
35
+ hashdiff (1.0.1)
36
+ jwt (2.2.3)
20
37
  multi_json (1.15.0)
21
38
  multi_xml (0.6.0)
22
39
  multipart-post (2.1.1)
@@ -27,45 +44,60 @@ GEM
27
44
  multi_xml (~> 0.5)
28
45
  rack (>= 1.2, < 3)
29
46
  parallel (1.20.1)
30
- parser (3.0.0.0)
47
+ parser (3.0.1.1)
31
48
  ast (~> 2.4.1)
49
+ public_suffix (4.0.6)
32
50
  rack (2.2.3)
33
51
  rainbow (3.0.0)
34
52
  rake (12.3.3)
53
+ readapt (1.3.0)
54
+ backport (~> 1.1)
55
+ thor (~> 1.0)
35
56
  redcarpet (3.5.1)
36
57
  regexp_parser (2.1.1)
37
58
  rexml (3.2.5)
38
- rspec (3.9.0)
39
- rspec-core (~> 3.9.0)
40
- rspec-expectations (~> 3.9.0)
41
- rspec-mocks (~> 3.9.0)
42
- rspec-core (3.9.2)
43
- rspec-support (~> 3.9.3)
44
- rspec-expectations (3.9.2)
59
+ rspec (3.10.0)
60
+ rspec-core (~> 3.10.0)
61
+ rspec-expectations (~> 3.10.0)
62
+ rspec-mocks (~> 3.10.0)
63
+ rspec-core (3.10.1)
64
+ rspec-support (~> 3.10.0)
65
+ rspec-expectations (3.10.1)
45
66
  diff-lcs (>= 1.2.0, < 2.0)
46
- rspec-support (~> 3.9.0)
47
- rspec-mocks (3.9.1)
67
+ rspec-support (~> 3.10.0)
68
+ rspec-mocks (3.10.2)
48
69
  diff-lcs (>= 1.2.0, < 2.0)
49
- rspec-support (~> 3.9.0)
50
- rspec-support (3.9.3)
51
- rubocop (1.12.0)
70
+ rspec-support (~> 3.10.0)
71
+ rspec-support (3.10.2)
72
+ rubocop (1.16.1)
52
73
  parallel (~> 1.10)
53
74
  parser (>= 3.0.0.0)
54
75
  rainbow (>= 2.2.2, < 4.0)
55
76
  regexp_parser (>= 1.8, < 3.0)
56
77
  rexml
57
- rubocop-ast (>= 1.2.0, < 2.0)
78
+ rubocop-ast (>= 1.7.0, < 2.0)
58
79
  ruby-progressbar (~> 1.7)
59
80
  unicode-display_width (>= 1.4.0, < 3.0)
60
- rubocop-ast (1.4.1)
61
- parser (>= 2.7.1.5)
81
+ rubocop-ast (1.7.0)
82
+ parser (>= 3.0.1.1)
62
83
  ruby-progressbar (1.11.0)
63
84
  ruby2_keywords (0.0.4)
64
85
  rubyzip (2.3.0)
65
86
  selenium-webdriver (3.142.7)
66
87
  childprocess (>= 0.5, < 4.0)
67
88
  rubyzip (>= 1.2.2)
89
+ simplecov (0.21.2)
90
+ docile (~> 1.1)
91
+ simplecov-html (~> 0.11)
92
+ simplecov_json_formatter (~> 0.1)
93
+ simplecov-html (0.12.3)
94
+ simplecov_json_formatter (0.1.3)
95
+ thor (1.1.0)
68
96
  unicode-display_width (2.0.0)
97
+ webmock (3.13.0)
98
+ addressable (>= 2.3.6)
99
+ crack (>= 0.3.2)
100
+ hashdiff (>= 0.4.0, < 2.0.0)
69
101
 
70
102
  PLATFORMS
71
103
  ruby
@@ -73,12 +105,15 @@ PLATFORMS
73
105
  DEPENDENCIES
74
106
  bundler (~> 2.0)
75
107
  byebug (~> 11.0)
108
+ codecov (~> 0.5.2)
76
109
  rake (~> 12.3, >= 12.3.3)
110
+ readapt (~> 1.3)
77
111
  redcarpet (~> 3.5.0)
78
112
  rspec (~> 3.0)
79
113
  rubocop (~> 1.12)
80
114
  selenium-webdriver (~> 3.142)
81
115
  smartcar!
116
+ webmock (~> 3.13)
82
117
 
83
118
  BUNDLED WITH
84
119
  2.1.4
data/README.md CHANGED
@@ -29,28 +29,28 @@ not have access to the dashboard, please
29
29
 
30
30
  ### Flow
31
31
 
32
- - Create a new `AuthClient` object with your `clientId`, `clientSecret`,
33
- `redirectUri`, and required `scope`.
34
- - Redirect the user to Smartcar Connect using `getAuthUrl` or one
32
+ - Create a new `AuthClient` object with your `client_id`, `client_secret`,
33
+ `redirect_uri`.
34
+ - Redirect the user to Smartcar Connect using `get_auth_url` with required `scope` or with one
35
35
  of our frontend SDKs.
36
36
  - The user will login, and then accept or deny your `scope`'s permissions.
37
- - Handle the get request to `redirectUri`.
37
+ - Handle the get request to `redirect_uri`.
38
38
  - If the user accepted your permissions, `req.query.code` will contain an
39
39
  authorization code.
40
- - Use `exchangeCode` with this code to obtain an access object
40
+ - Use `exchange_code` with this code to obtain an access object
41
41
  containing an access token (lasting 2 hours) and a refresh token
42
42
  (lasting 60 days).
43
43
  - Save this access object.
44
44
  - If the user denied your permissions, `req.query.error` will be set
45
45
  to `"access_denied"`.
46
- - If you passed a state parameter to `getAuthUrl`, `req.query.state` will
46
+ - If you passed a state parameter to `get_auth_url`, `req.query.state` will
47
47
  contain the state value.
48
- - Get the user's vehicles with `getVehicleIds`.
49
- - Create a new `Vehicle` object using a `vehicleId` from the previous response,
48
+ - Get the user's vehicles with `getVehicles`.
49
+ - Create a new `Vehicle` object using a `vehicle_id` from the previous response,
50
50
  and the `access_token`.
51
51
  - Make requests to the Smartcar API.
52
- - Use `exchangeRefreshToken` on your saved `refreshToken` to retrieve a new token
53
- when your `accessToken` expires.
52
+ - Use `exchange_refresh_token` on your saved `refresh_token` to retrieve a new token
53
+ when your `access_token` expires.
54
54
 
55
55
  ## Installation
56
56
 
@@ -70,53 +70,47 @@ Or install it yourself as:
70
70
 
71
71
  ## Usage
72
72
 
73
- Setup the environment variables for CLIENT_ID and CLIENT_SECRET.
73
+ Setup the environment variables for SMARTCAR_CLIENT_ID, SMARTCAR_CLIENT_SECRET and SMARTCAR_REDIRECT_URI.
74
74
  ```bash
75
75
  # Get your API keys from https://dashboard.smartcar.com/signup
76
- export CLIENT_ID=<client id>
77
- export CLIENT_SECRET=<client secret>
76
+ export SMARTCAR_CLIENT_ID=<client id>
77
+ export SMARTCAR_CLIENT_SECRET=<client secret>
78
+ export SMARTCAR_REDIRECT_URI=<redirect URI>
78
79
  ```
79
80
 
80
81
  Example Usage for calling the reports API with oAuth token
81
82
  ```ruby
82
83
  2.5.7 :001 > require 'smartcar'
83
84
  => true
84
- 2.5.7 :003 > ids = Smartcar::Vehicle.all_vehicle_ids(token: token)
85
+ 2.5.7 :003 > ids = Smartcar::Vehicle.get_vehicles(token: token).vehicles
85
86
  => ["4bb777b2-bde7-4305-8952-25956f8c0868"]
86
87
  2.5.7 :004 > vehicle = Smartcar::Vehicle.new(token: token, id: ids.first)
87
- => #<Smartcar::Vehicle:0x00005564211a7c48 @token="5ae77cb0-7c1a-486a-ac20-00c76d2fd1aa", @id="4bb777b2-bde7-4305-8952-25956f8c0868", @unit_system="imperial">
88
+ => #<Smartcar::Vehicle:0x0000558dcd7ee608 @token="c900e00e-ee8e-403d-a7bf-f992bc0ad302", @id="e31c9de6-1332-472b-b648-5d74b05b7fda", @options={:unit_system=>"metric", :version=>"2.0"}, @unit_system="metric", @version="2.0", @service=#<Faraday::Connection:0x0000558dcd7d63f0 @parallel_manager=nil, @headers={"User-Agent"=>"Faraday v1.4.2"}, @params={}, @options=#<Faraday::RequestOptions timeout=310>, @ssl=#<Faraday::SSLOptions verify=true>, @default_parallel_manager=nil, @builder=#<Faraday::RackBuilder:0x0000558dcd7c1bf8 @adapter=Faraday::Adapter::NetHttp, @handlers=[Faraday::Request::UrlEncoded], @app=#<Faraday::Request::UrlEncoded:0x0000558dcd7af048 @app=#<Faraday::Adapter::NetHttp:0x0000558dcd7af390 @ssl_cert_store=#<OpenSSL::X509::Store:0x0000558dcd7a36a8 @verify_callback=nil, @error=nil, @error_string=nil, @chain=nil, @time=nil>, @app=#<Proc:0x0000558dcd7af278 /home/ashwinsubramanian/.rvm/gems/ruby-2.7.2/gems/faraday-1.4.2/lib/faraday/adapter.rb:37 (lambda)>, @connection_options={}, @config_block=nil>, @options={}>>, @url_prefix=#<URI::HTTPS https://api.smartcar.com/>, @proxy=nil, @manual_proxy=false>>
88
89
  2.5.7 :006 > vehicle.odometer
89
- => #<Smartcar::Odometer:0x00005564211330f0 @distance=17966.94802354251, @meta={"date"=>"Fri, 12 Jun 2020 06:04:32 GMT", "content-type"=>"application/json; charset=utf-8", "content-length"=>"30", "connection"=>"keep-alive", "access-control-allow-origin"=>"*", "sc-data-age"=>"2020-06-12T06:04:28.843Z", "sc-unit-system"=>"imperial", "sc-request-id"=>"3c447e9e-4cf7-43cb-b688-fba8db3d3582"}>
90
+ => #<OpenStruct distance=39685.33984375, meta=#<OpenStruct data_age=#<DateTime: 2021-06-24T22:28:39+00:00 ((2459390j,80919s,95000000n),+0s,2299161j)>, unit_system="metric", request_id="4962ba7f-5c94-48ab-9955-4e2b101c7b8a">>
90
91
  2.5.7 :007 > vehicle.battery
91
- => #<Smartcar::Battery:0x00005564210fcb18 @range=105.63, @percentRemaining=0.98, @meta={"date"=>"Fri, 12 Jun 2020 06:04:44 GMT", "content-type"=>"application/json; charset=utf-8", "content-length"=>"40", "connection"=>"keep-alive", "access-control-allow-origin"=>"*", "sc-data-age"=>"2020-06-12T06:04:28.843Z", "sc-unit-system"=>"imperial", "sc-request-id"=>"455ed4b0-b768-4961-86d7-436ad71cf0fa"}>
92
+ => #<OpenStruct range=208.82, percentRemaining=0.31, meta=#<OpenStruct data_age=#<DateTime: 2021-06-24T22:28:54+00:00 ((2459390j,80934s,855000000n),+0s,2299161j)>, unit_system="metric", request_id="a88b95ec-b10f-4fc8-979b-5d95fe40d925">, percentage_remaining=0.31>
92
93
  2.5.7 :009 > vehicle.lock!
93
- => true
94
- 2.5.7 :010 > vehicle.batch(["charge","battery"])
95
- => {:charge=>#<Smartcar::Charge:0x000055853d1fd7c8 @state="NOT_CHARGING", @isPluggedIn=false, @meta={"sc-data-age"=>"2020-06-12T06:18:50.581Z"}>, :battery=>#<Smartcar::Battery:0x000055853d1fd638 @range=105.63, @percentRemaining=0.98, @meta={"sc-data-age"=>"2020-06-12T06:18:50.581Z", "sc-unit-system"=>"imperial"}>}
96
- 2.5.7 :011 > vehicle.start_charge!
97
- Traceback (most recent call last):
98
- 5: from /usr/share/rvm/rubies/ruby-2.5.7/bin/irb:11:in `<main>'
99
- 4: from (irb):5
100
- 3: from /home/st-2vgpnn2/.rvm/gems/ruby-2.5.7/gems/smartcar-1.0.0/lib/smartcar/vehicle.rb:118:in `start_charge!'
101
- 2: from /home/st-2vgpnn2/.rvm/gems/ruby-2.5.7/gems/smartcar-1.0.0/lib/smartcar/vehicle.rb:290:in `start_or_stop_charge!'
102
- 1: from /home/st-2vgpnn2/.rvm/gems/ruby-2.5.7/gems/smartcar-1.0.0/lib/smartcar/base.rb:39:in `block (2 levels) in <class:Base>'
103
- Smartcar::ExternalServiceError (API error - {"error":"vehicle_state_error","message":"Charging plug is not connected to the vehicle.","code":"VS_004"})
104
-
94
+ => #<OpenStruct status="success", message="Successfully sent request to vehicle", meta=#<OpenStruct request_id="0c90918f-a9cc-405c-839f-7d9b70e249c4">>
95
+ 2.5.7 :010 > batch_response = vehicle.batch(["/charge","/battery"])
96
+ => #<OpenStruct>
97
+ 2.5.7 :011 > batch_response.charge()
98
+ => #<OpenStruct state="NOT_CHARGING", isPluggedIn=false, meta=#<OpenStruct data_age=#<DateTime: 2021-06-24T22:30:20+00:00 ((2459390j,81020s,892000000n),+0s,2299161j)>, request_id="29a66280-8685-4a57-9733-daa3dfb9970f">, is_plugged_in?=false>
105
99
  ```
106
100
 
107
101
  Example Usage for oAuth -
108
102
  ```ruby
109
103
  # To get the redirect URL :
110
- 2.5.5 :002 > options = {test_mode: true,scope: ["read_battery","read_charge","read_fuel","read_location","control_security","read_odometer","read_tires","read_vin","read_vehicle_info"],flags: ["country:DE"]}
104
+ 2.5.5 :002 > options = {test_mode: true}
111
105
  2.5.5 :003 > require 'smartcar'
112
- 2.5.5 :004 > client = Smartcar::Oauth.new(options)
113
- 2.5.5 :005 > url = client.authorization_url
106
+ 2.5.5 :004 > client = Smartcar::AuthClient.new(options)
107
+ 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"]})
114
108
  => "https://connect.smartcar.com/oauth/authorize?approval_prompt=auto&client_id=<client id>&mode=test&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fcallback&response_type=code&scope=read_battery+read_charge+read_fuel+read_location+control_security+read_odometer+read_tires+read_vin+read_vehicle_info&flags=country%3ADE"
115
109
  # Redirect user to the above URL.
116
110
  # After authentication user control reaches the callback URL with code.
117
111
  # Use the code from the parameters and request a token
118
- 2.5.5 :006 > token_hash = client.get_token(code)
119
- => {"token_type"=>"Bearer", :access_token=>"56801a5e-6a0b-4d05-a43e-52a4d5e6648f", :refresh_token=>"4f46e7e4-28c5-47b3-ba8d-7dcef73d05dd", :expires_at=>1577875279}
112
+ 2.5.5 :006 > token_hash = client.exchange_code(code)
113
+ => #<OpenStruct token_type="Bearer", access_token="20e24b4a-3055-4cc8-9cf3-2b3c5afba3e6", refresh_token="cf89c62e-7b36-4e13-a9df-d9c2a5296280", expires_at=1624581588>
120
114
  # This access_token can be used to call the Smartcar APIs as given above.
121
115
  # Store this hash and if it expired refresh the token OR use the code again to
122
116
  # get a new token or use .
@@ -128,8 +122,10 @@ To install this gem onto your local machine, run `bundle exec rake install`.
128
122
 
129
123
  To run tests, make sure you have the env variables setup for client id and secret.
130
124
  ```shell
131
- export INTEGRATION_CLIENT_ID=<client id>
132
- export INTEGRATION_CLIENT_SECRET=<client secret>
125
+ export E2E_SMARTCAR_CLIENT_ID=<client id>
126
+ export E2E_SMARTCAR_CLIENT_SECRET=<client secret>
127
+ export E2E_SMARTCAR_AMT=<amt from dashboard for webhooks>
128
+ export E2E_SMARTCAR_WEBHOOK_ID=<webhook id to use for tests>
133
129
  ```
134
130
 
135
131
  Tests can be run using either default rake command OR specific rspec command.
@@ -164,3 +160,9 @@ To contribute, please:
164
160
 
165
161
  [gem-image]: https://badge.fury.io/rb/smartcar
166
162
  [gem-url]: https://badge.fury.io/rb/smartcar.svg
163
+
164
+ ## Supported Ruby Branches
165
+
166
+ Smartcar aims to support the SDK on all Ruby branches that have a status of "normal maintenance" or "security maintenance" as defined in the [Ruby Branches documentation](https://www.ruby-lang.org/en/downloads/branches/).
167
+
168
+ In accordance with the Semantic Versioning specification, the addition of support for new Ruby branches would result in a MINOR version bump and the removal of support for Ruby branches would result in a MAJOR version bump.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extension to OpenStruct to convert a nested OpenStruct object to a hash.
4
+ # Using this method any of the API response can be converted back to hash
5
+ # or JSON (from hash) for convenience.
6
+ # Example Usage :
7
+ # response = {a: { b: {c: "test", d: [{x: 1}, {y: 3}]}}}
8
+ class OpenStruct
9
+ def deep_to_h
10
+ to_h.transform_values do |value|
11
+ case value
12
+ when is_a?(OpenStruct)
13
+ value.deep_to_h
14
+ when is_a?(Array)
15
+ value.map { |item| item.is_a?(OpenStruct) ? item.deep_to_h : item }
16
+ else
17
+ value
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/smartcar.rb CHANGED
@@ -1,83 +1,184 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'smartcar_error'
3
4
  require 'smartcar/utils'
4
5
  require 'smartcar/version'
5
6
  require 'smartcar/base'
6
- require 'smartcar/oauth'
7
- require 'smartcar/permissions'
8
- require 'smartcar/battery'
9
- require 'smartcar/battery_capacity'
10
- require 'smartcar/charge'
11
- require 'smartcar/engine_oil'
12
- require 'smartcar/fuel'
13
- require 'smartcar/location'
14
- require 'smartcar/odometer'
15
- require 'smartcar/tire_pressure'
16
- require 'smartcar/vin'
17
- require 'smartcar/vehicle_attributes'
18
- require 'smartcar/vehicle_utils/batch'
19
- require 'smartcar/vehicle_utils/data'
20
- require 'smartcar/vehicle_utils/actions'
7
+ require 'smartcar/auth_client'
21
8
  require 'smartcar/vehicle'
22
- require 'smartcar/user'
23
9
 
24
10
  # Main Smartcar umbrella module
25
11
  module Smartcar
26
12
  # Error raised when a config is not found
27
13
  class ConfigNotFound < StandardError; end
28
14
 
29
- # Error raised when Smartcar returns non 400, 404, 401, 200 or 204 response
30
- class ExternalServiceError < StandardError; end
31
-
32
- # Error raised when Smartcar returns 404
33
- class ServiceUnavailableError < ExternalServiceError; end
34
-
35
- # Error raised when Smartcar returns Authentication Error with status 401
36
- class AuthenticationError < ExternalServiceError; end
37
-
38
- # Error raised when Smartcar returns 400 response
39
- class BadRequestError < ExternalServiceError; end
40
-
41
15
  # Host to connect to smartcar
42
- SITE = 'https://api.smartcar.com/'
16
+ API_ORIGIN = 'https://api.smartcar.com/'
17
+ PATHS = {
18
+ compatibility: '/compatibility',
19
+ user: '/user',
20
+ vehicles: '/vehicles'
21
+ }.freeze
43
22
 
44
23
  # Path for smartcar oauth
45
- OAUTH_PATH = 'https://connect.smartcar.com/oauth/authorize'
24
+ AUTH_ORIGIN = 'https://connect.smartcar.com'
46
25
  %w[success code test live force auto metric imperial].each do |constant|
47
26
  # Constant to represent the value
48
27
  const_set(constant.upcase, constant.freeze)
49
28
  end
50
29
 
51
- # Lock value sent in request body
52
- LOCK = 'LOCK'
53
- # Unlock value sent in request body
54
- UNLOCK = 'UNLOCK'
55
- # Start charge value sent in request body
56
- START_CHARGE = 'START'
57
- # Stop charge value sent in request body
58
- STOP_CHARGE = 'STOP'
59
30
  # Constant for units
60
31
  UNITS = [IMPERIAL, METRIC].freeze
61
32
 
62
- # Smartcar API version variable - defaulted to 1.0
63
- @api_version = '1.0'
64
-
65
- # rubocop:disable Naming/AccessorMethodName
66
- # Module method Used to set api version to be used.
67
- # This method can be used at the top to set the version and any
68
- # following request will use the version set here unless overridden
69
- # separately.
70
- # @param version [String] version to be set without 'v' prefix.
71
- def self.set_api_version(version)
72
- instance_variable_set('@api_version', version)
73
- end
33
+ # Smartcar API version variable - defaulted to 2.0
34
+ @api_version = '2.0'
35
+
36
+ class << self
37
+ # Module method Used to set api version to be used.
38
+ # This method can be used at the top to set the version and any
39
+ # following request will use the version set here unless overridden
40
+ # separately.
41
+ # @param version [String] version to be set without 'v' prefix.
42
+ def set_api_version(version)
43
+ instance_variable_set('@api_version', version)
44
+ end
45
+
46
+ # Module method Used to get api version to be used.
47
+ # This is the getter for the class instance variable @api_version
48
+ #
49
+ # @return [String] api version number without 'v' prefix
50
+ def get_api_version
51
+ instance_variable_get('@api_version')
52
+ end
53
+
54
+ # Module method Used to check compatiblity for VIN and scope
55
+ #
56
+ # API Documentation - https://smartcar.com/docs/api#connect-compatibility
57
+ # @param vin [String] VIN of the vehicle to be checked
58
+ # @param scope [Array of Strings] - array of scopes
59
+ # @param country [String] An optional country code according to
60
+ # [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).
61
+ # Defaults to US.
62
+ # @param options [Hash] Other optional parameters including overrides
63
+ # @option options [String] :client_id Client ID that overrides ENV
64
+ # @option options [String] :client_secret Client Secret that overrides ENV
65
+ # @option options [String] :version API version to use, defaults to what is globally set
66
+ # @option options [Hash] :flags A hash of flag name string as key and a string or boolean value.
67
+ # @option options [Boolean] :test_mode Wether to use test mode or not.
68
+ # @option options [String] :test_mode_compatibility_level this is required argument while using
69
+ # test mode with a real vin. For more information refer to docs.
70
+ #
71
+ # @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#connect-compatibility
72
+ # and a meta attribute with the relevant items from response headers.
73
+ def get_compatibility(vin:, scope:, country: 'US', options: {})
74
+ raise InvalidParameterValue.new, 'vin is a required field' if vin.nil?
75
+ raise InvalidParameterValue.new, 'scope is a required field' if scope.nil?
76
+
77
+ base_object = Base.new(
78
+ {
79
+ version: options[:version] || Smartcar.get_api_version,
80
+ auth_type: Base::BASIC
81
+ }
82
+ )
83
+
84
+ base_object.token = generate_basic_auth(options, base_object)
85
+
86
+ base_object.build_response(*base_object.fetch(
87
+ {
88
+ path: PATHS[:compatibility],
89
+ query_params: build_compatibility_params(vin, scope, country, options)
90
+ }
91
+ ))
92
+ end
93
+
94
+ # Module method Used to get user id
95
+ #
96
+ # API Documentation - https://smartcar.com/docs/api#get-user
97
+ # @param token [String] Access token
98
+ #
99
+ # @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#get-user
100
+ # and a meta attribute with the relevant items from response headers.
101
+ def get_user(token:, version: Smartcar.get_api_version)
102
+ base_object = Base.new(
103
+ {
104
+ token: token,
105
+ version: version
106
+ }
107
+ )
108
+ base_object.build_response(*base_object.fetch({ path: PATHS[:user] }))
109
+ end
110
+
111
+ # Module method Returns a paged list of all vehicles connected to the application for the current authorized user.
112
+ #
113
+ # API Documentation - https://smartcar.com/docs/api#get-all-vehicles
114
+ # @param token [String] - Access token
115
+ # @param paging [Hash] - Optional filter parameters (check documentation)
116
+ #
117
+ # @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#get-all-vehicles
118
+ # and a meta attribute with the relevant items from response headers.
119
+ def get_vehicles(token:, paging: {}, version: Smartcar.get_api_version)
120
+ base_object = Base.new(
121
+ {
122
+ token: token,
123
+ version: version
124
+ }
125
+ )
126
+ base_object.build_response(*base_object.fetch(
127
+ {
128
+ path: PATHS[:vehicles],
129
+ query_params: paging
130
+ }
131
+ ))
132
+ end
133
+
134
+ # Module method to generate hash challenge for webhooks. It does HMAC_SHA256(amt, challenge)
135
+ #
136
+ # @param amt [String] - Application Management Token
137
+ # @param challenge [String] - Challenge string
138
+ #
139
+ # @return [String] String representing the hex digest
140
+ def hash_challenge(amt, challenge)
141
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), amt, challenge)
142
+ end
143
+
144
+ # Module method used to verify webhook payload with AMT and signature.
145
+ #
146
+ # @param amt [String] - Application Management Token
147
+ # @param signature [String] - sc-signature header value
148
+ # @param body [Object] - webhook response body
149
+ #
150
+ # @return [true, false] - true if signature matches the hex digest of amt and body
151
+ def verify_payload(amt, signature, body)
152
+ hash_challenge(amt, body.to_json) == signature
153
+ end
154
+
155
+ private
156
+
157
+ def build_compatibility_params(vin, scope, country, options)
158
+ query_params = {
159
+ vin: vin,
160
+ scope: scope.join(' '),
161
+ country: country
162
+ }
163
+ query_params[:flags] = options[:flags].map { |key, value| "#{key}:#{value}" }.join(' ') if options[:flags]
164
+ query_params[:mode] = options[:test_mode].is_a?(TrueClass) ? 'test' : 'live' unless options[:test_mode].nil?
165
+
166
+ if options[:test_mode_compatibility_level]
167
+ query_params[:test_mode_compatibility_level] =
168
+ options[:test_mode_compatibility_level]
169
+ query_params[:mode] = 'test'
170
+ end
171
+
172
+ query_params
173
+ end
74
174
 
75
- # Module method Used to get api version to be used.
76
- # This is the getter for the class instance variable @api_version
77
- #
78
- # @return [String] api version number without 'v' prefix
79
- def self.get_api_version
80
- instance_variable_get('@api_version')
175
+ # returns auth token for Basic auth
176
+ #
177
+ # @return [String] Base64 encoding of CLIENT:SECRET
178
+ def generate_basic_auth(options, base_object)
179
+ client_id = options[:client_id] || base_object.get_config('SMARTCAR_CLIENT_ID')
180
+ client_secret = options[:client_secret] || base_object.get_config('SMARTCAR_CLIENT_SECRET')
181
+ Base64.strict_encode64("#{client_id}:#{client_secret}")
182
+ end
81
183
  end
82
- # rubocop:enable Naming/AccessorMethodName
83
184
  end