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'")
+ }
+ }
+ }
+ }
+ }
}