smartcar 2.4.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d9d54665fb1e1c644ec917708c8f702d6eec0afec4b7bc14e5504a717da92d9
4
- data.tar.gz: 31d22b73a4406d512a738c694bc250b9eeab7e60ba1e137fbd11c221d05206fa
3
+ metadata.gz: e822148047b9ffd85867b85f13eec9bbba7785424d7c98982a65657f24b02019
4
+ data.tar.gz: 1322fbc3a032a209bdd8b7101e0e3e8baf2113972586399edb292ca82879a967
5
5
  SHA512:
6
- metadata.gz: 950dccc0e0ae5e801bd24d8516a11258ef386bbc706e13b7ed323cbd032bf4e61d45f32ba7ec49136e022777d700611838548a73e7b339e7d668b01d3a64266a
7
- data.tar.gz: 979f5ee0f0bb62255aec3f5c11c844b787da1a9710f025f18d9f6d99d95dd80dd5d4ce4ae681743583d4a50ea8d251184ed31a4fdcd8073d056dc3d9fd654da6
6
+ metadata.gz: 5e99928f83946aa9a62b48a0f920c1571442545b5320d2b5d3c9e0195a6b0835748ef54d9335bf6f29f2ffa47b60dab6e24ffd576af885dd37d6b1bfa1c35214
7
+ data.tar.gz: 48df4fe316d3eb55ca38630345f35f00ebec59d984d63854e03810d0dbde2e12ae9768fda8d6ec5d24911d7c82fa2be7844427d0390f50927a6ce88aa61d4f79
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 ADDED
@@ -0,0 +1,32 @@
1
+ # Prevent messages for libraries of rubocop
2
+ AllCops:
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+
6
+ # Disabling ABC size for now as refactoring few places seems pointless for now
7
+ Metrics/AbcSize:
8
+ Enabled: false
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
+
14
+ Metrics/BlockLength:
15
+ Exclude:
16
+ - '**/*.gemspec'
17
+ - 'spec/**/*'
18
+
19
+ # Just ignoring test helper for headless auth.
20
+ Metrics/MethodLength:
21
+ Max: 20
22
+ Exclude:
23
+ - 'spec/smartcar/helpers/auth_helper.rb'
24
+
25
+ # Parameters in data from json API comes in as camelCase, ignoring those files to avoid snake_case enforcement
26
+ Naming/MethodName:
27
+ Exclude:
28
+ - 'lib/smartcar/battery.rb'
29
+ - 'lib/smartcar/charge.rb'
30
+ - 'lib/smartcar/engine_oil.rb'
31
+ - 'lib/smartcar/fuel.rb'
32
+ - 'lib/smartcar/tire_pressure.rb'
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 CHANGED
@@ -1,6 +1,8 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
7
  # Specify your gem's dependencies in smartcar.gemspec
6
8
  gemspec
data/Gemfile.lock CHANGED
@@ -1,21 +1,44 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smartcar (2.4.0)
4
+ smartcar (3.0.2)
5
5
  oauth2 (~> 1.4)
6
+ recursive-open-struct (~> 1.1.3)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
11
+ addressable (2.8.0)
12
+ public_suffix (>= 2.0.2, < 5.0)
13
+ ast (2.4.2)
14
+ backport (1.1.2)
10
15
  byebug (11.1.3)
11
16
  childprocess (3.0.0)
12
- diff-lcs (1.3)
13
- faraday (1.3.0)
17
+ codecov (0.5.2)
18
+ simplecov (>= 0.15, < 0.22)
19
+ crack (0.4.5)
20
+ rexml
21
+ diff-lcs (1.4.4)
22
+ docile (1.4.0)
23
+ faraday (1.5.1)
24
+ faraday-em_http (~> 1.0)
25
+ faraday-em_synchrony (~> 1.0)
26
+ faraday-excon (~> 1.1)
27
+ faraday-httpclient (~> 1.0.1)
14
28
  faraday-net_http (~> 1.0)
29
+ faraday-net_http_persistent (~> 1.1)
30
+ faraday-patron (~> 1.0)
15
31
  multipart-post (>= 1.2, < 3)
16
- ruby2_keywords
32
+ ruby2_keywords (>= 0.0.4)
33
+ faraday-em_http (1.0.0)
34
+ faraday-em_synchrony (1.0.0)
35
+ faraday-excon (1.1.0)
36
+ faraday-httpclient (1.0.1)
17
37
  faraday-net_http (1.0.1)
18
- jwt (2.2.2)
38
+ faraday-net_http_persistent (1.2.0)
39
+ faraday-patron (1.0.0)
40
+ hashdiff (1.0.1)
41
+ jwt (2.2.3)
19
42
  multi_json (1.15.0)
20
43
  multi_xml (0.6.0)
21
44
  multipart-post (2.1.1)
