Skip to content

Commit

Permalink
feat: vehicle management functions (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
nbry authored Aug 17, 2023
1 parent 6b60a70 commit 8158ae5
Show file tree
Hide file tree
Showing 12 changed files with 400 additions and 19 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ The recommended method for obtaining the SDK is via Gradle or Maven through the

### Gradle
```groovy
compile "com.smartcar.sdk:java-sdk:3.6.0"
compile "com.smartcar.sdk:java-sdk:3.7.0"
```

### Maven
```xml
<dependency>
<groupId>com.smartcar.sdk</groupId>
<artifactId>java-sdk</artifactId>
<version>3.6.0</version>
<version>3.7.0</version>
</dependency>
```

### Jar Direct Download
* [java-sdk-3.6.0.jar](https://search.maven.org/remotecontent?filepath=com/smartcar/sdk/java-sdk/3.6.0/java-sdk-3.6.0.jar)
* [java-sdk-3.6.0-sources.jar](https://search.maven.org/remotecontent?filepath=com/smartcar/sdk/java-sdk/3.6.0/java-sdk-3.6.0-sources.jar)
* [java-sdk-3.6.0-javadoc.jar](https://search.maven.org/remotecontent?filepath=com/smartcar/sdk/java-sdk/3.6.0/java-sdk-3.6.0-javadoc.jar)
* [java-sdk-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/smartcar/sdk/java-sdk/3.7.0/java-sdk-3.7.0.jar)
* [java-sdk-3.7.0-sources.jar](https://search.maven.org/remotecontent?filepath=com/smartcar/sdk/java-sdk/3.7.0/java-sdk-3.7.0-sources.jar)
* [java-sdk-3.7.0-javadoc.jar](https://search.maven.org/remotecontent?filepath=com/smartcar/sdk/java-sdk/3.7.0/java-sdk-3.7.0-javadoc.jar)

Signatures and other downloads available at [Maven Central](https://search.maven.org/artifact/com.smartcar.sdk/java-sdk/3.6.0/jar).
Signatures and other downloads available at [Maven Central](https://search.maven.org/artifact/com.smartcar.sdk/java-sdk/3.7.0/jar).

## Usage

Expand Down Expand Up @@ -136,5 +136,5 @@ In accordance with the Semantic Versioning specification, the addition of suppor
[ci-url]: https://travis-ci.com/smartcar/java-sdk
[coverage-image]: https://codecov.io/gh/smartcar/java-sdk/branch/master/graph/badge.svg?token=nZAITx7w3X
[coverage-url]: https://codecov.io/gh/smartcar/java-sdk
[javadoc-image]: https://img.shields.io/badge/javadoc-3.6.0-brightgreen.svg
[javadoc-image]: https://img.shields.io/badge/javadoc-3.7.0-brightgreen.svg
[javadoc-url]: https://smartcar.github.io/java-sdk
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
libGroup=com.smartcar.sdk
libName=java-sdk
libVersion=3.6.0
libVersion=3.7.0
libDescription=Smartcar Java SDK
31 changes: 27 additions & 4 deletions src/integration/java/com/smartcar/sdk/SmartcarTest.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.smartcar.sdk;

import com.smartcar.sdk.data.Compatibility;
import com.smartcar.sdk.data.RequestPaging;
import com.smartcar.sdk.data.User;
import com.smartcar.sdk.data.VehicleIds;
import com.smartcar.sdk.data.*;
import com.smartcar.sdk.helpers.AuthHelpers;
import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
Expand All @@ -14,8 +11,10 @@

public class SmartcarTest {
private String accessToken;
private VehicleIds vehicleIds;
private String clientId = System.getenv("E2E_SMARTCAR_CLIENT_ID");
private String clientSecret = System.getenv("E2E_SMARTCAR_CLIENT_SECRET");
private String amt = System.getenv("E2E_SMARTCAR_AMT");
private AuthClient client;
private String authorizeUrl;
private String[] scope = {"read_odometer"};
Expand All @@ -26,6 +25,8 @@ public void beforeSuite() throws Exception {
this.authorizeUrl = client.authUrlBuilder(new String[]{"read_vehicle_info"}).build();
String code = AuthHelpers.runAuthFlow(client.authUrlBuilder(this.scope).build());
this.accessToken = client.exchangeCode(code).getAccessToken();
VehicleIds vehicleIds = Smartcar.getVehicles(this.accessToken);
this.vehicleIds = vehicleIds;
}

@Test
Expand Down Expand Up @@ -78,4 +79,26 @@ public void testGetCompatibility() throws Exception {
}
Assert.assertFalse((capable));
}

@Test
public void testGetConnections() throws SmartcarException {
String testVehicleId = this.vehicleIds.getVehicleIds()[0];
ConnectionsFilter filter = new ConnectionsFilter
.Builder()
.vehicleId(testVehicleId)
.build();
GetConnections connections = Smartcar.getConnections(this.amt, filter);
Assert.assertEquals(connections.getConnections().length, 1);
}

@Test
public void testDeleteConnections() throws SmartcarException {
String testVehicleId = this.vehicleIds.getVehicleIds()[0];
ConnectionsFilter filter = new ConnectionsFilter
.Builder()
.vehicleId(testVehicleId)
.build();
DeleteConnections connections = Smartcar.deleteConnections(this.amt, filter);
Assert.assertEquals(connections.getConnections().length, 1);
}
}
159 changes: 152 additions & 7 deletions src/main/java/com/smartcar/sdk/Smartcar.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.json.JsonObject;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Smartcar {
public static String API_VERSION = "2.0";
public static String API_ORIGIN = "https://api.smartcar.com";
public static String MANAGEMENT_API_ORIGIN = "https://management.smartcar.com";

/**
* Sets the Smartcar API version
Expand All @@ -40,7 +42,6 @@ static String getApiUrl() {
}

/**
*
* @return Smartcar API origin
*/
static String getApiOrigin() {
Expand All @@ -51,6 +52,17 @@ static String getApiOrigin() {
return apiOrigin;
}

/**
* @return Smartcar Management API origin
*/
static String getManagementApiOrigin() {
String managementApiOrigin = System.getenv("SMARTCAR_MANAGEMENT_API_ORIGIN");
if (managementApiOrigin == null) {
return MANAGEMENT_API_ORIGIN;
}
return managementApiOrigin;
}

/**
* Retrieves the user ID of the user authenticated with the specified access token.
*
Expand All @@ -72,7 +84,7 @@ public static User getUser(String accessToken) throws SmartcarException {
* Retrieves all vehicles associated with the authenticated user.
*
* @param accessToken a valid access token
* @param paging paging parameters
* @param paging paging parameters
* @return the requested vehicle IDs
* @throws SmartcarException if the request is unsuccessful
*/
Expand Down Expand Up @@ -111,7 +123,7 @@ public static VehicleIds getVehicles(String accessToken)
* Convenience method for determining if an auth token expiration has passed.
*
* @param expiration the expiration date of the token
* @return whether or not the token has expired
* @return whether the token has expired
*/
public static boolean isExpired(Date expiration) {
return !expiration.after(new Date());
Expand All @@ -129,7 +141,7 @@ public static boolean isExpired(Date expiration) {
*
* @param compatibilityRequest with options for this request. See Smartcar.SmartcarCompatibilityRequest
* @return A Compatibility object with isCompatible set to false if the vehicle is not compatible in the specified country and true if the vehicle is
* likely compatible.
* likely compatible.
* @throws SmartcarException when the request is unsuccessful
*/
public static Compatibility getCompatibility(SmartcarCompatibilityRequest compatibilityRequest) throws SmartcarException {
Expand All @@ -144,7 +156,6 @@ public static Compatibility getCompatibility(SmartcarCompatibilityRequest compat
.addQueryParameter("country", compatibilityRequest.getCountry());



if (compatibilityRequest.getFlags() != null) {
urlBuilder.addQueryParameter("flags", compatibilityRequest.getFlags());
}
Expand All @@ -168,6 +179,7 @@ public static Compatibility getCompatibility(SmartcarCompatibilityRequest compat

/**
* Performs a HmacSHA256 hash on a challenge string using the key provided
*
* @param key
* @param challenge
* @return String digest
Expand All @@ -186,13 +198,146 @@ public static String hashChallenge(String key, String challenge) throws Smartcar

/**
* Verifies as HmacSHA256 signature
*
* @param applicationManagementToken
* @param signature
* @param payload
* @return boolean whether or not the signature was verified
* @return boolean whether the signature was verified
* @throws SmartcarException
*/
public static boolean verifyPayload(String applicationManagementToken, String signature, String payload) throws SmartcarException {
return Smartcar.hashChallenge(applicationManagementToken, payload).equals(signature);
}

/**
* Returns a paged list of all the vehicles that are connected to the application associated
* with the management API token used sorted in descending order by connection date.
*
* @param applicationManagementToken
* @param filter
* @param paging
* @return connections
* @throws SmartcarException if the request is unsuccessful
*/
public static GetConnections getConnections(String applicationManagementToken, ConnectionsFilter filter, RequestPagingCursor paging)
throws SmartcarException {
// Build Request
HttpUrl.Builder urlBuilder = HttpUrl
.parse(Smartcar.getManagementApiOrigin() + "/v" + Smartcar.API_VERSION + "/management/connections")
.newBuilder();

if (filter != null) {
if (filter.getUserId() != null) {
urlBuilder
.addQueryParameter("user_id", String.valueOf(filter.getUserId()));
}
if (filter.getVehicleId() != null) {
urlBuilder
.addQueryParameter("vehicle_id", String.valueOf(filter.getVehicleId()));
}
}
if (paging != null) {
if (paging.getCursor() != null) {
urlBuilder
.addQueryParameter("cursor", String.valueOf(paging.getCursor()));
}
if (paging.getLimit() != null) {
urlBuilder
.addQueryParameter("limit", String.valueOf(paging.getLimit()));
}
}

HttpUrl url = urlBuilder.build();
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", Credentials.basic(
"default",
applicationManagementToken
));
Request request = ApiClient.buildRequest(url, "GET", null, headers);

return ApiClient.execute(request, GetConnections.class);
}

/**
* Returns a paged list of all the vehicles that are connected to the application associated
* with the management API token used sorted in descending order by connection date.
*
* @param applicationManagementToken
* @param filter
* @throws SmartcarException if the request is unsuccessful
*/
public static GetConnections getConnections(String applicationManagementToken, ConnectionsFilter filter)
throws SmartcarException {
return Smartcar.getConnections(applicationManagementToken, filter, null);
}

/**
* Returns a paged list of all the vehicles that are connected to the application associated
* with the management API token used sorted in descending order by connection date.
*
* @param applicationManagementToken
* @throws SmartcarException if the request is unsuccessful
*/
public static GetConnections getConnections(String applicationManagementToken)
throws SmartcarException {
return Smartcar.getConnections(applicationManagementToken, null, null);
}

/**
* Deletes all the connections by vehicle or user ID and returns a list of all connections that were deleted.
*
* @param applicationManagementToken
* @param filter
* @return connections
* @throws SmartcarException if the request is unsuccessful
*/
public static DeleteConnections deleteConnections(String applicationManagementToken, ConnectionsFilter filter)
throws SmartcarException {
// Build Request
HttpUrl.Builder urlBuilder = HttpUrl
.parse(Smartcar.getManagementApiOrigin() + "/v" + Smartcar.API_VERSION + "/management/connections")
.newBuilder();

if (filter != null) {
String userId = filter.getUserId();
String vehicleId = filter.getVehicleId();
if (userId != null && vehicleId != null) {
throw new SmartcarException
.Builder()
.type("SDK_ERROR")
.description("Filter can contain EITHER user_id OR vehicle_id, not both")
.build();
}
if (userId != null) {
urlBuilder
.addQueryParameter("user_id", String.valueOf(userId));
}
if (vehicleId != null) {
urlBuilder
.addQueryParameter("vehicle_id", String.valueOf(vehicleId));
}
}

HttpUrl url = urlBuilder.build();
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", Credentials.basic(
"default",
applicationManagementToken
));
Request request = ApiClient.buildRequest(url, "GET", null, headers);

return ApiClient.execute(request, DeleteConnections.class);
}

private static String getManagementToken(String applicationManagementToken, String username) {
String credentials = username + ":" + applicationManagementToken;
byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
return Base64.getEncoder().encodeToString(credentialsBytes);
}

private static String getManagementToken(String applicationManagementToken) {
String credentials = "default:" + applicationManagementToken;
byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
return Base64.getEncoder().encodeToString(credentialsBytes);
}
}
28 changes: 28 additions & 0 deletions src/main/java/com/smartcar/sdk/data/Connection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.smartcar.sdk.data;

public class Connection {
private String vehicleId;
private String userId;
private String connectedAt;

public String getVehicleId() {
return vehicleId;
}

public String getUserId() {
return userId;
}

public String getConnectedAt() {
return connectedAt;
}

@Override
public String toString() {
return "Connection{" +
"vehicleId='" + vehicleId + '\'' +
", userId='" + userId + '\'' +
", createdAt='" + connectedAt + '\'' +
'}';
}
}
Loading

0 comments on commit 8158ae5

Please sign in to comment.