Skip to content

Commit e87486c

Browse files
committed
feat: ability to interact with vehicle inspections api
1 parent f0948a2 commit e87486c

File tree

11 files changed

+490
-4
lines changed

11 files changed

+490
-4
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ dependencies {
2424
implementation(libs.ktor.logging.plugin)
2525
implementation(libs.jetbrains.kotlinx.serialization.json)
2626
implementation(libs.jsonapi.converter)
27+
implementation(libs.jackson.datatype.jsr)
2728

2829
testImplementation(kotlin("test"))
2930
testImplementation(libs.mockk)

gradle/libs.versions.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[versions]
2+
datatypeJsr = "2.15.0"
23
kotlin = "2.0.21"
34
ktor = "3.0.3"
45
kotlinSerialization = "1.7.3"
@@ -15,4 +16,5 @@ ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" }
1516
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
1617
jetbrains-kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" }
1718
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
18-
jsonapi-converter = { module = "com.github.jasminb:jsonapi-converter", version.ref = "jsonapi" }
19+
jsonapi-converter = { module = "com.github.jasminb:jsonapi-converter", version.ref = "jsonapi" }
20+
jackson-datatype-jsr = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "datatypeJsr" }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.ctrlhub.core.api
2+
3+
import kotlinx.serialization.Serializable
4+
5+
@Serializable
6+
data class ApiResourcePayload<T>(
7+
val type: String,
8+
val data: T
9+
)

src/main/kotlin/com/ctrlhub/core/assets/vehicles/VehicleCategoriesRouter.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import com.ctrlhub.core.router.Router
66
import com.ctrlhub.core.router.request.RequestParameters
77
import io.ktor.client.*
88

