diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5cd2caa..e2668c2 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,10 +1,13 @@
+
+
+
-
+
\ No newline at end of file
diff --git a/src/main/kotlin/fr/dcproject/repository/Comment.kt b/src/main/kotlin/fr/dcproject/repository/Comment.kt
index 89a3547..fcc196f 100644
--- a/src/main/kotlin/fr/dcproject/repository/Comment.kt
+++ b/src/main/kotlin/fr/dcproject/repository/Comment.kt
@@ -46,21 +46,24 @@ abstract class Comment(override var requester: Requester) : Reposit
open fun findByTarget(
target: UuidEntityI,
page: Int = 1,
- limit: Int = 50
+ limit: Int = 50,
+ sort: CommentArticle.Sort = CommentArticle.Sort.CREATED_AT
): Paginated> {
- return findByTarget(target.id, page, limit)
+ return findByTarget(target.id, page, limit, sort)
}
open fun findByTarget(
targetId: UUID,
page: Int = 1,
- limit: Int = 50
+ limit: Int = 50,
+ sort: CommentArticle.Sort = CommentArticle.Sort.CREATED_AT
): Paginated> {
return requester.run {
getFunction("find_comments_by_target")
.select(
page, limit,
- "target_id" to targetId
+ "target_id" to targetId,
+ "sort" to sort.sql
)
}
}
@@ -145,16 +148,27 @@ class CommentArticle(requester: Requester) : Comment(requester) {
override fun findByTarget(
target: UuidEntityI,
page: Int,
- limit: Int
+ limit: Int,
+ sort: Sort
): Paginated> {
return requester.run {
getFunction("find_comments_by_target")
.select(
page, limit,
- "target_id" to target.id
+ "target_id" to target.id,
+ "sort" to sort.sql
)
}
}
+
+ enum class Sort(val sql: String) {
+ CREATED_AT("created_at"), VOTES("votes");
+ companion object {
+ fun fromString(string: String): Sort? {
+ return values().firstOrNull { it.sql == string }
+ }
+ }
+ }
}
class CommentConstitution(requester: Requester) : Comment(requester) {
@@ -182,13 +196,15 @@ class CommentConstitution(requester: Requester) : Comment(reque
override fun findByTarget(
target: UuidEntityI,
page: Int,
- limit: Int
+ limit: Int,
+ sort: CommentArticle.Sort
): Paginated> {
return requester.run {
getFunction("find_comments_by_target")
.select(
page, limit,
- "target_id" to target.id
+ "target_id" to target.id,
+ "sort" to sort.sql
)
}
}
diff --git a/src/main/kotlin/fr/dcproject/routes/CommentArticle.kt b/src/main/kotlin/fr/dcproject/routes/CommentArticle.kt
index befb1d2..0b184fd 100644
--- a/src/main/kotlin/fr/dcproject/routes/CommentArticle.kt
+++ b/src/main/kotlin/fr/dcproject/routes/CommentArticle.kt
@@ -3,6 +3,7 @@ package fr.dcproject.routes
import fr.dcproject.citizen
import fr.dcproject.entity.ArticleRef
import fr.dcproject.entity.Citizen
+import fr.dcproject.repository.CommentArticle.Sort
import fr.dcproject.security.voter.CommentVoter.Action.CREATE
import fr.dcproject.security.voter.CommentVoter.Action.VIEW
import fr.dcproject.security.voter.assertCan
@@ -26,10 +27,12 @@ object CommentArticlePaths {
val article: ArticleRef,
page: Int = 1,
limit: Int = 50,
- val search: String? = null
+ val search: String? = null,
+ sort: String = Sort.CREATED_AT.sql
) {
val page: Int = if (page < 1) 1 else page
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
+ val sort: Sort = Sort.fromString(sort) ?: Sort.CREATED_AT
}
@Location("/citizens/{citizen}/comments/articles")
@@ -39,7 +42,7 @@ object CommentArticlePaths {
@KtorExperimentalLocationsAPI
fun Route.commentArticle(repo: CommentArticleRepository) {
get {
- val comment = repo.findByTarget(it.article, it.page, it.limit)
+ val comment = repo.findByTarget(it.article, it.page, it.limit, it.sort)
assertCan(VIEW, comment.result)
call.respond(HttpStatusCode.OK, comment)
}
diff --git a/src/main/resources/openApi.yaml b/src/main/resources/openApi.yaml
index 991eb3f..42dc61a 100644
--- a/src/main/resources/openApi.yaml
+++ b/src/main/resources/openApi.yaml
@@ -449,6 +449,22 @@ paths:
tags:
- comment
- article
+ parameters:
+ - $ref: '#/components/parameters/page'
+ - $ref: '#/components/parameters/limit'
+ - $ref: '#/components/parameters/search'
+ - name: sort
+ in: query
+ required: false
+ example:
+ - created_at
+ - votes
+ schema:
+ type: string
+ default: created_at
+ enum:
+ - created_at
+ - votes
responses:
200:
description: Return Comment and children
diff --git a/src/main/resources/sql/functions/comment/find_comments_by_target.sql b/src/main/resources/sql/functions/comment/find_comments_by_target.sql
index 3c0b5ed..b4ede4a 100644
--- a/src/main/resources/sql/functions/comment/find_comments_by_target.sql
+++ b/src/main/resources/sql/functions/comment/find_comments_by_target.sql
@@ -2,6 +2,7 @@ create or replace function find_comments_by_target(
_target_id uuid,
"limit" int default 50,
"offset" int default 0,
+ "sort" text default 'created_at',
out resource json,
out total int
) language plpgsql as
@@ -18,7 +19,15 @@ begin
count_vote(com.id) as votes
from "comment" as com
where com.target_id = _target_id
- order by created_at asc,
+ order by
+ case sort
+ when 'votes' then (count_vote(com.id)->>'percent')::int
+ else null
+ end desc,
+ case sort
+ when 'created_at' then com.created_at::text
+ else null
+ end desc,
com.created_at desc
limit "limit" offset "offset"
) as t;
diff --git a/src/main/resources/sql/functions/vote/count_vote.sql b/src/main/resources/sql/functions/vote/count_vote.sql
index 5a04da8..6e507b3 100644
--- a/src/main/resources/sql/functions/vote/count_vote.sql
+++ b/src/main/resources/sql/functions/vote/count_vote.sql
@@ -5,6 +5,7 @@ declare
agg jsonb;
empty jsonb = '{"down":0,"neutral":0,"up":0,"total":0,"score":0}'::jsonb;
score int;
+ percent numeric;
total int;
begin
select jsonb_object_agg(t.label, t.total)
@@ -25,12 +26,14 @@ begin
agg = empty || coalesce(agg, empty);
score = ((agg->>'up')::int - (agg->>'down')::int);
+ percent = ((agg->>'up')::int - (agg->>'down')::int);
total = ((agg->>'up')::int + (agg->>'down')::int + (agg->>'neutral')::int);
resource = agg ||
jsonb_build_object('updated_at', now()) ||
jsonb_build_object('total', total) ||
- jsonb_build_object('score', score);
+ jsonb_build_object('score', score) ||
+ jsonb_build_object('percent', percent);
end;
$$;
diff --git a/src/test/resources/feature/commentArticle.feature b/src/test/resources/feature/commentArticle.feature
index d548899..7016ed1 100644
--- a/src/test/resources/feature/commentArticle.feature
+++ b/src/test/resources/feature/commentArticle.feature
@@ -17,6 +17,14 @@ Feature: comment Article
When I send a GET request to "/articles/9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b/comments"
Then the response status code should be 200
+ Scenario: Can get all comment on article sorted by votes
+ Given I am authenticated as John Doe with id "64b7b379-2298-43ec-b428-ba134930cabd"
+ And I have article with id "9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b"
+ When I send a GET request to "/articles/9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b/comments?sort=votes"
+ Then the response status code should be 200
+ And the response should contain object:
+ | result[1].votes.up | 1 |
+
Scenario: Can get comments on articles of the current citizen
Given I have citizen John Doe with id "64b7b379-2298-43ec-b428-ba134930cabd"
And I have article with id "9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b"
@@ -33,11 +41,11 @@ Feature: comment Article
Hello boy
"""
Then the response status code should be 200
- And the JSON should contain:
- | content | Hello boy |
+ And the JSON should contain:
+ | content | Hello boy |
Scenario: Can get comment by its ID
When I send a GET request to "/comments/2f01c257-cf20-3466-fb10-a3b8eff12a97"
Then the response status code should be 200
- And the JSON should contain:
- | content | Hello boy |
+ And the JSON should contain:
+ | content | Hello boy |