From 496cf50d88fc4a63bbc08153cecc188aef3291c1 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Thu, 15 Apr 2021 01:27:48 +0200 Subject: [PATCH] Add validation on route GetCitizenVotesOnArticle --- build.gradle.kts | 6 +++++ .../vote/routes/GetCitizenVotesOnArticle.kt | 15 ++++++++++++ src/main/resources/openapi.yaml | 9 +++++++ src/test/kotlin/integration/Vote routes.kt | 24 ++++++++++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 283e4c8..3aff791 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -362,6 +362,12 @@ tasks.register("testOpinions", Test::class) { includeTags("opinion") } } +tasks.register("testVotes", Test::class) { + group = "tests" + useJUnitPlatform { + includeTags("vote") + } +} dependencyCheck { formats = listOf(ReportGenerator.Format.HTML, ReportGenerator.Format.XML) diff --git a/src/main/kotlin/fr/dcproject/component/vote/routes/GetCitizenVotesOnArticle.kt b/src/main/kotlin/fr/dcproject/component/vote/routes/GetCitizenVotesOnArticle.kt index d8b5654..102300b 100644 --- a/src/main/kotlin/fr/dcproject/component/vote/routes/GetCitizenVotesOnArticle.kt +++ b/src/main/kotlin/fr/dcproject/component/vote/routes/GetCitizenVotesOnArticle.kt @@ -1,5 +1,6 @@ package fr.dcproject.component.vote.routes +import fr.dcproject.application.http.badRequestIfNotValid import fr.dcproject.common.response.toOutput import fr.dcproject.common.security.assert import fr.dcproject.component.auth.citizenOrNull @@ -9,6 +10,9 @@ import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.database.VoteArticleRepository import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequestI +import io.konform.validation.Validation +import io.konform.validation.jsonschema.maximum +import io.konform.validation.jsonschema.minimum import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI @@ -28,11 +32,22 @@ object GetCitizenVotesOnArticle { val search: String? = null ) : PaginatedRequestI by PaginatedRequest(page, limit) { val citizen = CitizenRef(citizen) + fun validate() = Validation { + CitizenVoteArticleRequest::page { + minimum(1) + } + CitizenVoteArticleRequest::limit { + minimum(1) + maximum(50) + } + }.validate(this) } fun Route.getCitizenVotesOnArticle(repo: VoteArticleRepository, ac: VoteAccessControl) { get { mustBeAuth() + it.validate().badRequestIfNotValid() + val votes = repo.findByCitizen(it.citizen, it.page, it.limit) ac.assert { canView(votes.result, citizenOrNull) } diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index e4a1fd1..76b7217 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -1265,6 +1265,9 @@ paths: - vote - article - citizen + parameters: + - $ref: '#/components/parameters/page' + - $ref: '#/components/parameters/limit' responses: 200: description: Votes @@ -1279,6 +1282,12 @@ paths: type: array items: $ref: '#/components/schemas/VoteResponse' + 400: + description: BadReqest + content: + application/json: + schema: + $ref: '#/components/schemas/400' 401: $ref: '#/components/responses/401' /articles/{article}/vote: diff --git a/src/test/kotlin/integration/Vote routes.kt b/src/test/kotlin/integration/Vote routes.kt index ec734b8..6d15ce2 100644 --- a/src/test/kotlin/integration/Vote routes.kt +++ b/src/test/kotlin/integration/Vote routes.kt @@ -1,6 +1,9 @@ package integration import fr.dcproject.component.citizen.database.CitizenI.Name +import integration.steps.`when`.Validate +import integration.steps.`when`.Validate.ALL +import integration.steps.`when`.Validate.REQUEST_PARAM import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a PUT request` import integration.steps.`when`.`with body` @@ -12,8 +15,10 @@ import integration.steps.given.`Given I have vote +1 on article` import integration.steps.given.`Given I have vote -1 on article` import integration.steps.given.`authenticated as` import integration.steps.then.`And the response should contain` +import integration.steps.then.`And the response should not be null` import integration.steps.then.`Then the response should be` import integration.steps.then.and +import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode.Companion.Created import io.ktor.http.HttpStatusCode.Companion.OK import org.junit.jupiter.api.Tag @@ -66,7 +71,7 @@ class `Vote routes` : BaseTest() { `Given I have citizen`("Carl", "Gauss", id = "c044823d-e778-4256-9016-b1334bf933d3") `Given I have article`("7c9286db-470d-448c-aab1-3f0b072213b1") `Given I have vote +1 on article`("7c9286db-470d-448c-aab1-3f0b072213b1", Name("Carl", "Gauss")) - `When I send a GET request`("/citizens/c044823d-e778-4256-9016-b1334bf933d3/votes/articles") { + `When I send a GET request`("/citizens/c044823d-e778-4256-9016-b1334bf933d3/votes/articles?page=1&limit=50") { `authenticated as`("Carl", "Gauss") } `Then the response should be` OK and { `And the response should contain`("$.currentPage", 1) @@ -77,6 +82,23 @@ class `Vote routes` : BaseTest() { } } + @Test + @Tag("BadRequest") + fun `I cannot get votes of current citizen with wrong request`() { + withIntegrationApplication { + `Given I have citizen`("Carl", "Gauss", id = "c044823d-e778-4256-9016-b1334bf933d3") + `Given I have article`("7c9286db-470d-448c-aab1-3f0b072213b1") + `Given I have vote +1 on article`("7c9286db-470d-448c-aab1-3f0b072213b1", Name("Carl", "Gauss")) + `When I send a GET request`("/citizens/c044823d-e778-4256-9016-b1334bf933d3/votes/articles?page=1&limit=60", ALL - REQUEST_PARAM) { + `authenticated as`("Carl", "Gauss") + } `Then the response should be` HttpStatusCode.BadRequest and { + `And the response should not be null`() + `And the response should contain`("$.invalidParams[0].name", ".limit") + `And the response should contain`("$.invalidParams[0].reason", "must be at most '50'") + } + } + } + @Test fun `I can get votes of current citizen by target ids`() { withIntegrationApplication {