Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.ctrlhub.core.datacapture

import com.ctrlhub.core.Api
import com.ctrlhub.core.datacapture.resource.FormSubmissionVersion
import com.ctrlhub.core.datacapture.response.FormSchema
import com.ctrlhub.core.router.Router
import io.ktor.client.HttpClient
import io.ktor.http.ContentType
import com.ctrlhub.core.api.response.PaginatedList

class FormSubmissionVersionsRouter(httpClient: HttpClient) : Router(httpClient) {
/**
* Create a new form submission version
*/
suspend fun create(organisationId: String, formId: String, schemaId: String, payload: Map<String, Any>): FormSubmissionVersion {
return postJsonApiResource(
"/v3/orgs/$organisationId/data-capture/forms/$formId/submissions",
requestBody = FormSubmissionVersion(
payload = payload,
id = "",
schema = FormSchema(
id = schemaId,
rawSchema = null,
)
),
queryParameters = emptyMap(),
contentType = ContentType.parse("application/vnd.api+json"),
FormSubmissionVersion::class.java,
FormSchema::class.java
)
}

/**
* Get all submission versions for a given form (paginated)
*/
suspend fun all(organisationId: String, formId: String, submissionId: String): PaginatedList<FormSubmissionVersion> {
return fetchPaginatedJsonApiResources(
"/v3/orgs/$organisationId/data-capture/forms/$formId/submissions/$submissionId/versions",
queryParameters = emptyMap(),
FormSubmissionVersion::class.java,
FormSchema::class.java
)
}

/**
* Get a single submission version
*/
suspend fun one(organisationId: String, formId: String, submissionId: String, versionId: String): FormSubmissionVersion {
return fetchJsonApiResource(
"/v3/orgs/$organisationId/data-capture/forms/$formId/submissions/$submissionId/versions/$versionId",
queryParameters = emptyMap(),
FormSubmissionVersion::class.java,
FormSchema::class.java
)
}
}

val Api.formSubmissionVersions
get() = FormSubmissionVersionsRouter(httpClient = httpClient)
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
package com.ctrlhub.core.datacapture

import com.ctrlhub.core.Api
import com.ctrlhub.core.datacapture.resource.FormSubmissionVersion
import com.ctrlhub.core.datacapture.response.FormSchema
import com.ctrlhub.core.datacapture.response.FormSubmission
import com.ctrlhub.core.datacapture.response.Form
import com.ctrlhub.core.iam.response.User
import com.ctrlhub.core.projects.response.Organisation
import com.ctrlhub.core.router.Router
import io.ktor.client.HttpClient
import io.ktor.http.ContentType
import com.ctrlhub.core.api.response.PaginatedList