@@ -25,27 +48,62 @@ GEM
25
48
  multi_json (~> 1.3)
26
49
  multi_xml (~> 0.5)
27
50
  rack (>= 1.2, < 3)
51
+ parallel (1.20.1)
52
+ parser (3.0.1.1)
53
+ ast (~> 2.4.1)
54
+ public_suffix (4.0.6)
28
55
  rack (2.2.3)
56
+ rainbow (3.0.0)
29
57
  rake (12.3.3)
58
+ readapt (1.3.0)
59
+ backport (~> 1.1)
60
+ thor (~> 1.0)
61
+ recursive-open-struct (1.1.3)
30
62
  redcarpet (3.5.1)
31
- rspec (3.9.0)
32
- rspec-core (~> 3.9.0)
33
- rspec-expectations (~> 3.9.0)
34
- rspec-mocks (~> 3.9.0)
35
- rspec-core (3.9.2)
36
- rspec-support (~> 3.9.3)
37
- rspec-expectations (3.9.2)
63
+ regexp_parser (2.1.1)
64
+ rexml (3.2.5)
65
+ rspec (3.10.0)
66
+ rspec-core (~> 3.10.0)
67
+ rspec-expectations (~> 3.10.0)
68
+ rspec-mocks (~> 3.10.0)
69
+ rspec-core (3.10.1)
70
+ rspec-support (~> 3.10.0)
71
+ rspec-expectations (3.10.1)
38
72
  diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.9.0)
40
- rspec-mocks (3.9.1)
73
+ rspec-support (~> 3.10.0)
74
+ rspec-mocks (3.10.2)
41
75
  diff-lcs (>= 1.2.0, < 2.0)
42
- rspec-support (~> 3.9.0)
43
- rspec-support (3.9.3)
76
+ rspec-support (~> 3.10.0)
77
+ rspec-support (3.10.2)
78
+ rubocop (1.16.1)
79
+ parallel (~> 1.10)
80
+ parser (>= 3.0.0.0)
81
+ rainbow (>= 2.2.2, < 4.0)
82
+ regexp_parser (>= 1.8, < 3.0)
83
+ rexml
84
+ rubocop-ast (>= 1.7.0, < 2.0)
85
+ ruby-progressbar (~> 1.7)
86
+ unicode-display_width (>= 1.4.0, < 3.0)
87
+ rubocop-ast (1.7.0)
88
+ parser (>= 3.0.1.1)
89
+ ruby-progressbar (1.11.0)
44
90
  ruby2_keywords (0.0.4)
45
91
  rubyzip (2.3.0)
46
92
  selenium-webdriver (3.142.7)
47
93
  childprocess (>= 0.5, < 4.0)
48
94
  rubyzip (>= 1.2.2)
95
+ simplecov (0.21.2)
96
+ docile (~> 1.1)
97
+ simplecov-html (~> 0.11)
98
+ simplecov_json_formatter (~> 0.1)
99
+ simplecov-html (0.12.3)
100
+ simplecov_json_formatter (0.1.3)
101
+ thor (1.1.0)
102
+ unicode-display_width (2.0.0)
103
+ webmock (3.13.0)
104
+ addressable (>= 2.3.6)
105
+ crack (>= 0.3.2)
106
+ hashdiff (>= 0.4.0, < 2.0.0)
49
107
 
50
108
  PLATFORMS
51
109
  ruby
@@ -53,11 +111,15 @@ PLATFORMS
53
111
  DEPENDENCIES
54
112
  bundler (~> 2.0)
55
113
  byebug (~> 11.0)
114
+ codecov (~> 0.5.2)
56
115
  rake (~> 12.3, >= 12.3.3)
116
+ readapt (~> 1.3)
57
117
  redcarpet (~> 3.5.0)
58
118
  rspec (~> 3.0)
119
+ rubocop (~> 1.12)
59
120
  selenium-webdriver (~> 3.142)
60
121
  smartcar!
122
+ webmock (~> 3.13)
61
123
 
62
124
  BUNDLED WITH
63
125
  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.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.
data/Rakefile CHANGED
@@ -1,6 +1,14 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new(:rubocop) do |t|
11
+ t.options = ['--display-cop-names']
12
+ end
13
+
14
+ task default: %i[rubocop spec]
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "smartcar"
4
+ require 'bundler/setup'
5
+ require 'smartcar'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "smartcar"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start(__FILE__)
data/lib/smartcar.rb CHANGED
@@ -1,73 +1,185 @@
1
- require "smartcar/utils"
2
- require "smartcar/version"
3
- require "smartcar/base"
4
- require "smartcar/oauth"
5
- require "smartcar/permissions"
6
- require "smartcar/battery"
7
- require "smartcar/battery_capacity"
8
- require "smartcar/charge"
9
- require "smartcar/engine_oil"
10
- require "smartcar/fuel"
11
- require "smartcar/location"
12
- require "smartcar/odometer"
13
- require "smartcar/tire_pressure"
14
- require "smartcar/vin"
15
- require "smartcar/vehicle_attributes"
16
- require "smartcar/vehicle"
17
- require "smartcar/user"
1
+ # frozen_string_literal: true
18
2
 
