Add validation on route UpsertArticle
This commit is contained in:
@@ -38,7 +38,6 @@ object FindArticles {
|
|||||||
fun validate() = Validation<ArticlesRequest> {
|
fun validate() = Validation<ArticlesRequest> {
|
||||||
ArticlesRequest::page {
|
ArticlesRequest::page {
|
||||||
minimum(1)
|
minimum(1)
|
||||||
maximum(100)
|
|
||||||
}
|
}
|
||||||
ArticlesRequest::limit {
|
ArticlesRequest::limit {
|
||||||
minimum(1)
|
minimum(1)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package fr.dcproject.component.article.routes
|
package fr.dcproject.component.article.routes
|
||||||
|
|
||||||
|
import fr.dcproject.application.http.badRequestIfNotValid
|
||||||
import fr.dcproject.common.security.assert
|
import fr.dcproject.common.security.assert
|
||||||
import fr.dcproject.common.utils.receiveOrBadRequest
|
import fr.dcproject.common.utils.receiveOrBadRequest
|
||||||
import fr.dcproject.component.article.ArticleAccessControl
|
import fr.dcproject.component.article.ArticleAccessControl
|
||||||
@@ -12,6 +13,11 @@ import fr.dcproject.component.auth.mustBeAuth
|
|||||||
import fr.dcproject.component.notification.ArticleUpdateNotification
|
import fr.dcproject.component.notification.ArticleUpdateNotification
|
||||||
import fr.dcproject.component.notification.Publisher
|
import fr.dcproject.component.notification.Publisher
|
||||||
import fr.dcproject.component.workgroup.database.WorkgroupRef
|
import fr.dcproject.component.workgroup.database.WorkgroupRef
|
||||||
|
import io.konform.validation.Validation
|
||||||
|
import io.konform.validation.jsonschema.maxItems
|
||||||
|
import io.konform.validation.jsonschema.maxLength
|
||||||
|
import io.konform.validation.jsonschema.minItems
|
||||||
|
import io.konform.validation.jsonschema.minLength
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
@@ -35,11 +41,31 @@ object UpsertArticle {
|
|||||||
val draft: Boolean = false,
|
val draft: Boolean = false,
|
||||||
val versionId: UUID,
|
val versionId: UUID,
|
||||||
val workgroup: WorkgroupRef? = null,
|
val workgroup: WorkgroupRef? = null,
|
||||||
)
|
) {
|
||||||
|
fun validate() = Validation<Input> {
|
||||||
|
Input::title {
|
||||||
|
minLength(5)
|
||||||
|
maxLength(80)
|
||||||
|
}
|
||||||
|
Input::content {
|
||||||
|
minLength(50)
|
||||||
|
maxLength(6000)
|
||||||
|
}
|
||||||
|
Input::description {
|
||||||
|
minLength(50)
|
||||||
|
maxLength(6000)
|
||||||
|
}
|
||||||
|
Input::tags {
|
||||||
|
minItems(0)
|
||||||
|
maxItems(15)
|
||||||
|
}
|
||||||
|
}.validate(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Route.upsertArticle(repo: ArticleRepository, publisher: Publisher, ac: ArticleAccessControl) {
|
fun Route.upsertArticle(repo: ArticleRepository, publisher: Publisher, ac: ArticleAccessControl) {
|
||||||
suspend fun ApplicationCall.convertRequestToEntity(): ArticleForUpdate = receiveOrBadRequest<Input>().run {
|
suspend fun ApplicationCall.convertRequestToEntity(): ArticleForUpdate = receiveOrBadRequest<Input>().run {
|
||||||
|
validate().badRequestIfNotValid()
|
||||||
ArticleForUpdate(
|
ArticleForUpdate(
|
||||||
id = id ?: UUID.randomUUID(),
|
id = id ?: UUID.randomUUID(),
|
||||||
title = title,
|
title = title,
|
||||||
|
|||||||
@@ -71,16 +71,21 @@ paths:
|
|||||||
Limit power of press
|
Limit power of press
|
||||||
content:
|
content:
|
||||||
type: string
|
type: string
|
||||||
|
minLength: 50
|
||||||
|
maxLength: 6000
|
||||||
example:
|
example:
|
||||||
Lorem upsum...
|
Lorem upsum...
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
|
minLength: 50
|
||||||
|
maxLength: 6000
|
||||||
example:
|
example:
|
||||||
I think is the bether choice
|
I think is the bether choice
|
||||||
tags:
|
tags:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
maxItems: 15
|
||||||
default: [ ]
|
default: [ ]
|
||||||
example: [ power, press ]
|
example: [ power, press ]
|
||||||
anonymous:
|
anonymous:
|
||||||
@@ -112,6 +117,12 @@ paths:
|
|||||||
format: uuid
|
format: uuid
|
||||||
versionNumber:
|
versionNumber:
|
||||||
type: integer
|
type: integer
|
||||||
|
400:
|
||||||
|
description: BadReqest
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/400'
|
||||||
401:
|
401:
|
||||||
$ref: '#/components/responses/401'
|
$ref: '#/components/responses/401'
|
||||||
403:
|
403:
|
||||||
|
|||||||
@@ -145,8 +145,8 @@ class `Article routes` : BaseTest() {
|
|||||||
"versionId": "09c418b6-63ba-448b-b38b-502b41cd500e",
|
"versionId": "09c418b6-63ba-448b-b38b-502b41cd500e",
|
||||||
"title": "title2",
|
"title": "title2",
|
||||||
"anonymous": false,
|
"anonymous": false,
|
||||||
"content": "content2",
|
"content": "Sed malesuada ante et sem congue, scelerisque feugiat lorem viverra.",
|
||||||
"description": "description2",
|
"description": "Sed vulputate, ligula id porta posuere, sapien lorem mattis arcu, sit amet luctus erat orci sed tellus.",
|
||||||
"tags": [
|
"tags": [
|
||||||
"green"
|
"green"
|
||||||
]
|
]
|
||||||
@@ -161,6 +161,7 @@ class `Article routes` : BaseTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Tag("Forbidden")
|
||||||
fun `I cannot create an article if I'm not connected`() {
|
fun `I cannot create an article if I'm not connected`() {
|
||||||
withIntegrationApplication {
|
withIntegrationApplication {
|
||||||
`When I send a POST request`("/articles") {
|
`When I send a POST request`("/articles") {
|
||||||
@@ -170,8 +171,8 @@ class `Article routes` : BaseTest() {
|
|||||||
"versionId": "e3c7ce42-241c-4caf-9a59-aba4e466440e",
|
"versionId": "e3c7ce42-241c-4caf-9a59-aba4e466440e",
|
||||||
"title": "title2",
|
"title": "title2",
|
||||||
"anonymous": false,
|
"anonymous": false,
|
||||||
"content": "content2",
|
"content": "Sed malesuada ante et sem congue, scelerisque feugiat lorem viverra.",
|
||||||
"description": "description2",
|
"description": "Sed vulputate, ligula id porta posuere, sapien lorem mattis arcu, sit amet luctus erat orci sed tellus.",
|
||||||
"tags": [
|
"tags": [
|
||||||
"green"
|
"green"
|
||||||
]
|
]
|
||||||
@@ -185,4 +186,35 @@ class `Article routes` : BaseTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Tag("BadRequest")
|
||||||
|
fun `I cannot create an article with wrong request`() {
|
||||||
|
withIntegrationApplication {
|
||||||
|
`Given I have citizen`("John", "Doe")
|
||||||
|
`When I send a POST request`("/articles", Validate.NONE) {
|
||||||
|
`authenticated as`("John", "Doe")
|
||||||
|
`with body`(
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"versionId": "09c418b6-63ba-448b-b38b-502b41cd500e",
|
||||||
|
"title": "title2",
|
||||||
|
"anonymous": false,
|
||||||
|
"content": "content2",
|
||||||
|
"description": "description2",
|
||||||
|
"tags": [
|
||||||
|
"green"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
} `Then the response should be` BadRequest and {
|
||||||
|
`And the response should not be null`()
|
||||||
|
`And the response should contain`("$.invalidParams[0].name", ".content")
|
||||||
|
`And the response should contain`("$.invalidParams[0].reason", "must have at least 50 characters")
|
||||||
|
`And the response should contain`("$.invalidParams[1].name", ".description")
|
||||||
|
`And the response should contain`("$.invalidParams[1].reason", "must have at least 50 characters")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import io.ktor.server.testing.TestApplicationRequest
|
|||||||
import io.ktor.server.testing.setBody
|
import io.ktor.server.testing.setBody
|
||||||
|
|
||||||
enum class Validate(override val bit: Long) : BitMaskI {
|
enum class Validate(override val bit: Long) : BitMaskI {
|
||||||
|
NONE(0),
|
||||||
REQUEST_BODY(1),
|
REQUEST_BODY(1),
|
||||||
REQUEST_PARAM(2),
|
REQUEST_PARAM(2),
|
||||||
REQUEST_HEADER(4),
|
REQUEST_HEADER(4),
|
||||||
|
|||||||
Reference in New Issue
Block a user