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
Expand Up @@ -3,14 +3,58 @@ 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.Form
import com.ctrlhub.core.iam.response.User
import com.ctrlhub.core.media.response.Image
import com.ctrlhub.core.router.Router
import io.ktor.client.HttpClient
import io.ktor.http.ContentType
import com.ctrlhub.core.api.response.PaginatedList
import com.ctrlhub.core.router.request.FilterOption
import com.ctrlhub.core.router.request.JsonApiIncludes
import com.ctrlhub.core.router.request.RequestParametersWithIncludes

@Suppress("unused")
enum class FormSubmissionVersionIncludes(val key: String) : JsonApiIncludes {
Author("author"),
Form("form"),
Organisation("organisation"),
Schema("schema"),
Submission("submission"),
PayloadImages("payload_images"),
PayloadOperations("payload_operations"),
PayloadProperties("payload_properties"),
PayloadUsers("payload_users"),
PayloadWorkOrders("payload_work_orders"),
PayloadSchemes("payload_schemes");

override fun value(): String = key
}

class FormSubmissionVersionRequestParameters(
offset: Int = 0,
limit: Int = 100,
filterOptions: List<FilterOption> = emptyList(),
includes: List<FormSubmissionVersionIncludes> = emptyList()
) : RequestParametersWithIncludes<FormSubmissionVersionIncludes>(
offset = offset,
limit = limit,
filterOptions = filterOptions,
includes = includes,
)