3
+ require 'recursive_open_struct'
4
+ require 'smartcar_error'
5
+ require 'smartcar/utils'
6
+ require 'smartcar/version'
7
+ require 'smartcar/base'
8
+ require 'smartcar/auth_client'
9
+ require 'smartcar/vehicle'
19
10
 
20
11
  # Main Smartcar umbrella module
21
12
  module Smartcar
22
13
  # Error raised when a config is not found
23
14
  class ConfigNotFound < StandardError; end
24
- # Error raised when Smartcar returns non 400, 404, 401, 200 or 204 response
25
- class ExternalServiceError < StandardError; end
26
- # Error raised when Smartcar returns 404
27
- class ServiceUnavailableError < ExternalServiceError; end
28
- # Error raised when Smartcar returns Authentication Error with status 401
29
- class AuthenticationError < ExternalServiceError; end
30
- # Error raised when Smartcar returns 400 response
31
- class BadRequestError < ExternalServiceError; end
32
15
 
33
16
  # Host to connect to smartcar
34
- SITE = "https://api.smartcar.com/".freeze
17
+ API_ORIGIN = 'https://api.smartcar.com/'
18
+ PATHS = {
19
+ compatibility: '/compatibility',
20
+ user: '/user',
21
+ vehicles: '/vehicles'
22
+ }.freeze
35
23
 
36
24
  # Path for smartcar oauth
37
- OAUTH_PATH = "https://connect.smartcar.com/oauth/authorize".freeze
38
- %w(success code test live force auto metric imperial).each do |constant|
25
+ AUTH_ORIGIN = 'https://connect.smartcar.com'
26
+ %w[success code test live force auto metric imperial].each do |constant|
39
27
  # Constant to represent the value
40
28
  const_set(constant.upcase, constant.freeze)
41
29
  end
42
30
 
43
- # Lock value sent in request body
44
- LOCK = "LOCK".freeze
45
- # Unlock value sent in request body
46
- UNLOCK = "UNLOCK".freeze
47
- # Start charge value sent in request body
48
- START_CHARGE = "START".freeze
49
- # Stop charge value sent in request body
50
- STOP_CHARGE = "STOP".freeze
51
31
  # Constant for units
