From bb637dd96a3d19cdd2b2c9d9fa36dbcc90f916aa Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 5 Mar 2021 00:39:49 +0100 Subject: [PATCH] #71 Use response object for route FindArticles --- .../fr/dcproject/common/dto/CreatedBy.kt | 13 ++++++++ .../fr/dcproject/common/dto/Paginated.kt | 16 ++++++++++ .../component/article/database/Article.kt | 4 +-- .../component/article/routes/FindArticles.kt | 29 ++++++++++++++++- src/main/resources/openapi.yaml | 32 ++++++++++++++++++- src/test/kotlin/integration/Article routes.kt | 18 ++++++++--- src/test/kotlin/integration/Citizen routes.kt | 10 +++--- .../integration/Comment articles routes.kt | 8 ++--- .../Comment constitutions routes.kt | 10 +++--- src/test/kotlin/integration/Comment routes.kt | 6 ++-- .../kotlin/integration/Constitution routes.kt | 10 +++--- .../integration/Follow articles routes.kt | 10 +++--- .../Follow constitutions routes.kt | 10 +++--- src/test/kotlin/integration/Login routes.kt | 6 ++-- src/test/kotlin/integration/Opinion routes.kt | 8 ++--- .../kotlin/integration/Register routes.kt | 2 +- src/test/kotlin/integration/Vote routes.kt | 6 ++-- .../kotlin/integration/Workgroup routes.kt | 10 +++--- .../kotlin/integration/steps/then/request.kt | 25 ++++++++++++++- 19 files changed, 175 insertions(+), 58 deletions(-) create mode 100644 src/main/kotlin/fr/dcproject/common/dto/CreatedBy.kt create mode 100644 src/main/kotlin/fr/dcproject/common/dto/Paginated.kt diff --git a/src/main/kotlin/fr/dcproject/common/dto/CreatedBy.kt b/src/main/kotlin/fr/dcproject/common/dto/CreatedBy.kt new file mode 100644 index 0000000..b7c2616 --- /dev/null +++ b/src/main/kotlin/fr/dcproject/common/dto/CreatedBy.kt @@ -0,0 +1,13 @@ +package fr.dcproject.common.dto + +import fr.dcproject.component.citizen.database.CitizenI +import java.util.UUID +import fr.dcproject.common.entity.CreatedBy as EntityCreatedBy + +interface CreatedBy { + val createdBy: UUID + + class Imp(parent: EntityCreatedBy) : CreatedBy { + override val createdBy: UUID = parent.createdBy.id + } +} diff --git a/src/main/kotlin/fr/dcproject/common/dto/Paginated.kt b/src/main/kotlin/fr/dcproject/common/dto/Paginated.kt new file mode 100644 index 0000000..1c5e9aa --- /dev/null +++ b/src/main/kotlin/fr/dcproject/common/dto/Paginated.kt @@ -0,0 +1,16 @@ +package fr.dcproject.common.dto + +import fr.dcproject.common.entity.EntityI +import fr.postgresjson.connexion.Paginated + +fun Paginated.toOutput(setup: (E) -> Any): Any { + return object { + val count = this@toOutput.count + val currentPage = this@toOutput.count + val limit = this@toOutput.limit + val offset = this@toOutput.offset + val total = this@toOutput.total + val totalPages = this@toOutput.totalPages + val result = this@toOutput.result.map { setup(it) } + } +} diff --git a/src/main/kotlin/fr/dcproject/component/article/database/Article.kt b/src/main/kotlin/fr/dcproject/component/article/database/Article.kt index 8e63808..408f0c7 100644 --- a/src/main/kotlin/fr/dcproject/component/article/database/Article.kt +++ b/src/main/kotlin/fr/dcproject/component/article/database/Article.kt @@ -8,8 +8,8 @@ import fr.dcproject.common.entity.TargetI import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.Versionable import fr.dcproject.common.entity.VersionableId -import fr.dcproject.component.citizen.database.CitizenCart import fr.dcproject.component.citizen.database.CitizenCartI +import fr.dcproject.component.citizen.database.CitizenCreator import fr.dcproject.component.citizen.database.CitizenI import fr.dcproject.component.citizen.database.CitizenRef import fr.dcproject.component.opinion.entity.Opinionable @@ -78,7 +78,7 @@ class ArticleForUpdate( class ArticleForListing( id: UUID? = null, override val title: String, - override val createdBy: CitizenCart, + override val createdBy: CitizenCreator, override val workgroup: WorkgroupCart?, override val deletedAt: DateTime?, override val draft: Boolean diff --git a/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt b/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt index 87b60ce..efd469c 100644 --- a/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt +++ b/src/main/kotlin/fr/dcproject/component/article/routes/FindArticles.kt @@ -1,5 +1,6 @@ package fr.dcproject.component.article.routes +import fr.dcproject.common.dto.toOutput import fr.dcproject.common.security.assert import fr.dcproject.component.article.ArticleAccessControl import fr.dcproject.component.article.database.ArticleForListing @@ -44,7 +45,33 @@ object FindArticles { get { repo.findArticles(it) .apply { ac.assert { canView(result, citizenOrNull) } } - .let { call.respond(it) } + .let { + call.respond( + it.toOutput { + object { + val id = it.id + val title = it.title + val createdBy = object { + val id = it.createdBy.id + val name = it.createdBy.name.let { + object { + val firstName = it.firstName + val lastName = it.lastName + } + } + val email = it.createdBy.email + } + val workgroup = it.workgroup?.let { + object { + val id = it.id + val name = it.name + } + } + val draft = it.draft + } + } + ) + } } } } diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index bee2f1e..6ba0368 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -243,7 +243,37 @@ paths: result: type: array items: - $ref: '#/components/schemas/ArticleResponse' + properties: + id: + type: string + format: uuid + title: + type: string + created_by: + type: object + properties: + id: + type: string + format: uuid + name: + type: object + properties: + first_name: + type: string + last_name: + type: string + email: + type: string + workgroup: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + draft: + type: boolean post: security: - JWTAuth: [] diff --git a/src/test/kotlin/integration/Article routes.kt b/src/test/kotlin/integration/Article routes.kt index 3edff99..66f61f6 100644 --- a/src/test/kotlin/integration/Article routes.kt +++ b/src/test/kotlin/integration/Article routes.kt @@ -1,18 +1,21 @@ package integration -import integration.steps.`And have property` -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And have property` +import integration.steps.then.`And the response should contain pattern` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a POST request` -import integration.steps.`whish contains` -import integration.steps.and +import integration.steps.then.`whish contains` +import integration.steps.then.and import integration.steps.given.`Given I have article created by workgroup` import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have articles` import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have workgroup` import integration.steps.given.`authenticated as` +import integration.steps.then.`And the response should contain list` +import integration.steps.then.`And the response should not contain` import io.ktor.http.HttpStatusCode.Companion.OK import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tags @@ -28,6 +31,11 @@ class `Article routes` : BaseTest() { `Given I have articles`(3) `When I send a GET request`("/articles") `Then the response should be` OK and { `And the response should not be null`() + `And the response should contain pattern`("$.result[0].created_by.name.first_name", "firstName.+") + `And the response should contain pattern`("$.result[1].created_by.name.first_name", "firstName.+") + `And the response should contain pattern`("$.result[2].created_by.name.first_name", "firstName.+") + `And the response should not contain`("$.result[3]") + `And the response should contain list`("$.result", 3, 3) } } } diff --git a/src/test/kotlin/integration/Citizen routes.kt b/src/test/kotlin/integration/Citizen routes.kt index 77e87df..d9ea4d4 100644 --- a/src/test/kotlin/integration/Citizen routes.kt +++ b/src/test/kotlin/integration/Citizen routes.kt @@ -1,12 +1,12 @@ package integration -import integration.steps.`And have property` -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And have property` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a PUT request` -import integration.steps.`whish contains` -import integration.steps.and +import integration.steps.then.`whish contains` +import integration.steps.then.and import integration.steps.given.`Given I have citizen` import integration.steps.given.`authenticated as` import io.ktor.http.HttpStatusCode.Companion.BadRequest diff --git a/src/test/kotlin/integration/Comment articles routes.kt b/src/test/kotlin/integration/Comment articles routes.kt index 182c0e6..d1d693a 100644 --- a/src/test/kotlin/integration/Comment articles routes.kt +++ b/src/test/kotlin/integration/Comment articles routes.kt @@ -1,13 +1,13 @@ package integration import fr.dcproject.component.citizen.database.CitizenI.Name -import integration.steps.`And the response should contain` -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should contain` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` 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` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have comment on article` diff --git a/src/test/kotlin/integration/Comment constitutions routes.kt b/src/test/kotlin/integration/Comment constitutions routes.kt index 8416dfa..2b192dc 100644 --- a/src/test/kotlin/integration/Comment constitutions routes.kt +++ b/src/test/kotlin/integration/Comment constitutions routes.kt @@ -1,13 +1,13 @@ package integration import fr.dcproject.component.citizen.database.CitizenI.Name -import integration.steps.`And the response should contain list` -import integration.steps.`And the response should contain` -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should contain list` +import integration.steps.then.`And the response should contain` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a POST request` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have comment on constitution` import integration.steps.given.`Given I have constitution` diff --git a/src/test/kotlin/integration/Comment routes.kt b/src/test/kotlin/integration/Comment routes.kt index 40d1242..b06a811 100644 --- a/src/test/kotlin/integration/Comment routes.kt +++ b/src/test/kotlin/integration/Comment routes.kt @@ -1,9 +1,9 @@ package integration -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a GET request` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have comment on article` diff --git a/src/test/kotlin/integration/Constitution routes.kt b/src/test/kotlin/integration/Constitution routes.kt index 3e74347..7a1ede9 100644 --- a/src/test/kotlin/integration/Constitution routes.kt +++ b/src/test/kotlin/integration/Constitution routes.kt @@ -1,12 +1,12 @@ package integration -import integration.steps.`And have property` -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And have property` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a POST request` -import integration.steps.`whish contains` -import integration.steps.and +import integration.steps.then.`whish contains` +import integration.steps.then.and import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have constitution` import integration.steps.given.`Given I have constitutions` diff --git a/src/test/kotlin/integration/Follow articles routes.kt b/src/test/kotlin/integration/Follow articles routes.kt index 2036bda..d0d0246 100644 --- a/src/test/kotlin/integration/Follow articles routes.kt +++ b/src/test/kotlin/integration/Follow articles routes.kt @@ -1,13 +1,13 @@ package integration -import integration.steps.`And the response should be null` -import integration.steps.`And the response should contain` -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should be null` +import integration.steps.then.`And the response should contain` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a DELETE request` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a POST request` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`And follow article` import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have citizen` diff --git a/src/test/kotlin/integration/Follow constitutions routes.kt b/src/test/kotlin/integration/Follow constitutions routes.kt index 015bac0..53feae2 100644 --- a/src/test/kotlin/integration/Follow constitutions routes.kt +++ b/src/test/kotlin/integration/Follow constitutions routes.kt @@ -1,13 +1,13 @@ package integration -import integration.steps.`And the response should be null` -import integration.steps.`And the response should contain` -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should be null` +import integration.steps.then.`And the response should contain` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a DELETE request` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a POST request` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`And follow constitution` import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have constitution` diff --git a/src/test/kotlin/integration/Login routes.kt b/src/test/kotlin/integration/Login routes.kt index 768f752..65f837b 100644 --- a/src/test/kotlin/integration/Login routes.kt +++ b/src/test/kotlin/integration/Login routes.kt @@ -1,8 +1,8 @@ package integration -import integration.steps.`And the response should not be null` -import integration.steps.`Then the response should be` -import integration.steps.`and should contains` +import integration.steps.then.`And the response should not be null` +import integration.steps.then.`Then the response should be` +import integration.steps.then.`and should contains` import integration.steps.`when`.`When I send a POST request` import integration.steps.given.`Given I have citizen` import integration.steps.given.`authenticated as` diff --git a/src/test/kotlin/integration/Opinion routes.kt b/src/test/kotlin/integration/Opinion routes.kt index 423db3c..29990be 100644 --- a/src/test/kotlin/integration/Opinion routes.kt +++ b/src/test/kotlin/integration/Opinion routes.kt @@ -1,12 +1,12 @@ package integration import fr.dcproject.component.citizen.database.CitizenI.Name -import integration.steps.`And the response should contain list` -import integration.steps.`And the response should contain` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should contain list` +import integration.steps.then.`And the response should contain` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a PUT request` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`Given I have an opinion choice` import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have citizen` diff --git a/src/test/kotlin/integration/Register routes.kt b/src/test/kotlin/integration/Register routes.kt index 014ba31..3614615 100644 --- a/src/test/kotlin/integration/Register routes.kt +++ b/src/test/kotlin/integration/Register routes.kt @@ -1,6 +1,6 @@ package integration -import integration.steps.`Then the response should be` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a POST request` import io.ktor.http.HttpStatusCode import org.amshove.kluent.`should be null` diff --git a/src/test/kotlin/integration/Vote routes.kt b/src/test/kotlin/integration/Vote routes.kt index c163f60..e657e53 100644 --- a/src/test/kotlin/integration/Vote routes.kt +++ b/src/test/kotlin/integration/Vote routes.kt @@ -1,11 +1,11 @@ package integration import fr.dcproject.component.citizen.database.CitizenI.Name -import integration.steps.`And the response should contain` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should contain` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a GET request` import integration.steps.`when`.`When I send a PUT request` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`Given I have article` import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have comment on article` diff --git a/src/test/kotlin/integration/Workgroup routes.kt b/src/test/kotlin/integration/Workgroup routes.kt index 4e80932..80a1a1b 100644 --- a/src/test/kotlin/integration/Workgroup routes.kt +++ b/src/test/kotlin/integration/Workgroup routes.kt @@ -1,15 +1,15 @@ package integration import fr.dcproject.component.citizen.database.CitizenI.Name -import integration.steps.`And the response should be null` -import integration.steps.`And the response should contain list` -import integration.steps.`And the response should contain` -import integration.steps.`Then the response should be` +import integration.steps.then.`And the response should be null` +import integration.steps.then.`And the response should contain list` +import integration.steps.then.`And the response should contain` +import integration.steps.then.`Then the response should be` import integration.steps.`when`.`When I send a DELETE request` 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` -import integration.steps.and +import integration.steps.then.and import integration.steps.given.`Given I have citizen` import integration.steps.given.`Given I have workgroup` import integration.steps.given.`With members` diff --git a/src/test/kotlin/integration/steps/then/request.kt b/src/test/kotlin/integration/steps/then/request.kt index f1a49ea..c4ed68a 100644 --- a/src/test/kotlin/integration/steps/then/request.kt +++ b/src/test/kotlin/integration/steps/then/request.kt @@ -1,8 +1,9 @@ -package integration.steps +package integration.steps.then import assert.assertGreaterThan import assert.assertLessThan import com.jayway.jsonpath.JsonPath +import com.jayway.jsonpath.PathNotFoundException import io.ktor.http.HttpStatusCode import io.ktor.server.testing.TestApplicationCall import io.ktor.server.testing.TestApplicationResponse @@ -12,8 +13,10 @@ import org.amshove.kluent.`should be null` import org.amshove.kluent.`should be` import org.amshove.kluent.`should not be null` import org.amshove.kluent.shouldContain +import org.junit.jupiter.api.assertThrows import kotlin.test.assertEquals import kotlin.test.assertNotNull +import kotlin.test.assertTrue fun TestApplicationCall.`Then the response should be`(status: HttpStatusCode? = null, block: TestApplicationResponse.() -> Unit): TestApplicationCall = this.apply { if (status != null) { @@ -62,6 +65,26 @@ inline fun TestApplicationResponse.`And the response should contain` } } +fun TestApplicationResponse.`And the response should not contain`(path: String) { + assertThrows { + JsonPath.read(content, path) + } +} + +fun TestApplicationResponse.`And the response should contain pattern`(path: String, expectedRegex: String): Any { + return JsonPath.read(content, path).also { + it.let { + if (it is JSONArray && it.count() == 1) { + it.first() + } else { + it + } + }?.let { + assertTrue(expectedRegex.toRegex().containsMatchIn(it.toString())) + } ?: throw AssertionError("\"$path -> element not found on json response") + } +} + fun TestApplicationResponse.`And the response should contain list`(path: String, min: Int? = null, max: Int? = null) { JsonPath.read(content, path).also { assertNotNull(it)