class FormSubmissionsRouter(httpClient: HttpClient) : Router(httpClient) {
suspend fun create(organisationId: String, formId: String, schemaId: String, payload: Map<String, Any>): FormSubmissionVersion {
return postJsonApiResource("/v3/orgs/$organisationId/data-capture/forms/$formId/submissions", requestBody = FormSubmissionVersion(
payload = payload,
id = "",
schema = FormSchema(
id = schemaId,
rawSchema = null,
)
), queryParameters = emptyMap(), contentType = ContentType.parse("application/vnd.api+json"), FormSubmissionVersion::class.java,
FormSchema::class.java)
/**
* Get paginated form-submission resources (hydrated with relationships)
*
* @return PaginatedList of FormSubmission
*/
suspend fun all(organisationId: String, formId: String): PaginatedList<FormSubmission> {
return fetchPaginatedJsonApiResources(
"/v3/orgs/$organisationId/data-capture/forms/$formId/submissions",
queryParameters = emptyMap<String, String>(),
FormSubmission::class.java,
User::class.java,
Form::class.java,
Organisation::class.java,
com.ctrlhub.core.datacapture.resource.FormSubmissionVersion::class.java
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.ctrlhub.core.datacapture.response

import com.ctrlhub.core.datacapture.resource.FormSubmissionVersion
import com.ctrlhub.core.projects.response.Organisation
import com.ctrlhub.core.iam.response.User
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import com.github.jasminb.jsonapi.StringIdHandler
import com.github.jasminb.jsonapi.annotations.Id
import com.github.jasminb.jsonapi.annotations.Meta
import com.github.jasminb.jsonapi.annotations.Relationship
import com.github.jasminb.jsonapi.annotations.Type
import java.time.LocalDateTime

@Type("form-submissions")
@JsonIgnoreProperties(ignoreUnknown = true)
class FormSubmission @JsonCreator constructor(
@Id(StringIdHandler::class) var id: String = "",

@Relationship("contributors")
var contributors: java.util.List<User>? = null,

@Relationship("creator")
var creator: User? = null,

@Relationship("form")
var form: Form? = null,

@Relationship("organisation")
var organisation: Organisation? = null,

@Relationship("versions")
var versions: java.util.List<FormSubmissionVersion>? = null,

@Meta
var meta: FormSubmissionMeta? = null
) {
constructor(): this(id = "")
}

@JsonIgnoreProperties(ignoreUnknown = true)
class FormSubmissionMeta @JsonCreator constructor(
@JsonProperty("created_at") var createdAt: LocalDateTime? = null,
@JsonProperty("modified_at") var modifiedAt: LocalDateTime? = null,
@JsonProperty("counts") var counts: FormSubmissionCounts? = null
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class FormSubmissionCounts(
@JsonProperty("versions") val versions: Int = 0,
@JsonProperty("contributors") val contributors: Int = 0
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.ctrlhub.core.datacapture

import com.ctrlhub.core.configureForTest
import com.ctrlhub.core.datacapture.resource.FormSubmissionVersion
import com.ctrlhub.core.api.response.PaginatedList
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import io.ktor.http.*
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

class FormSubmissionVersionsRouterTest {

@Test
fun `can create form submission versions`() {
val jsonFilePath = Paths.get("src/test/resources/datacapture/form-submission-version-response.json")
val jsonContent = Files.readString(jsonFilePath)

val mockEngine = MockEngine { _ ->
respond(
content = jsonContent,
status = HttpStatusCode.Created,
headers = headersOf(HttpHeaders.ContentType, "application/vnd.api+json")
)
}

val formSubmissionVersionsRouter = FormSubmissionVersionsRouter(httpClient = HttpClient(mockEngine).configureForTest())

runBlocking {
val result = formSubmissionVersionsRouter.create(
organisationId = "org-123",
formId = "form-456",
schemaId = "schema-789",
payload = mapOf("Test" to "value")
)

assertIs<FormSubmissionVersion>(result)
assertNotNull(result.id)
}
}

@Test
fun `can get all form submission versions and hydrate`() {
val jsonFilePath = Paths.get("src/test/resources/datacapture/all-form-submission-versions-response.json")
val jsonContent = Files.readString(jsonFilePath)

val mockEngine = MockEngine { _ ->
respond(
content = jsonContent,
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "application/vnd.api+json")
)
}

val formSubmissionVersionsRouter = FormSubmissionVersionsRouter(httpClient = HttpClient(mockEngine).configureForTest())

runBlocking {
val result = formSubmissionVersionsRouter.all(
organisationId = "org-123",
formId = "form-456",
submissionId = "d3c2b1a0-9f8e-7d6c-5b4a-3e2f1d0c9b8a"
)

// verify the paginated wrapper
assertNotNull(result)
assertTrue(result.data.isNotEmpty())

// verify hydration of the first item
val first = result.data.first()
assertIs<FormSubmissionVersion>(first)
assertNotNull(first.id)
}
}

@Test
fun `can get one form submission version and hydrate`() {
val jsonFilePath = Paths.get("src/test/resources/datacapture/one-form-submission-version-response.json")
val jsonContent = Files.readString(jsonFilePath)

val mockEngine = MockEngine { _ ->
respond(
content = jsonContent,
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "application/vnd.api+json")
)
}

val formSubmissionVersionsRouter = FormSubmissionVersionsRouter(httpClient = HttpClient(mockEngine).configureForTest())

runBlocking {
val result = formSubmissionVersionsRouter.one(
organisationId = "org-123",
formId = "form-456",
submissionId = "d4c3b2a1-0f9e-8d7c-6b5a-4e3f2d1c0b9a",
versionId = "4a8b7c6d-2e3f-4a1b-9c2d-0e1f2a3b4c5d"
)

assertIs<FormSubmissionVersion>(result)
assertEquals("4a8b7c6d-2e3f-4a1b-9c2d-0e1f2a3b4c5d", result.id)
// check payload exists and contains expected keys
assertNotNull(result.payload)
assertTrue(result.payload!!.containsKey("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"))
assertTrue(result.payload!!.containsKey("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.ctrlhub.core.datacapture

import com.ctrlhub.core.configureForTest
import com.ctrlhub.core.datacapture.resource.FormSubmissionVersion
import com.ctrlhub.core.datacapture.response.FormSubmission
import com.ctrlhub.core.api.response.PaginatedList
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import io.ktor.http.*
Expand All @@ -16,30 +17,29 @@ import kotlin.test.assertIs
class FormSubmissionsRouterTest {

@Test
fun `can create form submission`() {
val jsonFilePath = Paths.get("src/test/resources/datacapture/form-submission-response.json")
fun `can retrieve and hydrate submissions`() {
val jsonFilePath = Paths.get("src/test/resources/datacapture/all-form-submissions-response.json")
val jsonContent = Files.readString(jsonFilePath)

val mockEngine = MockEngine { request ->
respond(
content = jsonContent,
status = HttpStatusCode.Created,
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "application/vnd.api+json")
)
}

val formSubmissionsRouter = FormSubmissionsRouter(httpClient = HttpClient(mockEngine).configureForTest())

runBlocking {
val result = formSubmissionsRouter.create(
organisationId = "org-123",
formId = "form-456",
schemaId = "schema-789",
payload = mapOf("Test" to "value")
)
val response = formSubmissionsRouter.all(organisationId = "org-123", formId = "form-456")

assertIs<FormSubmissionVersion>(result)
assertNotNull(result.id)
assertIs<PaginatedList<FormSubmission>>(response)
assertEquals(4, response.data.size)
assertNotNull(response.data[0].id)
// verify pagination counts parsed from meta
assertEquals(4, response.pagination.counts.resources)
assertEquals(1, response.pagination.counts.pages)
}
}
}
Loading
Loading