52
- UNITS = [IMPERIAL,METRIC]
53
-
54
- # Smartcar API version variable - defaulted to 1.0
55
- @api_version = "1.0"
56
-
57
- # Module method Used to set api version to be used.
58
- # This method can be used at the top to set the version and any
59
- # following request will use the version set here unless overridden
60
- # separately.
61
- # @param version [String] version to be set without 'v' prefix.
62
- def self.set_api_version(version)
63
- instance_variable_set('@api_version', version)
64
- end
32
+ UNITS = [IMPERIAL, METRIC].freeze
33
+
34
+ # Smartcar API version variable - defaulted to 2.0
35
+ @api_version = '2.0'
36
+
37
+ class << self
38
+ # Module method Used to set api version to be used.
39
+ # This method can be used at the top to set the version and any
40
+ # following request will use the version set here unless overridden
41
+ # separately.
42
+ # @param version [String] version to be set without 'v' prefix.
43
+ def set_api_version(version)
44
+ instance_variable_set('@api_version', version)
45
+ end
46
+
47
+ # Module method Used to get api version to be used.
48
+ # This is the getter for the class instance variable @api_version
49
+ #
50
+ # @return [String] api version number without 'v' prefix
51
+ def get_api_version
52
+ instance_variable_get('@api_version')
53
+ end
54
+
55
+ # Module method Used to check compatiblity for VIN and scope
56
+ #
57
+ # API Documentation - https://smartcar.com/docs/api#connect-compatibility
58
+ # @param vin [String] VIN of the vehicle to be checked
59
+ # @param scope [Array of Strings] - array of scopes
60
+ # @param country [String] An optional country code according to
61
+ # [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).
62
+ # Defaults to US.
63
+ # @param options [Hash] Other optional parameters including overrides
64
+ # @option options [String] :client_id Client ID that overrides ENV
65
+ # @option options [String] :client_secret Client Secret that overrides ENV
66
+ # @option options [String] :version API version to use, defaults to what is globally set
67
+ # @option options [Hash] :flags A hash of flag name string as key and a string or boolean value.
68
+ # @option options [Boolean] :test_mode Wether to use test mode or not.
69
+ # @option options [String] :test_mode_compatibility_level this is required argument while using
70
+ # test mode with a real vin. For more information refer to docs.
71
+ #
72
+ # @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#connect-compatibility
73
+ # and a meta attribute with the relevant items from response headers.
74
+ def get_compatibility(vin:, scope:, country: 'US', options: {})
75
+ raise InvalidParameterValue.new, 'vin is a required field' if vin.nil?
76
+ raise InvalidParameterValue.new, 'scope is a required field' if scope.nil?
77
+
78
+ base_object = Base.new(
79
+ {
80
+ version: options[:version] || Smartcar.get_api_version,
81
+ auth_type: Base::BASIC
82
+ }
83
+ )
84
+
85
+ base_object.token = generate_basic_auth(options, base_object)
86
+
87
+ base_object.build_response(*base_object.fetch(
88
+ {
89
+ path: PATHS[:compatibility],
90
+ query_params: build_compatibility_params(vin, scope, country, options)
91
+ }
92
+ ))
93
+ end
94
+
95
+ # Module method Used to get user id
96
+ #
97
+ # API Documentation - https://smartcar.com/docs/api#get-user
98
+ # @param token [String] Access token
99
+ #
100
+ # @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#get-user
101
+ # and a meta attribute with the relevant items from response headers.
102
+ def get_user(token:, version: Smartcar.get_api_version)
103
+ base_object = Base.new(
104
+ {
105
+ token: token,
106
+ version: version
107
+ }
108
+ )
109
+ base_object.build_response(*base_object.fetch({ path: PATHS[:user] }))
110
+ end
111
+
112
+ # Module method Returns a paged list of all vehicles connected to the application for the current authorized user.
113
+ #
114
+ # API Documentation - https://smartcar.com/docs/api#get-all-vehicles
115
+ # @param token [String] - Access token
116
+ # @param paging [Hash] - Optional filter parameters (check documentation)
117
+ #
118
+ # @return [OpenStruct] And object representing the JSON response mentioned in https://smartcar.com/docs/api#get-all-vehicles
119
+ # and a meta attribute with the relevant items from response headers.
120
+ def get_vehicles(token:, paging: {}, version: Smartcar.get_api_version)
121
+ base_object = Base.new(
122
+ {
123
+ token: token,
124
+ version: version
125
+ }
126
+ )
127
+ base_object.build_response(*base_object.fetch(
128
+ {
129
+ path: PATHS[:vehicles],
130
+ query_params: paging
131
+ }
132
+ ))
133
+ end
134
+
135
+ # Module method to generate hash challenge for webhooks. It does HMAC_SHA256(amt, challenge)
136
+ #
137
+ # @param amt [String] - Application Management Token
138
+ # @param challenge [String] - Challenge string
139
+ #
140
+ # @return [String] String representing the hex digest
141
+ def hash_challenge(amt, challenge)
142
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), amt, challenge)
143
+ end
144
+
145
+ # Module method used to verify webhook payload with AMT and signature.
146
+ #
147
+ # @param amt [String] - Application Management Token
148
+ # @param signature [String] - sc-signature header value
149
+ # @param body [Object] - webhook response body
150
+ #
151
+ # @return [true, false] - true if signature matches the hex digest of amt and body
152
+ def verify_payload(amt, signature, body)
153
+ hash_challenge(amt, body.to_json) == signature
154
+ end
155
+
156
+ private
157
+
158
+ def build_compatibility_params(vin, scope, country, options)
159
+ query_params = {
160
+ vin: vin,
161
+ scope: scope.join(' '),
162
+ country: country
163
+ }
164
+ query_params[:flags] = options[:flags].map { |key, value| "#{key}:#{value}" }.join(' ') if options[:flags]
165
+ query_params[:mode] = options[:test_mode].is_a?(TrueClass) ? 'test' : 'live' unless options[:test_mode].nil?
166
+
167
+ if options[:test_mode_compatibility_level]
168
+ query_params[:test_mode_compatibility_level] =
169
+ options[:test_mode_compatibility_level]
170
+ query_params[:mode] = 'test'
171
+ end
172
+
173
+ query_params
174
+ end
65
175
 
66
- # Module method Used to get api version to be used.
67
- # This is the getter for the class instance variable @api_version
68
- #
69
- # @return [String] api version number without 'v' prefix
70
- def self.get_api_version
71
- instance_variable_get('@api_version')
176
+ # returns auth token for Basic auth
177
+ #
178
+ # @return [String] Base64 encoding of CLIENT:SECRET
179
+ def generate_basic_auth(options, base_object)
180
+ client_id = options[:client_id] || base_object.get_config('SMARTCAR_CLIENT_ID')
181
+ client_secret = options[:client_secret] || base_object.get_config('SMARTCAR_CLIENT_SECRET')
182
+ Base64.strict_encode64("#{client_id}:#{client_secret}")
183
+ end
72
184
  end
73
185
  end