Improve Vote Comment

Add "targetReference" field into Extra Entity
Add VoteCommentRoute to OpenApi
This commit is contained in:
2019-10-07 14:15:43 +02:00
parent d90d3117d5
commit f20964878f
10 changed files with 70 additions and 24 deletions

View File

@@ -15,7 +15,7 @@ import fr.dcproject.repository.FollowArticle as FollowArticleRepository
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository
import fr.dcproject.repository.User as UserRepository import fr.dcproject.repository.User as UserRepository
import fr.dcproject.repository.VoteArticle as VoteArticleRepository import fr.dcproject.repository.VoteArticle as VoteArticleRepository
import fr.dcproject.repository.VoteArticleComment as VoteArticleCommentRepository import fr.dcproject.repository.VoteComment as VoteCommentRepository
import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository
val config = Config() val config = Config()
@@ -44,7 +44,7 @@ val Module = module {
single { CommentConstitutionRepository(get()) } single { CommentConstitutionRepository(get()) }
single { VoteArticleRepository(get()) } single { VoteArticleRepository(get()) }
single { VoteConstitutionRepository(get()) } single { VoteConstitutionRepository(get()) }
single { VoteArticleCommentRepository(get()) } single { VoteCommentRepository(get()) }
single { Migrations(connection = get(), directory = config.sqlFiles) } single { Migrations(connection = get(), directory = config.sqlFiles) }
} }

View File

@@ -6,12 +6,12 @@ import java.util.*
open class Comment <T: UuidEntity> ( open class Comment <T: UuidEntity> (
id: UUID = UUID.randomUUID(), id: UUID = UUID.randomUUID(),
createdBy: Citizen, createdBy: Citizen,
override var target: T, target: T,
var content: String, var content: String,
var responses: List<Comment<T>>? = null, var responses: List<Comment<T>>? = null,
var parent: Comment<T>? = null, var parent: Comment<T>? = null,
var parentsIds: List<UUID>? = null, var parentsIds: List<UUID>? = null,
val childrenCount: Int? = null val childrenCount: Int? = null
): Extra<T>(id, createdBy), ): Extra<T>(id, createdBy, target),
EntityUpdatedAt by EntityUpdatedAtImp(), EntityUpdatedAt by EntityUpdatedAtImp(),
EntityDeletedAt by EntityDeletedAtImp() EntityDeletedAt by EntityDeletedAtImp()

View File

@@ -8,11 +8,14 @@ interface ExtraI <T: EntityI>:
EntityCreatedAt, EntityCreatedAt,
EntityCreatedBy<Citizen>{ EntityCreatedBy<Citizen>{
var target: T var target: T
var targetReference: String
} }
abstract class Extra<T: UuidEntity>( abstract class Extra<T: UuidEntity>(
id: UUID? = UUID.randomUUID(), id: UUID? = UUID.randomUUID(),
createdBy: Citizen createdBy: Citizen,
override var target: T,
override var targetReference: String = target::class.simpleName!!.toLowerCase()
): ):
ExtraI<T>, ExtraI<T>,
UuidEntity(id), UuidEntity(id),

View File

@@ -5,5 +5,5 @@ import java.util.*
class Follow <T: UuidEntity> ( class Follow <T: UuidEntity> (
id: UUID = UUID.randomUUID(), id: UUID = UUID.randomUUID(),
createdBy: Citizen, createdBy: Citizen,
override var target: T target: T
): Extra<T>(id, createdBy) ): Extra<T>(id, createdBy, target)

View File

