Test openapi schema of /constitutions/*

This commit is contained in:
2021-03-20 01:14:39 +01:00
parent c1a3590b2b
commit 4c1ab796e4
5 changed files with 347 additions and 5 deletions

View File

@@ -20,6 +20,7 @@ import io.ktor.locations.Location
import io.ktor.locations.post import io.ktor.locations.post
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
@@ -110,6 +111,23 @@ object CreateConstitution {
val anonymous: Boolean = c.anonymous val anonymous: Boolean = c.anonymous
val draft: Boolean = c.draft val draft: Boolean = c.draft
val versionId: UUID = c.versionId val versionId: UUID = c.versionId
val createdAt: DateTime = c.createdAt
val createdBy: Any = c.createdBy.let { c ->
object {
val id: UUID = c.id
val name: Any = c.name.let { n ->
object {
val firstName: String = n.firstName
val lastName: String = n.lastName
}
}
val user: Any = c.user.let { u ->
object {
val username: String = u.username
}
}
}
}
} }
) )
} }

View File

@@ -1,5 +1,6 @@
package fr.dcproject.component.constitution.routes package fr.dcproject.component.constitution.routes
import fr.dcproject.common.dto.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
import fr.dcproject.component.constitution.ConstitutionAccessControl import fr.dcproject.component.constitution.ConstitutionAccessControl
@@ -8,11 +9,14 @@ 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.ktor.application.call import io.ktor.application.call
import io.ktor.http.HttpStatusCode
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location import io.ktor.locations.Location
import io.ktor.locations.get import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import org.joda.time.DateTime
import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
object FindConstitutions { object FindConstitutions {
@@ -29,7 +33,33 @@ object FindConstitutions {
get<FindConstitutionsRequest> { get<FindConstitutionsRequest> {
val constitutions = repo.find(it.page, it.limit, it.sort, it.direction, it.search) val constitutions = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
ac.assert { canView(constitutions.result, citizenOrNull) } ac.assert { canView(constitutions.result, citizenOrNull) }
call.respond(constitutions) call.respond(
HttpStatusCode.OK,
constitutions.toOutput { c ->
object {
val id: UUID = c.id
val title: String = c.title
val versionId: UUID = c.versionId
val createdAt: DateTime = c.createdAt
val createdBy: Any = c.createdBy.let { c ->
object {
val id: UUID = c.id
val name: Any = c.name.let { n ->
object {
val firstName: String = n.firstName
val lastName: String = n.lastName
}
}
val user: Any = c.user.let { u ->
object {
val username: String = u.username
}
}
}
}
}
}
)
} }
} }
} }

View File

@@ -7,11 +7,13 @@ import fr.dcproject.component.constitution.database.ConstitutionRef
import fr.dcproject.component.constitution.database.ConstitutionRepository import fr.dcproject.component.constitution.database.ConstitutionRepository
import io.ktor.application.call import io.ktor.application.call
import io.ktor.features.NotFoundException import io.ktor.features.NotFoundException
import io.ktor.http.HttpStatusCode
import io.ktor.locations.KtorExperimentalLocationsAPI import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location import io.ktor.locations.Location
import io.ktor.locations.get import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.routing.Route import io.ktor.routing.Route
import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
@@ -25,7 +27,68 @@ object GetConstitution {
get<GetConstitutionRequest> { get<GetConstitutionRequest> {
val constitution = constitutionRepo.findById(it.constitution.id) ?: throw NotFoundException("Unable to find constitution ${it.constitution.id}") val constitution = constitutionRepo.findById(it.constitution.id) ?: throw NotFoundException("Unable to find constitution ${it.constitution.id}")
ac.assert { canView(constitution, citizenOrNull) } ac.assert { canView(constitution, citizenOrNull) }
call.respond(constitution) call.respond(
HttpStatusCode.OK,
constitution.let { c ->
object {
val id: UUID = c.id
val title: String = c.title
val titles: List<Any> = c.titles.map { t ->
object {
val id: UUID = t.id
val name: String = t.name
val rank: Int = t.rank
val articles: List<Any> = t.articles.map { a ->
val id = a.id
val title = a.title
val createdBy = a.createdBy.let { cr ->
object {
val id: UUID = cr.id
val name: Any = cr.name.let { n ->
object {
val firstName: String = n.firstName
val lastName: String = n.lastName
}
}
val user: Any = cr.user.let { u ->
object {
val username: String = u.username
}
}
}
}
val workgroup: Any? = a.workgroup?.let { w ->
object {
val id = w.id
val name = w.name
}
}
}
}
}
val anonymous: Boolean = c.anonymous
val draft: Boolean = c.draft
val versionId: UUID = c.versionId
val createdAt: DateTime = c.createdAt
val createdBy: Any = c.createdBy.let { c ->
object {
val id: UUID = c.id
val name: Any = c.name.let { n ->
object {
val firstName: String = n.firstName
val lastName: String = n.lastName
}
}
val user: Any = c.user.let { u ->
object {
val username: String = u.username
}
}
}
}
}
}
)
} }
} }
} }

View File

@@ -662,6 +662,73 @@ paths:
401: 401:
$ref: '#/components/responses/401' $ref: '#/components/responses/401'
/constitutions:
get:
summary: Get all constitutions
tags:
- constitution
operationId: getConstitutions
parameters:
- $ref: '#/components/parameters/page'
- $ref: '#/components/parameters/limit'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/direction'
- $ref: '#/components/parameters/search'
responses:
200:
description: The Constitution objects
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
properties:
result:
type: array
items:
$ref: '#/components/schemas/ConstitutionListingResponse'
post:
security:
- JWTAuth: [ ]
summary: Create new Constitution
tags:
- constitution
operationId: insertConstitution
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ConstitutionRequest'
responses:
201:
description: Constitution created
content:
application/json:
schema:
$ref: '#/components/schemas/ConstitutionResponse'
401:
$ref: '#/components/responses/401'
400:
$ref: '#/components/responses/400'
/constitutions/{constitution}:
parameters:
- $ref: '#/components/parameters/constitution'
get:
summary: Get all constitutions
tags:
- constitution
operationId: getConstitutions
responses:
200:
description: The Constitution objects
content:
application/json:
schema:
$ref: '#/components/schemas/ConstitutionResponse'
components: components:
parameters: parameters:
page: page:
@@ -781,6 +848,12 @@ components:
application/json: application/json:
schema: schema:
description: noting description: noting
400:
description: BadReqest
content:
application/json:
schema:
description: noting
schemas: schemas:
UUID: UUID:
@@ -962,6 +1035,9 @@ components:
type: object type: object
nullable: true nullable: true
additionalProperties: false additionalProperties: false
required:
- id
- name
properties: properties:
id: id:
type: string type: string
@@ -1139,6 +1215,136 @@ components:
minimum: 0 minimum: 0
score: score:
type: number type: number
ConstitutionRequest:
additionalProperties: false
description: The versionId field must be defined for update contitution
type: object
required:
- title
properties:
id:
$ref: '#/components/schemas/UUID'
title:
type: string
example:
Constitution for the liberty
titles:
type: array
default: [ ]
items:
additionalProperties: false
type: object
required:
- name
properties:
id:
$ref: '#/components/schemas/UUID'
name:
type: string
example:
The liberties
articles:
type: array
items:
required:
- id
properties:
id:
$ref: '#/components/schemas/UUID'
anonymous:
type: boolean
default: true
draft:
type: boolean
default: false
versionId:
$ref: '#/components/schemas/UUID'
ConstitutionResponse:
additionalProperties: false
type: object
required:
- id
- title
- titles
- anonymous
- draft
- versionId
- createdBy
- createdAt
properties:
id:
$ref: '#/components/schemas/UUID'
title:
type: string
example:
Constitution for the liberty
titles:
type: array
default: [ ]
items:
additionalProperties: false
type: object
required:
- id
- name
- rank
- articles
properties:
id:
$ref: '#/components/schemas/UUID'
name:
type: string
example:
The liberties
rank:
type: integer
minimum: 0
example: 0
createdBy:
$ref: '#/components/schemas/CitizenCreator'
createdAt:
type: string
format: 'date-time'
articles:
type: array
items:
$ref: '#/components/schemas/ArticleListingResponse'
anonymous:
type: boolean
default: true
draft:
type: boolean
default: false
versionId:
$ref: '#/components/schemas/UUID'
createdBy:
$ref: '#/components/schemas/CitizenCreator'
createdAt:
type: string
format: 'date-time'
ConstitutionListingResponse:
additionalProperties: false
type: object
required:
- id
- title
- versionId
- createdAt
- createdBy
properties:
id:
$ref: '#/components/schemas/UUID'
title:
type: string
example:
Constitution for the liberty
versionId:
$ref: '#/components/schemas/UUID'
createdBy:
$ref: '#/components/schemas/CitizenCreator'
createdAt:
type: string
format: 'date-time'
securitySchemes: securitySchemes:
JWTAuth: JWTAuth:

View File

@@ -1,5 +1,6 @@
package integration package integration
import integration.steps.`when`.Validate
import integration.steps.then.`And have property` import integration.steps.then.`And have property`
import integration.steps.then.`And the response should not be null` import integration.steps.then.`And the response should not be null`
import integration.steps.then.`Then the response should be` import integration.steps.then.`Then the response should be`
@@ -12,6 +13,8 @@ import integration.steps.given.`Given I have citizen`
import integration.steps.given.`Given I have constitution` import integration.steps.given.`Given I have constitution`
import integration.steps.given.`Given I have constitutions` import integration.steps.given.`Given I have constitutions`
import integration.steps.given.`authenticated as` import integration.steps.given.`authenticated as`
import io.ktor.http.HttpStatusCode.Companion.BadRequest
import io.ktor.http.HttpStatusCode.Companion.Created
import io.ktor.http.HttpStatusCode.Companion.OK import io.ktor.http.HttpStatusCode.Companion.OK
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Tags import org.junit.jupiter.api.Tags
@@ -70,17 +73,39 @@ class `Constitution routes` : BaseTest() {
"anonymous":true, "anonymous":true,
"titles":[ "titles":[
{ {
"name":"plop", "name":"plop"
"rank":0
} }
] ]
} }
""") """)
} `Then the response should be` OK and { } `Then the response should be` Created and {
`And the response should not be null`() `And the response should not be null`()
`And have property`("$.versionId") `whish contains` "15814bb6-8d90-4c6a-a456-c3939a8ec75e" `And have property`("$.versionId") `whish contains` "15814bb6-8d90-4c6a-a456-c3939a8ec75e"
`And have property`("$.title") `whish contains` "Hello world!" `And have property`("$.title") `whish contains` "Hello world!"
} }
} }
} }
@Test
fun `I cannot create an constitution if bad request`() {
withIntegrationApplication {
`Given I have citizen`("Henri", "Poincaré")
`When I send a POST request`("/constitutions", Validate.ALL - Validate.REQUEST_BODY) {
`authenticated as`("Henri", "Poincaré")
`with body`("""
{
"versionId":"15814bb6-8d90-4c6a-a456-c3939a8ec75e",
"title":"Hello world!",
"anonymous":true,
"titles":[
{
"name":"plop",
"wrongField":0
}
]
}
""")
} `Then the response should be` BadRequest
}
}
} }