Add validation on route FindCitizens

This commit is contained in:
2021-04-08 22:25:43 +02:00
parent e473e62068
commit 13cdaaf01a
6 changed files with 65 additions and 7 deletions

View File

@@ -326,6 +326,12 @@ tasks.register("testArticles", Test::class) {
includeTags("article") includeTags("article")
} }
} }
tasks.register("testCitizens", Test::class) {
group = "tests"
useJUnitPlatform {
includeTags("citizen")
}
}
dependencyCheck { dependencyCheck {
formats = listOf(ReportGenerator.Format.HTML, ReportGenerator.Format.XML) formats = listOf(ReportGenerator.Format.HTML, ReportGenerator.Format.XML)

View File

@@ -1,5 +1,6 @@
package fr.dcproject.component.citizen.routes package fr.dcproject.component.citizen.routes
import fr.dcproject.application.http.badRequestIfNotValid
import fr.dcproject.common.response.toOutput import fr.dcproject.common.response.toOutput
import fr.dcproject.common.security.assert import fr.dcproject.common.security.assert
import fr.dcproject.component.auth.citizenOrNull import fr.dcproject.component.auth.citizenOrNull
@@ -10,6 +11,10 @@ import fr.dcproject.component.citizen.database.CitizenRepository
import fr.dcproject.routes.PaginatedRequest import fr.dcproject.routes.PaginatedRequest
import fr.dcproject.routes.PaginatedRequestI import fr.dcproject.routes.PaginatedRequestI
import fr.postgresjson.repository.RepositoryI import fr.postgresjson.repository.RepositoryI
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.application.call
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location import io.ktor.locations.Location
@@ -27,11 +32,28 @@ object FindCitizens {
val sort: String? = null, val sort: String? = null,
val direction: RepositoryI.Direction? = null, val direction: RepositoryI.Direction? = null,
val search: String? = null val search: String? = null
) : PaginatedRequestI by PaginatedRequest(page, limit) ) : PaginatedRequestI by PaginatedRequest(page, limit) {
fun validate() = Validation<CitizensRequest> {
CitizensRequest::page {
minimum(1)
}
CitizensRequest::limit {
minimum(1)
maximum(50)
}
CitizensRequest::sort ifPresent {
enum(
"title",
"createdAt",
)
}
}.validate(this)
}
fun Route.findCitizen(ac: CitizenAccessControl, repo: CitizenRepository) { fun Route.findCitizen(ac: CitizenAccessControl, repo: CitizenRepository) {
get<CitizensRequest> { get<CitizensRequest> {
mustBeAuth() mustBeAuth()
it.validate().badRequestIfNotValid()
val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search) val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
ac.assert { canView(citizens.result, citizenOrNull) } ac.assert { canView(citizens.result, citizenOrNull) }
call.respond( call.respond(

View File

@@ -395,7 +395,7 @@ paths:
parameters: parameters:
- $ref: '#/components/parameters/page' - $ref: '#/components/parameters/page'
- $ref: '#/components/parameters/limit' - $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/sort' - $ref: '#/components/parameters/citizenSort'
- $ref: '#/components/parameters/direction' - $ref: '#/components/parameters/direction'
- $ref: '#/components/parameters/search' - $ref: '#/components/parameters/search'
responses: responses:
@@ -412,6 +412,12 @@ paths:
type: array type: array
items: items:
$ref: '#/components/schemas/CitizenListResponse' $ref: '#/components/schemas/CitizenListResponse'
400:
description: BadReqest
content:
application/json:
schema:
$ref: '#/components/schemas/400'
401: 401:
$ref: '#/components/responses/401' $ref: '#/components/responses/401'
/citizens/current: /citizens/current:
@@ -1418,6 +1424,17 @@ components:
- createdAt - createdAt
- vote - vote
- popularity - popularity
citizenSort:
name: sort
in: query
description: The sort field name
example: createdAt
required: false
schema:
type: string
enum:
- title
- createdAt
workgroupSort: workgroupSort:
name: sort name: sort
in: query in: query

View File

@@ -45,7 +45,7 @@ begin
case direction when 'asc' then case direction when 'asc' then
case sort case sort
when 'title' then a.title when 'title' then a.title
when 'created_at' then a.created_at::text when 'createdAt' then a.created_at::text
when 'vote' then ca.score::text when 'vote' then ca.score::text
when 'popularity' then ca.total::text when 'popularity' then ca.total::text
else null else null
@@ -54,7 +54,7 @@ begin
case direction when 'desc' then case direction when 'desc' then
case sort case sort
when 'title' then a.title when 'title' then a.title
when 'created_at' then a.created_at::text when 'createdAt' then a.created_at::text
when 'vote' then ca.score::text when 'vote' then ca.score::text
when 'popularity' then ca.total::text when 'popularity' then ca.total::text
end end

View File

@@ -23,14 +23,14 @@ begin
case direction when 'asc' then case direction when 'asc' then
case sort case sort
when 'name' then (z.name->'first_name')::text when 'name' then (z.name->'first_name')::text
when 'created_at' then z.created_at::text when 'createdAt' then z.created_at::text
else null else null
end end
end, end,
case direction when 'desc' then case direction when 'desc' then
case sort case sort
when 'name' then (z.name->'first_name')::text when 'name' then (z.name->'first_name')::text
when 'created_at' then z.created_at::text when 'createdAt' then z.created_at::text
end end
end end
desc, desc,

View File

@@ -26,7 +26,7 @@ class `Citizen routes` : BaseTest() {
fun `I can get Citizens information`() { fun `I can get Citizens information`() {
withIntegrationApplication { withIntegrationApplication {
`Given I have citizen`("Jean", "Perrin", id = "5267a5c6-af42-4a02-aa2b-6b71d2e43973") `Given I have citizen`("Jean", "Perrin", id = "5267a5c6-af42-4a02-aa2b-6b71d2e43973")
`When I send a GET request`("/citizens") { `When I send a GET request`("/citizens?page=1&limit=5&sort=createdAt") {
`authenticated as`("Jean", "Perrin") `authenticated as`("Jean", "Perrin")
} `Then the response should be` OK and { } `Then the response should be` OK and {
`And the response should not be null`() `And the response should not be null`()
@@ -34,6 +34,19 @@ class `Citizen routes` : BaseTest() {
} }
} }
@Test
@Tag("BadRequest")
fun `I cannot get Citizens information with wrong request`() {
withIntegrationApplication {
`Given I have citizen`("Jean", "Perrin", id = "5267a5c6-af42-4a02-aa2b-6b71d2e43973")
`When I send a GET request`("/citizens?page=1&limit=5&sort=created_at", Validate.ALL - Validate.REQUEST_PARAM) {
`authenticated as`("Jean", "Perrin")
} `Then the response should be` BadRequest and {
`And the response should not be null`()
}
}
}
@Test @Test
fun `I can get specific Citizen information`() { fun `I can get specific Citizen information`() {
withIntegrationApplication { withIntegrationApplication {