Skip to content

Commit f9525ee

Browse files
committed
feat: support operation templates
1 parent e2254ec commit f9525ee

File tree

5 files changed

+237
-0
lines changed

5 files changed

+237
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.ctrlhub.core.governance.schemes.workorders.operations.templates
2+
3+
import com.ctrlhub.core.Api
4+
import com.ctrlhub.core.governance.schemes.workorders.operations.OperationsRouter
5+
import com.ctrlhub.core.governance.schemes.workorders.operations.templates.response.OperationTemplate
6+
import com.ctrlhub.core.router.Router
7+
import io.ktor.client.HttpClient
8+
9+
class OperationTemplatesRouter(httpClient: HttpClient) : Router(httpClient) {
10+
suspend fun all(organisationId: String): List<OperationTemplate> {
11+
return fetchJsonApiResources("/v3/orgs/$organisationId/governance/operation-templates")
12+
}
13+
14+
suspend fun one(organisationId: String, operationTemplateId: String): OperationTemplate {
15+
return fetchJsonApiResource("/v3/orgs/$organisationId/governance/operation-templates/$operationTemplateId")
16+
}
17+
}
18+
19+
val Api.operationTemplates: OperationTemplatesRouter
20+
get() = OperationTemplatesRouter(httpClient)
21+
22+
val OperationsRouter.templates: OperationTemplatesRouter
23+
get() = OperationTemplatesRouter(httpClient)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.ctrlhub.core.governance.schemes.workorders.operations.templates.response
2+
3+
import com.ctrlhub.core.governance.response.Label
4+
import com.fasterxml.jackson.annotation.JsonCreator
5+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
6+
import com.fasterxml.jackson.annotation.JsonProperty
7+
import com.github.jasminb.jsonapi.StringIdHandler
8+
import com.github.jasminb.jsonapi.annotations.Id
9+
import com.github.jasminb.jsonapi.annotations.Meta
10+
import com.github.jasminb.jsonapi.annotations.Type
11+
import java.time.LocalDateTime
12+
13+
@JsonIgnoreProperties(ignoreUnknown = true)
14+
@Type("operation-templates")
15+
class OperationTemplate @JsonCreator constructor(
16+
@Id(StringIdHandler::class) var id: String = "",
17+
@JsonProperty("labels") var labels: List<Label> = emptyList(),
18+
@JsonProperty("requirements") var requirements: OperationTemplateRequirements? = null,
19+
20+
@Meta
21+
var meta: OperationTemplateMeta = OperationTemplateMeta()
22+
) {
23+
constructor(): this(
24+
id = "",
25+
requirements = null
26+
)
27+
}
28+
29+
@JsonIgnoreProperties(ignoreUnknown = true)
30+
class OperationTemplateRequirements @JsonCreator constructor(
31+
var forms: List<OperationFormResult> = emptyList()
32+
) {
33+
constructor(): this(
34+
forms = emptyList()
35+
)
36+
}
37+
38+
@JsonIgnoreProperties(ignoreUnknown = true)
39+
class OperationTemplateMeta @JsonCreator constructor(
40+
@JsonProperty("created_at") var createdAt: LocalDateTime? = null,
41+
@JsonProperty("updated_at") var updatedAt: LocalDateTime? = null
42+
)
43+
44+
@JsonIgnoreProperties(ignoreUnknown = true)
45+
class OperationFormResult @JsonCreator constructor(
46+
var id: String = "",
47+
var required: Boolean = false
48+
) {
49+
constructor(): this(
50+
id = "",
51+
required = false
52+
)
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.ctrlhub.core.governance.schemes.workorders.operations.templates
2+
3+
import com.ctrlhub.core.configureForTest
4+
import com.ctrlhub.core.governance.schemes.workorders.operations.templates.response.OperationTemplate
5+
import io.ktor.client.*
6+
import io.ktor.client.engine.mock.*
7+
import io.ktor.http.*
8+
import kotlinx.coroutines.runBlocking
9+
import org.junit.jupiter.api.Test
10+
import java.nio.file.Files
11+
import java.nio.file.Paths
12+
import kotlin.test.assertIs
13+
import kotlin.test.assertNotNull
14+
15+
class OperationTemplatesRouterTest {
16+
17+
@Test
18+
fun `can retrieve all operation templates`() {
19+
val jsonFilePath = Paths.get("src/test/resources/governance/schemes/workorders/operations/templates/all-operation-templates-response.json")
20+
val jsonContent = Files.readString(jsonFilePath)
21+
22+
val mockEngine = MockEngine { _ ->
23+
respond(
24+
content = jsonContent,
25+
status = HttpStatusCode.OK,
26+
headers = headersOf(HttpHeaders.ContentType, "application/json")
27+
)
28+
}
29+
30+
val router = OperationTemplatesRouter(httpClient = HttpClient(mockEngine).configureForTest())
31+
32+
runBlocking {
33+
val response = router.all(
34+
organisationId = "org-123"
35+
)
36+
37+
assertIs<List<OperationTemplate>>(response)
38+
assertNotNull(response.first().id)
39+
}
40+
}
41+
42+
@Test
43+
fun `can retrieve a single operation template`() {
44+
val jsonFilePath = Paths.get("src/test/resources/governance/schemes/workorders/operations/templates/one-operation-template-response.json")
45+
val jsonContent = Files.readString(jsonFilePath)
46+
47+
val mockEngine = MockEngine { _ ->
48+
respond(
49+
content = jsonContent,
50+
status = HttpStatusCode.OK,
51+
headers = headersOf(HttpHeaders.ContentType, "application/json")
52+
)
53+
}
54+
55+
val router = OperationTemplatesRouter(httpClient = HttpClient(mockEngine).configureForTest())
56+
57+
runBlocking {
58+
val response = router.one(
59+
organisationId = "org-123",
60+
operationTemplateId = "template-456"
61+
)
62+
63+
assertIs<OperationTemplate>(response)
64+
assertNotNull(response.id)
65+
}
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"data": [
3+
{
4+
"id": "f3c6de1f-20f2-4c8a-9e0b-65e89d8df3a2",
5+
"type": "operation-templates",
6+
"attributes": {
7+
"labels": [
8+
{
9+
"key": "a",
10+
"value": "b"
11+
}
12+
],
13+
"name": "Test",
14+
"requirements": null
15+
},
16+
"meta": {
17+
"created_at": "2025-03-20T13:22:11Z",
18+
"updated_at": "2025-03-20T13:22:11Z"
19+
}
20+
}
21+
],
22+
"meta": {
23+
"features": {
24+
"params": {
25+
"include": {
26+
"options": null
27+
},
28+
"sort": {
29+
"default": "name",
30+
"options": [
31+
"name",
32+
"created_at"
33+
]
34+
},
35+
"filter": {
36+
"options": null
37+
}
38+
}
39+
},
40+
"count": 1,
41+
"pagination": {
42+
"current_page": 1,
43+
"counts": {
44+
"resources": 1,
45+
"pages": 1
46+
},
47+
"requested": {
48+
"offset": 0,
49+
"limit": 100
50+
},
51+
"offsets": {
52+
"previous": null,
53+
"next": null
54+
}
55+
}
56+
},
57+
"jsonapi": {
58+
"version": "1.0",
59+
"meta": {
60+
61+
}
62+
},
63+
"links": {
64+
"self": "https://api.ctrl-hub.dev/v3/orgs/f3c6de1f-20f2-4c8a-9e0b-65e89d8df3a2/governance/operation-templates"
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"data": {
3+
"id": "f3c6de1f-20f2-4c8a-9e0b-65e89d8df3a2",
4+
"type": "operation-templates",
5+
"attributes": {
6+
"labels": [
7+
{
8+
"key": "a",
9+
"value": "b"
10+
}
11+
],
12+
"name": "Test",
13+
"requirements": null
14+
},
15+
"meta": {
16+
"created_at": "2025-03-20T13:22:11Z",
17+
"updated_at": "2025-03-20T13:22:11Z"
18+
}
19+
},
20+
"meta": {},
21+
"jsonapi": {
22+
"version": "1.0",
23+
"meta": {}
24+
},
25+
"links": {
26+
"self": "https://api.ctrl-hub.dev/v3/orgs/f3c6de1f-20f2-4c8a-9e0b-65e89d8df3a2/governance/operation-templates/f3c6de1f-20f2-4c8a-9e0b-65e89d8df3a2"
27+
}
28+
}

0 commit comments

Comments
 (0)