diff --git a/src/main/kotlin/fr/dcproject/component/vote/routes/PutVoteOnComment.kt b/src/main/kotlin/fr/dcproject/component/vote/routes/PutVoteOnComment.kt index 8884047..cf65882 100644 --- a/src/main/kotlin/fr/dcproject/component/vote/routes/PutVoteOnComment.kt +++ b/src/main/kotlin/fr/dcproject/component/vote/routes/PutVoteOnComment.kt @@ -1,15 +1,21 @@ package fr.dcproject.component.vote.routes +import fr.dcproject.application.http.badRequestIfNotValid import fr.dcproject.common.security.assert import fr.dcproject.common.utils.receiveOrBadRequest import fr.dcproject.component.auth.citizen import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.mustBeAuth +import fr.dcproject.component.comment.generic.database.CommentRef import fr.dcproject.component.comment.generic.database.CommentRepository import fr.dcproject.component.vote.VoteAccessControl import fr.dcproject.component.vote.database.VoteCommentRepository import fr.dcproject.component.vote.database.VoteForUpdate +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.features.NotFoundException import io.ktor.http.HttpStatusCode import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.Location @@ -21,18 +27,29 @@ import java.util.UUID @KtorExperimentalLocationsAPI object PutVoteOnComment { @Location("/comments/{comment}/vote") - class CommentVoteRequest(val comment: UUID) { - data class Content(var note: Int) + class CommentVoteRequest(comment: UUID) { + val comment = CommentRef(comment) + data class Input(var note: Int) { + fun validate() = Validation { + Input::note { + minimum(-1) + maximum(1) + } + }.validate(this) + } } fun Route.putVoteOnComment(voteCommentRepo: VoteCommentRepository, commentRepo: CommentRepository, ac: VoteAccessControl) { put { mustBeAuth() - val comment = commentRepo.findById(it.comment)!! - val content = call.receiveOrBadRequest() + + val comment = commentRepo.findById(it.comment.id) ?: throw NotFoundException("Comment ${it.comment.id} not found") + val input = call.receiveOrBadRequest() + .apply { validate().badRequestIfNotValid() } + val vote = VoteForUpdate( target = comment, - note = content.note, + note = input.note, createdBy = this.citizen ) ac.assert { canCreate(vote, citizenOrNull) } diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index 2c3293d..76b8846 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -1252,6 +1252,12 @@ paths: application/json: schema: $ref: '#/components/schemas/VoteAggregation' + 400: + description: BadReqest + content: + application/json: + schema: + $ref: '#/components/schemas/400' 401: $ref: '#/components/responses/401' /citizens/{citizen}/votes/articles: diff --git a/src/test/kotlin/integration/Vote routes.kt b/src/test/kotlin/integration/Vote routes.kt index ef65a0b..efd54bc 100644 --- a/src/test/kotlin/integration/Vote routes.kt +++ b/src/test/kotlin/integration/Vote routes.kt @@ -181,4 +181,39 @@ class `Vote routes` : BaseTest() { } } } + + @TestFactory + @Tag("BadRequest") + fun `I cannot vote comment with wrong request`(): List { + withIntegrationApplication { + `Given I have citizen`("Antoine", "Lavoisier") + `Given I have article`(id = "835c5101-ca39-4038-a4e6-da6ee62ca6d5") + `Given I have comment on article`( + createdBy = Name("Antoine", "Lavoisier"), + article = "835c5101-ca39-4038-a4e6-da6ee62ca6d5", + id = "e793eccc-456b-4450-a292-46d592229b74", + ) + } + + return listOf(-10, -2, +2, +10).map { note -> + DynamicTest.dynamicTest("""I can vote comment with note "$note"""") { + withIntegrationApplication { + `When I send a PUT request`("/comments/e793eccc-456b-4450-a292-46d592229b74/vote", ALL - REQUEST_BODY) { + `authenticated as`("Antoine", "Lavoisier") + `with body`( + """ + { + "note": $note + } + """ + ) + } `Then the response should be` BadRequest and { + `And the response should not be null`() + `And the response should contain`("$.invalidParams[0].name", ".note") + `And the response should contain`("$.invalidParams[0].reason", if (note > 0) "must be at most '1'" else "must be at least '-1'") + } + } + } + } + } }