class FormSubmissionVersionsRouter(httpClient: HttpClient) : Router(httpClient) {
/**
* Create a new form submission version
* Create a new form submission version.
*
* Sends a POST request to create a submission (and implicitly its version) for the given form.
*
* @param organisationId the organisation UUID the form belongs to
* @param formId the form UUID to create a submission for
* @param schemaId the schema UUID to associate with the created version
* @param payload arbitrary map representing the submission payload (field id -> value)
* @return the created and hydrated FormSubmissionVersion instance
* @throws Exception on network or parsing errors
*/
suspend fun create(organisationId: String, formId: String, schemaId: String, payload: Map<String, Any>): FormSubmissionVersion {
return postJsonApiResource(
Expand All @@ -31,26 +75,136 @@ class FormSubmissionVersionsRouter(httpClient: HttpClient) : Router(httpClient)
}

/**
* Get all submission versions for a given form (paginated)
* Get all submission versions for a given form (paginated).
*
* Returns a paginated list of FormSubmissionVersion resources. Supports JSON:API include options
* to hydrate related resources (author, form, schema, images, etc.) via the requestParameters.
*
* @param organisationId the organisation UUID
* @param formId the form UUID
* @param submissionId the submission UUID to list versions for
* @param requestParameters optional paging, filter and include parameters
* @return PaginatedList containing FormSubmissionVersion items and pagination meta
*/
suspend fun all(organisationId: String, formId: String, submissionId: String): PaginatedList<FormSubmissionVersion> {
suspend fun all(
organisationId: String,
formId: String,
submissionId: String,
requestParameters: FormSubmissionVersionRequestParameters = FormSubmissionVersionRequestParameters()
): PaginatedList<FormSubmissionVersion> {
return fetchPaginatedJsonApiResources(
"/v3/orgs/$organisationId/data-capture/forms/$formId/submissions/$submissionId/versions",
queryParameters = emptyMap(),
FormSubmissionVersion::class.java,
FormSchema::class.java
requestParameters.toMap(),
User::class.java,
Form::class.java,
FormSchema::class.java,
Image::class.java
)
}

/**
* Get all submission versions for a specific submission (paginated).
*
* Overload that lists versions by submission id without a form id in the path.
*
* @param organisationId the organisation UUID
* @param submissionId the submission UUID to list versions for
* @param requestParameters optional paging, filter and include parameters
* @return PaginatedList containing FormSubmissionVersion items and pagination meta
*/
suspend fun all(
organisationId: String,
submissionId: String,
requestParameters: FormSubmissionVersionRequestParameters = FormSubmissionVersionRequestParameters()
): PaginatedList<FormSubmissionVersion> {
return fetchPaginatedJsonApiResources(
"/v3/orgs/$organisationId/data-capture/submissions/$submissionId/versions",
requestParameters.toMap(),
User::class.java,
Form::class.java,
FormSchema::class.java,
Image::class.java
)
}

/**
* Get all form submission versions across an organisation (paginated).
*
* Useful for admin-style listing of all submission versions. Supports includes via requestParameters.
*
* @param organisationId the organisation UUID
* @param requestParameters optional paging, filter and include parameters
* @return PaginatedList containing FormSubmissionVersion items and pagination meta
*/
suspend fun all(
organisationId: String,
requestParameters: FormSubmissionVersionRequestParameters = FormSubmissionVersionRequestParameters()
): PaginatedList<FormSubmissionVersion> {
return fetchPaginatedJsonApiResources(
"/v3/orgs/$organisationId/data-capture/form-submission-versions",
requestParameters.toMap(),
User::class.java,
Form::class.java,
FormSchema::class.java,
Image::class.java
)
}

/**
* Get a single submission version
* Get a single submission version.
*
* Fetches and hydrates a single FormSubmissionVersion resource by id. Supports JSON:API include
* parameters via requestParameters to hydrate related resources.
*
* @param organisationId the organisation UUID
* @param formId the form UUID the submission belongs to
* @param submissionId the submission UUID
* @param versionId the version UUID to fetch
* @param requestParameters optional paging, filter and include parameters
* @return the hydrated FormSubmissionVersion
*/
suspend fun one(organisationId: String, formId: String, submissionId: String, versionId: String): FormSubmissionVersion {
suspend fun one(
organisationId: String,
formId: String,
submissionId: String,
versionId: String,
requestParameters: FormSubmissionVersionRequestParameters = FormSubmissionVersionRequestParameters()
): FormSubmissionVersion {
return fetchJsonApiResource(
"/v3/orgs/$organisationId/data-capture/forms/$formId/submissions/$submissionId/versions/$versionId",
queryParameters = emptyMap(),
FormSubmissionVersion::class.java,
FormSchema::class.java
requestParameters.toMap(),
User::class.java,
Form::class.java,
FormSchema::class.java,
Image::class.java
)
}

/**
* Get a single submission version by submission id (no form in path).
*
* Fetches and hydrates a single FormSubmissionVersion resource by id using the endpoint that does
* not include the form id in the path.
*
* @param organisationId the organisation UUID
* @param submissionId the submission UUID
* @param versionId the version UUID to fetch
* @param requestParameters optional paging, filter and include parameters
* @return the hydrated FormSubmissionVersion
*/
suspend fun one(
organisationId: String,
submissionId: String,
versionId: String,
requestParameters: FormSubmissionVersionRequestParameters = FormSubmissionVersionRequestParameters()
): FormSubmissionVersion {
return fetchJsonApiResource(
"/v3/orgs/$organisationId/data-capture/submissions/$submissionId/versions/$versionId",
requestParameters.toMap(),
User::class.java,
Form::class.java,
FormSchema::class.java,
Image::class.java
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package com.ctrlhub.core.datacapture.resource

import com.ctrlhub.core.datacapture.response.FormSchema
import com.ctrlhub.core.datacapture.response.Form
import com.ctrlhub.core.geo.Property
import com.ctrlhub.core.iam.response.User
import com.ctrlhub.core.media.response.Image
import com.ctrlhub.core.projects.operations.response.Operation
import com.ctrlhub.core.projects.schemes.response.Scheme
import com.ctrlhub.core.projects.workorders.response.WorkOrder
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
Expand All @@ -11,7 +18,7 @@ import com.github.jasminb.jsonapi.annotations.Type

@JsonIgnoreProperties(ignoreUnknown = true)
@Type("form-submission-versions")
data class FormSubmissionVersion @JsonCreator constructor(
class FormSubmissionVersion @JsonCreator constructor(
@Id(StringIdHandler::class)
var id: String = "",

Expand All @@ -23,4 +30,31 @@ data class FormSubmissionVersion @JsonCreator constructor(

@Relationship("schema")
var schema: FormSchema? = null,

@JsonProperty("meta")
var meta: Map<String, Any>? = null,

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

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

@Relationship("payload_images")
var payloadImages: List<Image>? = null,

@Relationship("payload_operations")
var payloadOperations: List<Operation>? = null,

@Relationship("payload_properties")
var payloadProperties: List<Property>? = null,

@Relationship("payload_users")
var payloadUsers: List<User>? = null,

@Relationship("payload_work_orders")
var payloadWorkOrders: List<WorkOrder>? = null,

@Relationship("payload_schemes")
var payloadSchemes: List<Scheme>? = null,
)
6 changes: 6 additions & 0 deletions src/main/kotlin/com/ctrlhub/core/http/KtorClientFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.ctrlhub.core.Config
import io.ktor.client.HttpClient
import io.ktor.client.HttpClientConfig
import io.ktor.client.engine.okhttp.OkHttp
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.UserAgent
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.defaultRequest
Expand Down Expand Up @@ -41,6 +42,11 @@ object KtorClientFactory {
encodeDefaults = true
})
}
install(HttpTimeout) {
requestTimeoutMillis = 15_000
connectTimeoutMillis = 15_000
socketTimeoutMillis = 15_000
}
install(UserAgent) {
agent = Config.userAgent
}
Expand Down
57 changes: 44 additions & 13 deletions src/main/kotlin/com/ctrlhub/core/media/response/Image.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,51 @@ import com.fasterxml.jackson.annotation.JsonCreator
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.Type

@Type("images")
data class Image @JsonCreator constructor(
@Id(StringIdHandler::class) val id: String = "",
@JsonProperty("mime_type") val mimeType: String,
@JsonProperty("extension") val extension: String,
@JsonProperty("width") val width: Int,
@JsonProperty("height") val height: Int,
@JsonProperty("bytes") val bytes: Long,
@JsonProperty("dimensions") val dimensions: List<ImageDimensions> = emptyList()
)
class Image @JsonCreator constructor(
@Id(StringIdHandler::class) var id: String = "",
@JsonProperty("mime_type") var mimeType: String = "",
@JsonProperty("extension") var extension: String = "",
@JsonProperty("width") var width: Int = 0,
@JsonProperty("height") var height: Int = 0,
@JsonProperty("bytes") var bytes: Long = 0L,
@JsonProperty("dimensions") var dimensions: List<ImageDimensions> = emptyList(),

data class ImageDimensions(
val width: Int,
val height: Int,
)
@Meta var meta: ImageMeta? = null
) {
constructor(): this(
id = "",
mimeType = "",
extension = "",
width = 0,
height = 0,
bytes = 0L,
dimensions = emptyList(),
meta = null
)
}

class ImageDimensions(
var width: Int = 0,
var height: Int = 0,
) {
constructor(): this(width = 0, height = 0)
}

class ImageLink(
var url: String = "",
var width: Int? = null,
var height: Int? = null
) {
constructor(): this(url = "", width = null, height = null)
}

class ImageMeta(
var links: List<ImageLink> = emptyList(),
@JsonProperty("created_at") var createdAt: String? = null
) {
constructor(): this(links = emptyList(), createdAt = null)
}
Loading