@@ -8,10 +8,10 @@ import java.util.*
open class Vote <T: UuidEntity> ( open class Vote <T: UuidEntity> (
id: UUID = UUID.randomUUID(), id: UUID = UUID.randomUUID(),
createdBy: Citizen, createdBy: Citizen,
override var target: T, target: T,
var note: Int, var note: Int,
var anonymous: Boolean = true var anonymous: Boolean = true
): Extra<T>(id, createdBy), ): Extra<T>(id, createdBy, target),
EntityUpdatedAt by EntityUpdatedAtImp() { EntityUpdatedAt by EntityUpdatedAtImp() {
init { init {
if (note > 1 && note < -1) { if (note > 1 && note < -1) {

View File

@@ -84,10 +84,8 @@ abstract class Comment <T: UuidEntity>(override var requester: Requester): Repos
} }
} }
class GenericTargetEntity(id: UUID = UUID.randomUUID()): UuidEntity(id) class CommentGeneric (requester: Requester): Comment<UuidEntity>(requester) {
override fun findById(id: UUID): CommentEntity<UuidEntity>? {
class CommentGeneric (requester: Requester): Comment<GenericTargetEntity>(requester) {
override fun findById(id: UUID): CommentEntity<GenericTargetEntity>? {
return requester return requester
.getFunction("find_comment_by_id") .getFunction("find_comment_by_id")
.selectOne(mapOf("id" to id)) .selectOne(mapOf("id" to id))
@@ -97,7 +95,7 @@ class CommentGeneric (requester: Requester): Comment<GenericTargetEntity>(reques
citizen: CitizenEntity, citizen: CitizenEntity,
page: Int, page: Int,
limit: Int limit: Int
): Paginated<CommentEntity<GenericTargetEntity>> { ): Paginated<CommentEntity<UuidEntity>> {
return requester.run { return requester.run {
getFunction("find_comments_by_citizen") getFunction("find_comments_by_citizen")
.select(page, limit, .select(page, limit,

View File

@@ -22,7 +22,7 @@ open class Vote <T: UuidEntity>(override var requester: Requester): RepositoryI<
val reference = if (target is Comment<*>) { val reference = if (target is Comment<*>) {
target::class.simpleName!!.toLowerCase() + target::class.simpleName!!.toLowerCase() +
"_on_" + "_on_" +
target.target::class.simpleName!!.toLowerCase() target.targetReference
} else { } else {
target::class.simpleName!!.toLowerCase() target::class.simpleName!!.toLowerCase()
} }
@@ -101,6 +101,21 @@ class VoteArticleComment (requester: Requester): Vote<Comment<Article>>(requeste
) )
} }
class VoteComment (requester: Requester): Vote<Comment<UuidEntity>>(requester) {
fun findByCitizen(
citizen: CitizenEntity,
page: Int = 1,
limit: Int = 50
): Paginated<VoteEntity<Comment<UuidEntity>>> =
findByCitizen(
citizen.id ?: error("The citizen must have an id"),
"article",
object: TypeReference<List<VoteEntity<Comment<UuidEntity>>>>() {},
page,
limit
)
}
class VoteConstitution (requester: Requester): Vote<Constitution>(requester) { class VoteConstitution (requester: Requester): Vote<Constitution>(requester) {
fun findByCitizen( fun findByCitizen(
citizen: CitizenEntity, citizen: CitizenEntity,

View File

@@ -2,10 +2,10 @@ package fr.dcproject.routes
import fr.dcproject.citizen import fr.dcproject.citizen
import fr.dcproject.entity.Citizen import fr.dcproject.entity.Citizen
import fr.dcproject.repository.CommentArticle import fr.dcproject.repository.CommentGeneric
import fr.dcproject.repository.VoteArticleComment import fr.dcproject.repository.VoteComment
import fr.dcproject.routes.VoteArticlePaths.ArticleCommentVoteRequest
import fr.dcproject.routes.VoteArticlePaths.ArticleVoteRequest import fr.dcproject.routes.VoteArticlePaths.ArticleVoteRequest
import fr.dcproject.routes.VoteArticlePaths.CommentVoteRequest
import fr.dcproject.security.voter.VoteVoter.Action.CREATE import fr.dcproject.security.voter.VoteVoter.Action.CREATE
import fr.dcproject.security.voter.VoteVoter.Action.VIEW import fr.dcproject.security.voter.VoteVoter.Action.VIEW
import fr.dcproject.security.voter.assertCan import fr.dcproject.security.voter.assertCan
@@ -30,8 +30,8 @@ object VoteArticlePaths {
data class Content(var note: Int) data class Content(var note: Int)
} }
@Location("/articles/{article}/comments/{comment}/vote") @Location("/comments/{comment}/vote")
class ArticleCommentVoteRequest(val article: ArticleEntity, val comment: UUID) { class CommentVoteRequest(val comment: UUID) {
data class Content(var note: Int) data class Content(var note: Int)
} }
@@ -53,7 +53,7 @@ object VoteArticlePaths {
} }
@KtorExperimentalLocationsAPI @KtorExperimentalLocationsAPI
fun Route.voteArticle(repo: VoteArticleRepository, voteCommentRepo: VoteArticleComment, commentRepo: CommentArticle) { fun Route.voteArticle(repo: VoteArticleRepository, voteCommentRepo: VoteComment, commentRepo: CommentGeneric) {
put<ArticleVoteRequest> { put<ArticleVoteRequest> {
val content = call.receive<ArticleVoteRequest.Content>() val content = call.receive<ArticleVoteRequest.Content>()
val vote = VoteEntity( val vote = VoteEntity(
@@ -66,9 +66,9 @@ fun Route.voteArticle(repo: VoteArticleRepository, voteCommentRepo: VoteArticleC
call.respond(HttpStatusCode.Created, votes) call.respond(HttpStatusCode.Created, votes)
} }
put<ArticleCommentVoteRequest> { put<CommentVoteRequest> {
val comment = commentRepo.findById(it.comment)!! val comment = commentRepo.findById(it.comment)!!
val content = call.receive<ArticleCommentVoteRequest.Content>() val content = call.receive<CommentVoteRequest.Content>()
val vote = VoteEntity( val vote = VoteEntity(
target = comment, target = comment,
note = content.note, note = content.note,

View File

@@ -405,6 +405,7 @@ paths:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/CommentResponse' $ref: '#/components/schemas/CommentResponse'
/articles/{article}/follows: /articles/{article}/follows:
parameters: parameters:
- $ref: '#/components/parameters/article' - $ref: '#/components/parameters/article'
@@ -451,6 +452,7 @@ paths:
responses: responses:
204: 204:
description: Return only http status 204 on success description: Return only http status 204 on success
/articles/{article}/vote: /articles/{article}/vote:
parameters: parameters:
- $ref: '#/components/parameters/article' - $ref: '#/components/parameters/article'
@@ -492,6 +494,31 @@ paths:
responses: responses:
201: 201:
description: Return only http status 201 on success description: Return only http status 201 on success
/comments/{comment}/vote:
parameters:
- $ref: '#/components/parameters/comment'
put:
security:
- JWTAuth: []
summary: Vote for a comment
tags:
- vote
- comment
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/VoteRequest'
responses:
201:
description: Return votes aggregation
content:
application/json:
schema:
$ref: '#/components/schemas/VoteAggregation'
404:
description: article or comment not found
/citizens/{citizen}/votes/articles: /citizens/{citizen}/votes/articles:
parameters: parameters:
@@ -584,6 +611,7 @@ components:
in: path in: path
required: true required: true
description: the ID of article description: the ID of article
example: d91aa0cd-61d6-83cc-41bb-8d5656e130f7
schema: schema:
type: string type: string
format: uuid format: uuid

View File

@@ -40,10 +40,12 @@ Feature: vote Article
Scenario: Can vote a comment on article Scenario: Can vote a comment on article
Given I am authenticated as John Doe with id "64b7b379-2298-43ec-b428-ba134930cabd" Given I am authenticated as John Doe with id "64b7b379-2298-43ec-b428-ba134930cabd"
And I have comment "ea5c9e87-c99e-4646-a381-2910219e077f" on article "cc9c624e-a27e-42de-af78-ae821c657a68" And I have comment "ea5c9e87-c99e-4646-a381-2910219e077f" on article "cc9c624e-a27e-42de-af78-ae821c657a68"
When I send a PUT request to "/articles/cc9c624e-a27e-42de-af78-ae821c657a68/comments/ea5c9e87-c99e-4646-a381-2910219e077f/vote" with body: When I send a PUT request to "/comments/ea5c9e87-c99e-4646-a381-2910219e077f/vote" with body:
""" """
{ {
"note": -1 "note": -1
} }
""" """
Then the response status code should be 201 Then the response status code should be 201
And the response should contain object:
| down | 1 |