Test openapi schema response of FindArticlesVersion,GetOneArticle,UpsertArticle

change snack_case to camelCase
This commit is contained in:
2021-03-12 23:32:32 +01:00
parent ed0873837b
commit 9c88adbabd
17 changed files with 432 additions and 156 deletions

View File

@@ -138,11 +138,11 @@ fun Application.module(env: Env = PROD) {
install(ContentNegotiation) {
jackson {
propertyNamingStrategy = PropertyNamingStrategies.SNAKE_CASE
propertyNamingStrategy = PropertyNamingStrategies.LOWER_CAMEL_CASE
registerModule(JodaModule())
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
configure(SerializationFeature.INDENT_OUTPUT, true)
setDefaultPrettyPrinter(
DefaultPrettyPrinter().apply {

View File

@@ -29,7 +29,7 @@ data class ArticleForView(
val content: String,
val description: String,
val tags: List<String> = emptyList(),
override val createdBy: CitizenRef,
override val createdBy: CitizenCreator,
override val versionNumber: Int = 0,
override val versionId: UUID = UUID.randomUUID(),
val workgroup: WorkgroupCart? = null,
@@ -37,7 +37,7 @@ data class ArticleForView(
override val draft: Boolean = false,
override val deletedAt: DateTime? = null
) : ArticleRef(id),
ArticleAuthI<CitizenRef>,
ArticleAuthI<CitizenCreator>,
ArticleWithTitleI,
Versionable,
CreatedAt by CreatedAt.Imp(),
@@ -79,9 +79,10 @@ class ArticleForListing(
id: UUID? = null,
override val title: String,
override val createdBy: CitizenCreator,
override val workgroup: WorkgroupCart?,
override val deletedAt: DateTime?,
override val draft: Boolean
override val workgroup: WorkgroupCart? = null,
override val deletedAt: DateTime? = null,
override val draft: Boolean = false,
val lastVersion: Boolean = false
) : ArticleForListingI,
ArticleRef(id),
ArticleAuthI<CitizenCartI>,

View File

@@ -13,13 +13,13 @@ class ArticleRepository(override var requester: Requester) : RepositoryI {
return function.selectOne("id" to id)
}
fun findVersionsById(page: Int = 1, limit: Int = 50, id: UUID): Paginated<ArticleForView> {
fun findVersionsById(page: Int = 1, limit: Int = 50, id: UUID): Paginated<ArticleForListing> {
return requester
.getFunction("find_articles_versions_by_id")
.select(page, limit, "id" to id)
}
fun findVersionsByVersionId(page: Int = 1, limit: Int = 50, versionId: UUID): Paginated<ArticleForView> {
fun findVersionsByVersionId(page: Int = 1, limit: Int = 50, versionId: UUID): Paginated<ArticleForListing> {
return requester
.getFunction("find_articles_versions_by_version_id")
.select(page, limit, "version_id" to versionId)

View File

@@ -1,7 +1,9 @@
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
import fr.dcproject.component.article.database.ArticleRef
import fr.dcproject.component.article.database.ArticleRepository
import fr.dcproject.component.auth.citizenOrNull
@@ -37,7 +39,34 @@ object FindArticleVersions {
get<ArticleVersionsRequest> {
repo.findVersions(it)
.apply { ac.assert { canView(result, citizenOrNull) } }
.let { call.respond(it) }
.run {
call.respond(
toOutput { a: ArticleForListing ->
object {
val id = a.id
val title = a.title
val createdBy = object {
val id = a.createdBy.id
val name = a.createdBy.name.let { n ->
object {
val firstName = n.firstName
val lastName = n.lastName
}
}
val email = a.createdBy.email
}
val workgroup = a.workgroup?.let { w ->
object {
val id = w.id
val name = w.name
}
}
val draft = a.draft
val lastVersion = a.lastVersion
}
}
)
}
}
}
}

View File

@@ -1,7 +1,5 @@
package fr.dcproject.component.article.routes
import fr.dcproject.common.dto.CreatedAt
import fr.dcproject.common.dto.Versionable
import fr.dcproject.common.security.assert
import fr.dcproject.component.article.ArticleAccessControl
import fr.dcproject.component.article.ArticleViewManager
@@ -9,10 +7,6 @@ import fr.dcproject.component.article.database.ArticleForView
import fr.dcproject.component.article.database.ArticleRef
import fr.dcproject.component.article.database.ArticleRepository
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.opinion.dto.Opinionable
import fr.dcproject.component.views.dto.Viewable
import fr.dcproject.component.views.entity.ViewAggregation
import fr.dcproject.component.vote.dto.Votable
import io.ktor.application.call
import io.ktor.features.NotFoundException
import io.ktor.locations.KtorExperimentalLocationsAPI
@@ -30,39 +24,56 @@ object GetOneArticle {
val article = ArticleRef(article)
}
class Output(
article: ArticleForView,
views: ViewAggregation = ViewAggregation()
) : CreatedAt by CreatedAt.Imp(article),
Opinionable by Opinionable.Imp(article),
Votable by Votable.Imp(article),
Versionable by Versionable.Imp(article),
Viewable by Viewable.Imp(views) {
val id = article.id
val title = article.title
val anonymous = article.anonymous
val content = article.content
val description = article.description
val tags = article.tags
val draft = article.draft
val lastVersion = article.lastVersion
val createdBy = article.createdBy
val workgroup = article.workgroup?.let { Workgroup(article.workgroup.id, article.workgroup.name) }
class Workgroup(val id: UUID, val name: String)
}
fun Route.getOneArticle(viewManager: ArticleViewManager<ArticleForView>, ac: ArticleAccessControl, repo: ArticleRepository) {
get<ArticleRequest> {
val article: ArticleForView = repo.findById(it.article.id) ?: throw NotFoundException("Article ${it.article.id} not found")
ac.assert { canView(article, citizenOrNull) }
Output(
article,
viewManager.getViewsCount(article)
).also { out ->
call.respond(out)
}
call.respond(
article.let { a ->
object {
val id = a.id
val versionId = a.versionId
val versionNumber = a.versionNumber
val title = a.title
val anonymous = a.anonymous
val content = a.content
val description = a.description
val tags = a.tags
val draft = a.draft
val lastVersion = a.lastVersion
val createdAt = a.createdAt
val createdBy: Any = object {
val id: UUID = a.createdBy.id
val name: Any = object {
val firstName: String = a.createdBy.name.firstName
val lastName: String = a.createdBy.name.lastName
}
val email: String = a.createdBy.email
}
val workgroup: Any? = a.workgroup?.let { w ->
object {
val id: UUID = w.id
val name: String = w.name
}
}
val votes: Any = object {
val up: Int = a.votes.up
val neutral: Int = a.votes.neutral
val down: Int = a.votes.down
val total: Int = a.votes.total
val score: Int = a.votes.score
}
val views: Any = viewManager.getViewsCount(article).let { v ->
object {
val total = v.total
val unique = v.unique
}
}
val opinions: Map<String, Int> = a.opinions
}
}
)
launch {
viewManager.addView(call.request.local.remoteHost, article, citizenOrNull)

View File

@@ -4,7 +4,6 @@ import fr.dcproject.common.security.assert
import fr.dcproject.common.utils.receiveOrBadRequest
import fr.dcproject.component.article.ArticleAccessControl
import fr.dcproject.component.article.database.ArticleForUpdate
import fr.dcproject.component.article.database.ArticleForView
import fr.dcproject.component.article.database.ArticleRepository
import fr.dcproject.component.article.routes.UpsertArticle.UpsertArticleRequest.Input
import fr.dcproject.component.auth.citizen
@@ -57,9 +56,16 @@ object UpsertArticle {
post<UpsertArticleRequest> {
val article = call.convertRequestToEntity()
ac.assert { canUpsert(article, citizenOrNull) }
val newArticle: ArticleForView = repo.upsert(article) ?: error("Article not updated")
call.respond(newArticle)
publisher.publish(ArticleUpdateNotification(newArticle))
repo.upsert(article)?.let { a ->
call.respond(
object {
val id: UUID = a.id
val versionId = a.versionId
val versionNumber = a.versionNumber
}
)
publisher.publish(ArticleUpdateNotification(a))
} ?: error("Article not updated")
}
}
}