9+
/**
10+
* A router that interacts with the vehicle categories realm of the Ctrl Hub API
11+
*/
912
class VehicleCategoriesRouter(httpClient: HttpClient) : Router(httpClient) {
1013
private val endpoint = "/v3/assets/vehicles/categories"
1114

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.ctrlhub.core.assets.vehicles
2+
3+
import com.ctrlhub.core.api.ApiResourcePayload
4+
import com.ctrlhub.core.assets.vehicles.payload.VehicleInspectionPayload
5+
import com.ctrlhub.core.assets.vehicles.response.VehicleInspection
6+
import com.ctrlhub.core.router.Router
7+
import com.ctrlhub.core.router.request.RequestParameters
8+
import io.ktor.client.HttpClient
9+
import io.ktor.http.HttpStatusCode
10+
import kotlin.Result
11+
12+
/**
13+
* A router that interacts with the vehicle inspections realm of the Ctrl Hub API
14+
*/
15+
class VehicleInspectionsRouter(httpClient: HttpClient) : Router(httpClient) {
16+
private val resourceType = "vehicle-inspections"
17+
18+
/**
19+
* Retrieve all vehicle inspections
20+
*
21+
* @param organisationId String The associated organisation ID
22+
* @param vehicleId String The vehicle ID for which to retrieve inspections for
23+
* @param requestParameters RequestParameters An instance representing any request parameters for this API call
24+
*
25+
* @return A list of all vehicle inspections applicable to this vehicle
26+
*/
27+
suspend fun all(
28+
organisationId: String,
29+
vehicleId: String,
30+
requestParameters: RequestParameters = RequestParameters()
31+
): List<VehicleInspection> {
32+
val endpoint = "/v3/orgs/$organisationId/assets/vehicles/$vehicleId/inspections"
33+
34+
return fetchJsonApiResources(endpoint, requestParameters.toMap())
35+
}
36+
37+
/**
38+
* Retrieve a single vehicle inspections
39+
*
40+
* @param organisationId String The associated organisation ID
41+
* @param vehicleId String The vehicle ID for which to retrieve inspections for
42+
* @param inspectionId String The specific vehicle inspection ID to retrieve data for
43+
* @param requestParameters RequestParameters An instance representing any request parameters for this API call
44+
*
45+
* @return A VehicleInspection instance containing all data for the requested vehicle inspection
46+
*/
47+
suspend fun one(
48+
organisationId: String,
49+
vehicleId: String,
50+
inspectionId: String,
51+
requestParameters: RequestParameters = RequestParameters()
52+
): VehicleInspection {
53+
val endpoint = "/v3/orgs/$organisationId/assets/vehicles/$vehicleId/inspections/$inspectionId"
54+
55+
return fetchJsonApiResource(endpoint, requestParameters.toMap())
56+
}
57+
58+
/**
59+
* Create a single vehicle inspection
60+
*
61+
* @param organisationId String The associated organisation ID to create a vehicle inspection for
62+
* @param vehicleId String The vehicle ID to create a vehicle inspection against
63+
* @param payload VehicleInspectionPayload The payload to send
64+
*
65+
* @return A result representing the outcome of this operation
66+
*/
67+
suspend fun create(organisationId: String, vehicleId: String, payload: VehicleInspectionPayload): Result<Boolean> {
68+
return runCatching {
69+
val endpoint = "/v3/orgs/$organisationId/assets/vehicles/$vehicleId/inspections"
70+
71+
val response = performPost(
72+
endpoint, body = ApiResourcePayload(
73+
type = resourceType,
74+
data = payload
75+
)
76+
)
77+
response.status == HttpStatusCode.Created
78+
}
79+
}
80+
}
81+
82+
val VehiclesRouter.inspections: VehicleInspectionsRouter
83+
get() = VehicleInspectionsRouter(httpClient)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.ctrlhub.core.assets.vehicles.payload
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class VehicleInspectionPayload(
8+
val checks: VehicleInspectionChecksPayload
9+
)
10+
11+
@Serializable
12+
data class VehicleInspectionChecksPayload(
13+
val accessories: Boolean? = null,
14+
val beacons: Boolean? = null,
15+
@SerialName("chemicals_and_fuel") val chemicalsAndFuel: Boolean? = null,
16+
val cleanliness: Boolean? = null,
17+
@SerialName("driver_checks") val driverChecks: Boolean? = null,
18+
@SerialName("engine_warning_lights") val engineWarningLights: Boolean? = null,
19+
val levels: Boolean? = null,
20+
@SerialName("lights_and_indicators") val lightsAndIndicators: Boolean? = null,
21+
@SerialName("number_plate") val numberPlate: Boolean? = null,
22+
@SerialName("reversing_alarm") val reversingAlarm: Boolean? = null,
23+
@SerialName("safe_access") val safeAccess: Boolean? = null,
24+
val security: Boolean? = null,
25+
@SerialName("spare_number_plate") val spareNumberPlate: Boolean? = null,
26+
val storage: Boolean? = null,
27+
val tyres: Boolean? = null,
28+
@SerialName("visible_damage") val visibleDamage: Boolean? = null,
29+
@SerialName("washers_and_wipers") val washersAndWipers: Boolean? = null,
30+
val windscreen: Boolean? = null,
31+
)
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.ctrlhub.core.assets.vehicles.response
2+
3+
import com.ctrlhub.core.serializer.JacksonLocalDateTimeSerializer
4+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
5+
import com.fasterxml.jackson.annotation.JsonProperty
6+
import com.fasterxml.jackson.databind.annotation.JsonSerialize
7+
import com.github.jasminb.jsonapi.StringIdHandler
8+
import com.github.jasminb.jsonapi.annotations.Id
9+
import com.github.jasminb.jsonapi.annotations.Type
10+
import java.time.LocalDateTime
11+
12+
@Type("vehicle-inspections")
13+
@JsonIgnoreProperties(ignoreUnknown = true)
14+
class VehicleInspection {
15+
@Id(StringIdHandler::class)
16+
var id: String = ""
17+
var checks: VehicleInspectionChecks? = null
18+
19+
@JsonProperty("inspected_at")
20+
@JsonSerialize(contentUsing = JacksonLocalDateTimeSerializer::class)
21+
var inspectedAt: LocalDateTime? = null
22+
}
23+
24+
@JsonIgnoreProperties(ignoreUnknown = true)
25+
class VehicleInspectionChecks {
26+
@JsonProperty("visible_damage")
27+
var visibleDamage: Boolean? = null
28+
29+
@JsonProperty("tyres")
30+
var tyres: Boolean? = null
31+
32+
@JsonProperty("washers_and_wipers")
33+
var washersAndWipers: Boolean? = null
34+
35+
@JsonProperty("windscreen")
36+
var windscreen: Boolean? = null
37+
38+
@JsonProperty("number_plate")
39+
var numberPlate: Boolean? = null
40+
41+
@JsonProperty("security")
42+
var security: Boolean? = null
43+
44+
@JsonProperty("accessories")
45+
var accessories: Boolean? = null
46+
47+
@JsonProperty("spare_number_plate")
48+
var spareNumberPlate: Boolean? = null
49+
50+
@JsonProperty("safe_access")
51+
var safeAccess: Boolean? = null
52+
53+
@JsonProperty("reversing_alarm")
54+
var reversingAlarm: Boolean? = null
55+
56+
@JsonProperty("beacons")
57+
var beacons: Boolean? = null
58+
59+
@JsonProperty("chemicals_and_fuel")
60+
var chemicalsAndFuel: Boolean? = null
61+
62+
@JsonProperty("storage")
63+
var storage: Boolean? = null
64+
65+
@JsonProperty("lights_and_indicators")
66+
var lightsAndIndicators: Boolean? = null
67+
68+
@JsonProperty("engine_warning_lights")
69+
var engineWarningLights: Boolean? = null
70+
71+
@JsonProperty("servicing")
72+
var servicing: Boolean? = null
73+
74+
@JsonProperty("levels")
75+
var levels: Boolean? = null
76+
77+
@JsonProperty("cleanliness")
78+
var cleanliness: Boolean? = null
79+
80+
@JsonProperty("driver_checks")
81+
var driverChecks: Boolean? = null
82+
}

src/main/kotlin/com/ctrlhub/core/router/Router.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package com.ctrlhub.core.router
33
import com.ctrlhub.core.api.ApiClientException
44
import com.ctrlhub.core.api.ApiException
55
import com.ctrlhub.core.api.UnauthorizedException
6+
import com.fasterxml.jackson.databind.ObjectMapper
7+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
68
import com.github.jasminb.jsonapi.ResourceConverter
79
import com.github.jasminb.jsonapi.SerializationFeature
810
import io.ktor.client.*
@@ -12,7 +14,7 @@ import io.ktor.client.request.*
1214
import io.ktor.client.statement.*
1315
import io.ktor.http.*
1416

15-
abstract class Router(protected val httpClient: HttpClient) {
17+
abstract class Router(val httpClient: HttpClient) {
1618
protected suspend fun performGet(endpoint: String, queryString: Map<String, String> = emptyMap()): HttpResponse {
1719
return httpClient.get(endpoint) {
1820
url {
@@ -47,7 +49,7 @@ abstract class Router(protected val httpClient: HttpClient) {
4749
protected suspend inline fun <reified T> fetchJsonApiResource(endpoint: String, queryParameters: Map<String, String> = emptyMap()): T {
4850
return try {
4951
val rawResponse = performGet(endpoint, queryParameters)
50-
val resourceConverter = ResourceConverter(T::class.java).apply {
52+
val resourceConverter = ResourceConverter(getObjectMapper(), T::class.java).apply {
5153
enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES)
5254
}
5355
val jsonApiResponse = resourceConverter.readDocument<T>(rawResponse.body<ByteArray>(), T::class.java)
@@ -67,7 +69,7 @@ abstract class Router(protected val httpClient: HttpClient) {
6769
protected suspend inline fun <reified T> fetchJsonApiResources(endpoint: String, queryParameters: Map<String, String> = emptyMap()): List<T> {
6870
return try {
6971
val rawResponse = performGet(endpoint, queryParameters)
70-
val resourceConverter = ResourceConverter(T::class.java).apply {
72+
val resourceConverter = ResourceConverter(getObjectMapper(), T::class.java).apply {
7173
enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES)
7274
}
7375
val jsonApiResponse = resourceConverter.readDocumentCollection<T>(rawResponse.body<ByteArray>(), T::class.java)
@@ -83,4 +85,10 @@ abstract class Router(protected val httpClient: HttpClient) {
8385
throw ApiException("Request failed: $endpoint", e)
8486
}
8587
}
88+
89+
fun getObjectMapper(): ObjectMapper {
90+
return ObjectMapper().apply {
91+
registerModule(JavaTimeModule())
92+
}
93+
}
8694
}

0 commit comments

Comments
 (0)