From 3f392eece67baf1ddc77c5b1a770127a45bbb275 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Thu, 15 Apr 2021 23:45:47 +0200 Subject: [PATCH] Add validation on route EditWorkgroup --- .../fr/dcproject/common/validation/Url.kt | 15 +++++++ .../workgroup/routes/EditWorkgroup.kt | 23 +++++++++- src/main/resources/openapi.yaml | 6 +++ .../kotlin/integration/Workgroup routes.kt | 44 +++++++++++++++++-- 4 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/fr/dcproject/common/validation/Url.kt diff --git a/src/main/kotlin/fr/dcproject/common/validation/Url.kt b/src/main/kotlin/fr/dcproject/common/validation/Url.kt new file mode 100644 index 0000000..e7e2cc6 --- /dev/null +++ b/src/main/kotlin/fr/dcproject/common/validation/Url.kt @@ -0,0 +1,15 @@ +package fr.dcproject.common.validation + +import io.konform.validation.ValidationBuilder +import java.net.MalformedURLException +import java.net.URL + +fun ValidationBuilder.isUrl() = + addConstraint("is not url") { + try { + val url = URL(it) + true + } catch (e: MalformedURLException) { + false + } + } diff --git a/src/main/kotlin/fr/dcproject/component/workgroup/routes/EditWorkgroup.kt b/src/main/kotlin/fr/dcproject/component/workgroup/routes/EditWorkgroup.kt index 4d96298..b116b7d 100644 --- a/src/main/kotlin/fr/dcproject/component/workgroup/routes/EditWorkgroup.kt +++ b/src/main/kotlin/fr/dcproject/component/workgroup/routes/EditWorkgroup.kt @@ -1,13 +1,18 @@ package fr.dcproject.component.workgroup.routes +import fr.dcproject.application.http.badRequestIfNotValid import fr.dcproject.common.security.assert import fr.dcproject.common.utils.receiveOrBadRequest +import fr.dcproject.common.validation.isUrl import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.mustBeAuth import fr.dcproject.component.workgroup.WorkgroupAccessControl import fr.dcproject.component.workgroup.database.WorkgroupForUpdate import fr.dcproject.component.workgroup.database.WorkgroupRepository import fr.dcproject.component.workgroup.routes.EditWorkgroup.PutWorkgroupRequest.Input +import io.konform.validation.Validation +import io.konform.validation.jsonschema.maxLength +import io.konform.validation.jsonschema.minLength import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -27,7 +32,22 @@ object EditWorkgroup { val description: String?, val logo: String?, val anonymous: Boolean? - ) + ) { + fun validate() = Validation { + Input::name ifPresent { + minLength(5) + maxLength(80) + } + Input::description ifPresent { + minLength(50) + maxLength(6000) + } + Input::logo ifPresent { + isUrl() + maxLength(2048) + } + }.validate(this) + } } fun Route.editWorkgroup(repo: WorkgroupRepository, ac: WorkgroupAccessControl) { @@ -35,6 +55,7 @@ object EditWorkgroup { mustBeAuth() repo.findById(it.workgroupId)?.let { old -> call.receiveOrBadRequest().run { + validate().badRequestIfNotValid() WorkgroupForUpdate( id = old.id, name = name ?: old.name, diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index 352de91..de03709 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -1451,6 +1451,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Workgroup' + 400: + description: BadReqest + content: + application/json: + schema: + $ref: '#/components/schemas/400' delete: summary: Delete one workgroup security: diff --git a/src/test/kotlin/integration/Workgroup routes.kt b/src/test/kotlin/integration/Workgroup routes.kt index febebf2..c6182c4 100644 --- a/src/test/kotlin/integration/Workgroup routes.kt +++ b/src/test/kotlin/integration/Workgroup routes.kt @@ -1,6 +1,7 @@ package integration import fr.dcproject.component.citizen.database.CitizenI.Name +import integration.steps.`when`.Validate.REQUEST_BODY import integration.steps.`when`.Validate.REQUEST_PARAM import integration.steps.`when`.`When I send a DELETE request` import integration.steps.`when`.`When I send a GET request` @@ -112,14 +113,15 @@ class `Workgroup routes` : BaseTest() { """ { "name":"La ratatouille", - "description":"Une petite souris" + "description":"Une petite souris avec un chapeau et qui aime la cuisine", + "logo": "http://sdf@exemple.com/sdfsd?sdf=sss" } """ ) } `Then the response should be` OK and { `And the response should contain`("$.id", "aa875a24-0050-4252-9130-d37391714e26") `And the response should contain`("$.name", "La ratatouille") - `And the response should contain`("$.description", "Une petite souris") + `And the response should contain`("$.description", "Une petite souris avec un chapeau et qui aime la cuisine") `And have property`("$.members") `And the response should contain list`("$.members", 3) @@ -132,7 +134,43 @@ class `Workgroup routes` : BaseTest() { } `Then the response should be` OK and { `And the response should contain`("$.id", "aa875a24-0050-4252-9130-d37391714e26") `And the response should contain`("$.name", "La ratatouille") - `And the response should contain`("$.description", "Une petite souris") + `And the response should contain`("$.description", "Une petite souris avec un chapeau et qui aime la cuisine") + } + } + } + + @Test + @Tag("BadRequest") + fun `I cannot edit a workgroup with bad request`() { + withIntegrationApplication { + `Given I have citizen`("John", "Wheeler") + `Given I have citizen`("Heinrich", "Hertz", id = "94f92424-c257-4582-907c-98564a8c4ac9") + `Given I have citizen`("William", "Thomson", id = "87909ba3-2069-431c-9924-219fd8411cf2") + `Given I have workgroup`("aa875a24-0050-4252-9130-d37391714e26", createdBy = Name("John", "Wheeler")) { + `With members`( + Name("Heinrich", "Hertz"), + Name("William", "Thomson"), + ) + } + `When I send a PUT request`("/workgroups/aa875a24-0050-4252-9130-d37391714e26", -REQUEST_BODY) { + `authenticated as`("John", "Wheeler") + `with body`( + """ + { + "name":"sm", + "description":"small2", + "logo": "ws://sdfs.sdok" + } + """ + ) + } `Then the response should be` BadRequest and { + `And the response should not be null`() + `And the response should contain`("$.invalidParams[0].name", ".name") + `And the response should contain`("$.invalidParams[0].reason", "must have at least 5 characters") + `And the response should contain`("$.invalidParams[1].name", ".description") + `And the response should contain`("$.invalidParams[1].reason", "must have at least 50 characters") + `And the response should contain`("$.invalidParams[2].name", ".logo") + `And the response should contain`("$.invalidParams[2].reason", "is not url") } } }