Add validation on route GetArticleComments
This commit is contained in:
@@ -41,7 +41,7 @@ class CommentArticleRepository(requester: Requester) : CommentRepositoryAbs<Arti
|
||||
target: EntityI,
|
||||
page: Int,
|
||||
limit: Int,
|
||||
sort: Sort
|
||||
sort: String
|
||||
): Paginated<CommentForView<ArticleForView, CitizenCreatorI>> {
|
||||
return requester
|
||||
.getFunction("find_comments_by_target")
|
||||
@@ -49,18 +49,7 @@ class CommentArticleRepository(requester: Requester) : CommentRepositoryAbs<Arti
|
||||
page,
|
||||
limit,
|
||||
"target_id" to target.id,
|
||||
"sort" to sort.sql
|
||||
"sort" to sort
|
||||
) as Paginated<CommentForView<ArticleForView, CitizenCreatorI>>
|
||||
}
|
||||
|
||||
enum class Sort(val sql: String) {
|
||||
CREATED_AT("created_at"),
|
||||
VOTES("votes");
|
||||
|
||||
companion object {
|
||||
fun fromString(string: String): Sort? {
|
||||
return values().firstOrNull { it.sql == string }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.dcproject.component.comment.article.routes
|
||||
|
||||
import fr.dcproject.application.http.badRequestIfNotValid
|
||||
import fr.dcproject.common.response.toOutput
|
||||
import fr.dcproject.common.security.assert
|
||||
import fr.dcproject.component.article.database.ArticleRef
|
||||
@@ -9,6 +10,10 @@ import fr.dcproject.component.comment.generic.CommentAccessControl
|
||||
import fr.dcproject.component.comment.toOutput
|
||||
import fr.dcproject.routes.PaginatedRequest
|
||||
import fr.dcproject.routes.PaginatedRequestI
|
||||
import io.konform.validation.Validation
|
||||
import io.konform.validation.jsonschema.enum
|
||||
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
|
||||
@@ -26,14 +31,31 @@ object GetArticleComments {
|
||||
page: Int = 1,
|
||||
limit: Int = 50,
|
||||
val search: String? = null,
|
||||
sort: String = CommentArticleRepository.Sort.CREATED_AT.sql
|
||||
val sort: String = "createdAt"
|
||||
) : PaginatedRequestI by PaginatedRequest(page, limit) {
|
||||
val article = ArticleRef(article)
|
||||
val sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.fromString(sort) ?: CommentArticleRepository.Sort.CREATED_AT
|
||||
|
||||
fun validate() = Validation<ArticleCommentsRequest> {
|
||||
ArticleCommentsRequest::page {
|
||||
minimum(1)
|
||||
}
|
||||
ArticleCommentsRequest::limit {
|
||||
minimum(1)
|
||||
maximum(50)
|
||||
}
|
||||
ArticleCommentsRequest::sort ifPresent {
|
||||
enum(
|
||||
"votes",
|
||||
"createdAt",
|
||||
)
|
||||
}
|
||||
}.validate(this)
|
||||
}
|
||||
|
||||
fun Route.getArticleComments(repo: CommentArticleRepository, ac: CommentAccessControl) {
|
||||
get<ArticleCommentsRequest> {
|
||||
it.validate().badRequestIfNotValid()
|
||||
|
||||
val comments = repo.findByTarget(it.article, it.page, it.limit, it.sort)
|
||||
if (comments.result.isNotEmpty()) {
|
||||
ac.assert { canView(comments.result, citizenOrNull) }
|
||||
|
||||
@@ -5,7 +5,6 @@ import fr.dcproject.common.entity.TargetI
|
||||
import fr.dcproject.component.citizen.database.CitizenCreator
|
||||
import fr.dcproject.component.citizen.database.CitizenCreatorI
|
||||
import fr.dcproject.component.citizen.database.CitizenI
|
||||
import fr.dcproject.component.comment.article.database.CommentArticleRepository
|
||||
import fr.dcproject.component.comment.generic.database.CommentForView
|
||||
import fr.dcproject.component.comment.generic.database.CommentRepositoryAbs
|
||||
import fr.dcproject.component.constitution.database.ConstitutionRef
|
||||
@@ -41,7 +40,7 @@ class CommentConstitutionRepository(requester: Requester) : CommentRepositoryAbs
|
||||
target: EntityI,
|
||||
page: Int,
|
||||
limit: Int,
|
||||
sort: CommentArticleRepository.Sort
|
||||
sort: String
|
||||
): Paginated<CommentForView<ConstitutionRef, CitizenCreatorI>> {
|
||||
return requester.run {
|
||||
getFunction("find_comments_by_target")
|
||||
@@ -49,7 +48,7 @@ class CommentConstitutionRepository(requester: Requester) : CommentRepositoryAbs
|
||||
page,
|
||||
limit,
|
||||
"target_id" to target.id,
|
||||
"sort" to sort.sql
|
||||
"sort" to sort
|
||||
)
|
||||
as Paginated<CommentForView<ConstitutionRef, CitizenCreatorI>>
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import fr.dcproject.common.entity.TargetRef
|
||||
import fr.dcproject.component.citizen.database.CitizenCreator
|
||||
import fr.dcproject.component.citizen.database.CitizenCreatorI
|
||||
import fr.dcproject.component.citizen.database.CitizenI
|
||||
import fr.dcproject.component.comment.article.database.CommentArticleRepository
|
||||
import fr.postgresjson.connexion.Paginated
|
||||
import fr.postgresjson.connexion.Requester
|
||||
import fr.postgresjson.repository.RepositoryI
|
||||
@@ -49,7 +48,7 @@ abstract class CommentRepositoryAbs<T : TargetI>(override var requester: Request
|
||||
target: EntityI,
|
||||
page: Int = 1,
|
||||
limit: Int = 50,
|
||||
sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.CREATED_AT
|
||||
sort: String = "createdAt"
|
||||
): Paginated<CommentForView<T, CitizenCreatorI>> {
|
||||
return findByTarget(target.id, page, limit, sort)
|
||||
}
|
||||
@@ -58,7 +57,7 @@ abstract class CommentRepositoryAbs<T : TargetI>(override var requester: Request
|
||||
targetId: UUID,
|
||||
page: Int = 1,
|
||||
limit: Int = 50,
|
||||
sort: CommentArticleRepository.Sort = CommentArticleRepository.Sort.CREATED_AT
|
||||
sort: String = "createdAt"
|
||||
): Paginated<CommentForView<T, CitizenCreatorI>> {
|
||||
return requester.run {
|
||||
getFunction("find_comments_by_target")
|
||||
@@ -66,7 +65,7 @@ abstract class CommentRepositoryAbs<T : TargetI>(override var requester: Request
|
||||
page,
|
||||
limit,
|
||||
"target_id" to targetId,
|
||||
"sort" to sort.sql
|
||||
"sort" to sort
|
||||
)
|
||||
as Paginated<CommentForView<T, CitizenCreatorI>>
|
||||
}
|
||||
|
||||
@@ -544,6 +544,12 @@ paths:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/CommentResponse'
|
||||
400:
|
||||
description: BadReqest
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/400'
|
||||
post:
|
||||
security:
|
||||
- JWTAuth: [ ]
|
||||
|
||||
@@ -26,7 +26,7 @@ begin
|
||||
else null
|
||||
end desc,
|
||||
case sort
|
||||
when 'created_at' then com.created_at::text
|
||||
when 'createdAt' then com.created_at::text
|
||||
else null
|
||||
end desc,
|
||||
com.created_at desc
|
||||
|
||||
@@ -3,6 +3,7 @@ package integration
|
||||
import fr.dcproject.component.citizen.database.CitizenI.Name
|
||||
import integration.steps.`when`.Validate.ALL
|
||||
import integration.steps.`when`.Validate.REQUEST_BODY
|
||||
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 POST request`
|
||||
import integration.steps.`when`.`When I send a PUT request`
|
||||
@@ -78,7 +79,7 @@ class `Comment articles routes` : BaseTest() {
|
||||
`Given I have citizen`("Enrico", "Fermi")
|
||||
`Given I have article`(id = "6166c078-ca97-4366-b0aa-2a5cd558c78a")
|
||||
`Given I have comment on article`(article = "6166c078-ca97-4366-b0aa-2a5cd558c78a", createdBy = Name("Enrico", "Fermi"))
|
||||
`When I send a GET request`("/articles/6166c078-ca97-4366-b0aa-2a5cd558c78a/comments") {
|
||||
`When I send a GET request`("/articles/6166c078-ca97-4366-b0aa-2a5cd558c78a/comments?page=1&limit=40&sort=votes") {
|
||||
`authenticated as`("Enrico", "Fermi")
|
||||
} `Then the response should be` OK and {
|
||||
`And the response should not be null`()
|
||||
@@ -87,6 +88,23 @@ class `Comment articles routes` : BaseTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Tag("BadRequest")
|
||||
fun `I cannot get all comment on article with wrong parameters`() {
|
||||
withIntegrationApplication {
|
||||
`Given I have citizen`("Enrico", "Fermi")
|
||||
`Given I have article`(id = "6166c078-ca97-4366-b0aa-2a5cd558c78a")
|
||||
`Given I have comment on article`(article = "6166c078-ca97-4366-b0aa-2a5cd558c78a", createdBy = Name("Enrico", "Fermi"))
|
||||
`When I send a GET request`("/articles/6166c078-ca97-4366-b0aa-2a5cd558c78a/comments?page=1&limit=40&sort=wrong", ALL - REQUEST_PARAM) {
|
||||
`authenticated as`("Enrico", "Fermi")
|
||||
} `Then the response should be` BadRequest and {
|
||||
`And the response should not be null`()
|
||||
`And the response should contain`("$.invalidParams[*].name", ".sort")
|
||||
`And the response should contain`("$.invalidParams[*].reason", "must be one of: 'votes', 'createdAt'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO add votes */
|
||||
@Test
|
||||
fun `I can get all comment on article sorted by votes`() {
|
||||
|
||||
Reference in New Issue
Block a user