feature #7: Add routes for comment article
This commit is contained in:
@@ -18,6 +18,7 @@ import fr.dcproject.security.voter.CitizenVoter
|
|||||||
import fr.dcproject.security.voter.CommentVoter
|
import fr.dcproject.security.voter.CommentVoter
|
||||||
import fr.postgresjson.migration.Migrations
|
import fr.postgresjson.migration.Migrations
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
|
import io.ktor.application.ApplicationCall
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
import io.ktor.auth.Authentication
|
import io.ktor.auth.Authentication
|
||||||
@@ -39,6 +40,7 @@ import java.util.*
|
|||||||
import java.util.concurrent.CompletionException
|
import java.util.concurrent.CompletionException
|
||||||
import fr.dcproject.repository.Article as RepositoryArticle
|
import fr.dcproject.repository.Article as RepositoryArticle
|
||||||
import fr.dcproject.repository.Citizen as RepositoryCitizen
|
import fr.dcproject.repository.Citizen as RepositoryCitizen
|
||||||
|
import fr.dcproject.repository.CommentGeneric as CommentGenericRepository
|
||||||
import fr.dcproject.repository.Constitution as RepositoryConstitution
|
import fr.dcproject.repository.Constitution as RepositoryConstitution
|
||||||
import fr.dcproject.repository.User as UserRepository
|
import fr.dcproject.repository.User as UserRepository
|
||||||
|
|
||||||
@@ -90,6 +92,14 @@ fun Application.module() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
convert<CommentEntityGeneric> {
|
||||||
|
decode { values, _ ->
|
||||||
|
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||||
|
?: throw InternalError("Cannot convert $values to UUID")
|
||||||
|
get<CommentGenericRepository>().findById(id) ?: throw InternalError("Comment $values not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
convert<Citizen> {
|
convert<Citizen> {
|
||||||
decode { values, _ ->
|
decode { values, _ ->
|
||||||
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||||
@@ -154,6 +164,8 @@ fun Application.module() {
|
|||||||
constitution(get())
|
constitution(get())
|
||||||
followArticle(get())
|
followArticle(get())
|
||||||
followConstitution(get())
|
followConstitution(get())
|
||||||
|
comment(get())
|
||||||
|
commentArticle(get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import io.ktor.util.KtorExperimentalAPI
|
|||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import fr.dcproject.repository.Article as ArticleRepository
|
import fr.dcproject.repository.Article as ArticleRepository
|
||||||
import fr.dcproject.repository.Citizen as CitizenRepository
|
import fr.dcproject.repository.Citizen as CitizenRepository
|
||||||
|
import fr.dcproject.repository.CommentArticle as CommentArticleRepository
|
||||||
|
import fr.dcproject.repository.CommentGeneric as CommentGenericRepository
|
||||||
import fr.dcproject.repository.Constitution as ConstitutionRepository
|
import fr.dcproject.repository.Constitution as ConstitutionRepository
|
||||||
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
|
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
|
||||||
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository
|
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository
|
||||||
@@ -33,6 +35,10 @@ val Module = module {
|
|||||||
single { ConstitutionRepository(get()) }
|
single { ConstitutionRepository(get()) }
|
||||||
single { FollowArticleRepository(get()) }
|
single { FollowArticleRepository(get()) }
|
||||||
single { FollowConstitutionRepository(get()) }
|
single { FollowConstitutionRepository(get()) }
|
||||||
|
single { CommentGenericRepository(get()) }
|
||||||
|
single { CommentArticleRepository(get()) }
|
||||||
|
// TODO implment constitution
|
||||||
|
// single { CommentConstitutionRepository(get()) }
|
||||||
|
|
||||||
single { Migrations(connection = get(), directory = config.sqlFiles) }
|
single { Migrations(connection = get(), directory = config.sqlFiles) }
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/main/kotlin/fr/dcproject/entity/Comment.kt
Normal file
17
src/main/kotlin/fr/dcproject/entity/Comment.kt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package fr.dcproject.entity
|
||||||
|
|
||||||
|
import fr.postgresjson.entity.EntityUpdatedAt
|
||||||
|
import fr.postgresjson.entity.EntityUpdatedAtImp
|
||||||
|
import fr.postgresjson.entity.UuidEntity
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
open class Comment <T: UuidEntity> (
|
||||||
|
id: UUID = UUID.randomUUID(),
|
||||||
|
createdBy: Citizen,
|
||||||
|
override var target: T,
|
||||||
|
var content: String,
|
||||||
|
var responses: List<Comment<T>>? = null,
|
||||||
|
var parent: Comment<T>? = null,
|
||||||
|
var parentsIds: List<UUID>? = null
|
||||||
|
): Extra<T>(id, createdBy),
|
||||||
|
EntityUpdatedAt by EntityUpdatedAtImp()
|
||||||
@@ -10,7 +10,7 @@ interface ExtraI <T: EntityI<UUID>>:
|
|||||||
var target: T
|
var target: T
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Extra<T: EntityI<UUID>>(
|
abstract class Extra<T: UuidEntity>(
|
||||||
id: UUID? = UUID.randomUUID(),
|
id: UUID? = UUID.randomUUID(),
|
||||||
createdBy: Citizen
|
createdBy: Citizen
|
||||||
):
|
):
|
||||||
|
|||||||
139
src/main/kotlin/fr/dcproject/repository/Comment.kt
Normal file
139
src/main/kotlin/fr/dcproject/repository/Comment.kt
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package fr.dcproject.repository
|
||||||
|
|
||||||
|
import fr.postgresjson.connexion.Paginated
|
||||||
|
import fr.postgresjson.connexion.Requester
|
||||||
|
import fr.postgresjson.entity.UuidEntity
|
||||||
|
import fr.postgresjson.repository.RepositoryI
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import fr.dcproject.entity.Article as ArticleEntity
|
||||||
|
import fr.dcproject.entity.Citizen as CitizenEntity
|
||||||
|
import fr.dcproject.entity.Comment as CommentEntity
|
||||||
|
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||||
|
|
||||||
|
open class Comment <T: UuidEntity>(override var requester: Requester): RepositoryI<CommentEntity<T>> {
|
||||||
|
override val entityName = CommentEntity::class as KClass<CommentEntity<T>>
|
||||||
|
|
||||||
|
open fun findByCitizen(
|
||||||
|
citizen: CitizenEntity,
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50
|
||||||
|
): Paginated<CommentEntity<T>> =
|
||||||
|
findByCitizen(citizen.id ?: error("The citizen must have an id"), page, limit)
|
||||||
|
|
||||||
|
open fun findByCitizen(
|
||||||
|
citizenId: UUID,
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50
|
||||||
|
): Paginated<CommentEntity<T>> {
|
||||||
|
return requester.run {
|
||||||
|
getFunction("find_comments_by_citizen")
|
||||||
|
.select(page, limit,
|
||||||
|
"created_by_id" to citizenId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun findByParent(
|
||||||
|
parent: CommentEntity<T>,
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50
|
||||||
|
): Paginated<CommentEntity<T>> {
|
||||||
|
return findByParent(parent.id ?: error("comment must have an ID"), page, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun findByParent(
|
||||||
|
parentId: UUID,
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50
|
||||||
|
): Paginated<CommentEntity<T>> {
|
||||||
|
return requester.run {
|
||||||
|
getFunction("find_comments_by_parent")
|
||||||
|
.select(page, limit,
|
||||||
|
"parent_id" to parentId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun findByTarget(
|
||||||
|
target: UuidEntity,
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50
|
||||||
|
): Paginated<CommentEntity<T>> {
|
||||||
|
return findByTarget(target.id ?: error("comment must have an ID"), page, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun findByTarget(
|
||||||
|
targetId: UUID,
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50
|
||||||
|
): Paginated<CommentEntity<T>> {
|
||||||
|
return requester.run {
|
||||||
|
getFunction("find_comments_by_target")
|
||||||
|
.select(page, limit,
|
||||||
|
"target_id" to targetId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun comment(comment: CommentEntity<T>) {
|
||||||
|
val reference = comment.target::class.simpleName!!.toLowerCase()
|
||||||
|
requester
|
||||||
|
.getFunction("comment")
|
||||||
|
.sendQuery(
|
||||||
|
"reference" to reference,
|
||||||
|
"target_id" to comment.target.id,
|
||||||
|
"created_by_id" to comment.createdBy?.id,
|
||||||
|
"content" to comment.content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun edit(comment: CommentEntity<T>) {
|
||||||
|
val reference = comment.target::class.simpleName!!.toLowerCase()
|
||||||
|
requester
|
||||||
|
.getFunction("edit_comment")
|
||||||
|
.sendQuery(
|
||||||
|
"reference" to reference,
|
||||||
|
"id" to comment.target.id,
|
||||||
|
"content" to comment.content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommentGeneric (requester: Requester): Comment<UuidEntity>(requester) {
|
||||||
|
fun findById(id: UUID): CommentEntity<ArticleEntity>? {
|
||||||
|
return requester
|
||||||
|
.getFunction("find_comment_by_id")
|
||||||
|
.selectOne(mapOf("id" to id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommentArticle (requester: Requester): Comment<ArticleEntity>(requester) {
|
||||||
|
override fun findByCitizen(
|
||||||
|
citizenId: UUID,
|
||||||
|
page: Int,
|
||||||
|
limit: Int
|
||||||
|
): Paginated<CommentEntity<ArticleEntity>> {
|
||||||
|
return requester.run {
|
||||||
|
getFunction("find_comments_article_by_citizen")
|
||||||
|
.select(page, limit,
|
||||||
|
"created_by_id" to citizenId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommentConstitution (requester: Requester): Comment<ConstitutionEntity>(requester) {
|
||||||
|
override fun findByCitizen(
|
||||||
|
citizenId: UUID,
|
||||||
|
page: Int,
|
||||||
|
limit: Int
|
||||||
|
): Paginated<CommentEntity<ConstitutionEntity>> {
|
||||||
|
return requester.run {
|
||||||
|
getFunction("find_comments_constitution_by_citizen")
|
||||||
|
.select(page, limit,
|
||||||
|
"created_by_id" to citizenId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/main/kotlin/fr/dcproject/routes/Comment.kt
Normal file
45
src/main/kotlin/fr/dcproject/routes/Comment.kt
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package fr.dcproject.routes
|
||||||
|
|
||||||
|
import fr.dcproject.security.voter.CommentVoter.Action.UPDATE
|
||||||
|
import fr.dcproject.security.voter.CommentVoter.Action.VIEW
|
||||||
|
import fr.dcproject.security.voter.assertCan
|
||||||
|
import fr.postgresjson.entity.UuidEntity
|
||||||
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.locations.Location
|
||||||
|
import io.ktor.locations.get
|
||||||
|
import io.ktor.locations.put
|
||||||
|
import io.ktor.request.receiveText
|
||||||
|
import io.ktor.response.respond
|
||||||
|
import io.ktor.routing.Route
|
||||||
|
import java.util.*
|
||||||
|
import fr.dcproject.entity.Comment as CommentEntity
|
||||||
|
import fr.dcproject.repository.CommentGeneric as CommentRepository
|
||||||
|
|
||||||
|
typealias CommentEntityGeneric = CommentEntity<UuidEntity>
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
object CommentPaths {
|
||||||
|
// TODO: change UUID by entity converter
|
||||||
|
@Location("/comments/{comment}") class CommentRequest(val comment: UUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Route.comment(repo: CommentRepository) {
|
||||||
|
get<CommentPaths.CommentRequest> {
|
||||||
|
val comment = repo.findById(it.comment)!!
|
||||||
|
assertCan(VIEW, comment)
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.OK, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
put<CommentPaths.CommentRequest> {
|
||||||
|
val comment = repo.findById(it.comment)!!
|
||||||
|
assertCan(UPDATE,comment)
|
||||||
|
|
||||||
|
comment.content = call.receiveText()
|
||||||
|
repo.edit(comment as fr.dcproject.entity.Comment<UuidEntity>)
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.OK, comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/main/kotlin/fr/dcproject/routes/CommentArticle.kt
Normal file
55
src/main/kotlin/fr/dcproject/routes/CommentArticle.kt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package fr.dcproject.routes
|
||||||
|
|
||||||
|
import fr.dcproject.citizen
|
||||||
|
import fr.dcproject.entity.Citizen
|
||||||
|
import fr.dcproject.security.voter.CommentVoter.Action.CREATE
|
||||||
|
import fr.dcproject.security.voter.CommentVoter.Action.VIEW
|
||||||
|
import fr.dcproject.security.voter.assertCan
|
||||||
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.locations.Location
|
||||||
|
import io.ktor.locations.get
|
||||||
|
import io.ktor.locations.post
|
||||||
|
import io.ktor.request.receive
|
||||||
|
import io.ktor.response.respond
|
||||||
|
import io.ktor.routing.Route
|
||||||
|
import fr.dcproject.entity.Article as ArticleEntity
|
||||||
|
import fr.dcproject.entity.Comment as CommentEntity
|
||||||
|
import fr.dcproject.repository.CommentArticle as CommentArticleRepository
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
object CommentArticlePaths {
|
||||||
|
@Location("/articles/{article}/comments") class ArticleCommentRequest(val article: ArticleEntity)
|
||||||
|
@Location("/citizens/{citizen}/comments/articles") class CitizenCommentArticleRequest(val citizen: Citizen)
|
||||||
|
}
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Route.commentArticle(repo: CommentArticleRepository) {
|
||||||
|
get<CommentArticlePaths.ArticleCommentRequest> {
|
||||||
|
assertCan(VIEW, it.article)
|
||||||
|
|
||||||
|
val comment = repo.findByTarget(it.article)
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.OK, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
post<CommentArticlePaths.ArticleCommentRequest> {
|
||||||
|
assertCan(CREATE, it.article)
|
||||||
|
|
||||||
|
val content = call.receive<String>()
|
||||||
|
val comment = CommentEntity(
|
||||||
|
target = it.article,
|
||||||
|
createdBy = citizen,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
repo.comment(comment)
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.Created, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
get<CommentArticlePaths.CitizenCommentArticleRequest> {
|
||||||
|
val comments = repo.findByCitizen(it.citizen)
|
||||||
|
call.respond(comments)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ class ArticleVoter: Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
|
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
|
||||||
return action is Action && subject is Article?
|
return (action is Action || action is CommentVoter.Action) && subject is Article?
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
@@ -26,6 +26,14 @@ class ArticleVoter: Voter {
|
|||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action == CommentVoter.Action.CREATE) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == CommentVoter.Action.VIEW) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
if (action == Action.DELETE && user is User && subject is Article && subject.createdBy?.userId == user.id) {
|
if (action == Action.DELETE && user is User && subject is Article && subject.createdBy?.userId == user.id) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/main/kotlin/fr/dcproject/security/voter/CommentVoter.kt
Normal file
38
src/main/kotlin/fr/dcproject/security/voter/CommentVoter.kt
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package fr.dcproject.security.voter
|
||||||
|
|
||||||
|
import fr.dcproject.entity.Comment
|
||||||
|
import io.ktor.application.ApplicationCall
|
||||||
|
|
||||||
|
class CommentVoter: Voter {
|
||||||
|
enum class Action: ActionI {
|
||||||
|
CREATE,
|
||||||
|
UPDATE,
|
||||||
|
VIEW,
|
||||||
|
DELETE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
|
||||||
|
return action is Action && subject is Comment<*>?
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
|
val user = call.user
|
||||||
|
if (action == Action.CREATE && user != null) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == Action.VIEW) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == Action.UPDATE && user != null && subject is Comment<*> && user.id == subject.createdBy?.userId) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == Action.DELETE) {
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vote.ABSTAIN
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
create or replace function edit_comment(reference regclass, id uuid, content text) returns void
|
create or replace function edit_comment(reference regclass, _id uuid, _content text) returns void
|
||||||
language plpgsql as
|
language plpgsql as
|
||||||
$$
|
$$
|
||||||
declare
|
|
||||||
_id alias for id;
|
|
||||||
_content alias for content;
|
|
||||||
begin
|
begin
|
||||||
if reference = 'article'::regclass then
|
if reference = 'article'::regclass then
|
||||||
update comment_on_article c set
|
update comment_on_article c set
|
||||||
content = _content
|
"content" = _content
|
||||||
where c.id = _id;
|
where c.id = _id;
|
||||||
elseif reference = 'constitution'::regclass then
|
elseif reference = 'constitution'::regclass then
|
||||||
update comment_on_constitution c set
|
update comment_on_constitution c set
|
||||||
content = _content
|
"content" = _content
|
||||||
where c.id = _id;
|
where c.id = _id;
|
||||||
end if;
|
end if;
|
||||||
end;
|
end;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
-- drop function if exists edit_comment(regclass, uuid, uuid, text, uuid);
|
-- drop function if exists edit_comment(regclass, uuid, text);
|
||||||
@@ -9,7 +9,9 @@ begin
|
|||||||
from (
|
from (
|
||||||
select
|
select
|
||||||
com.*,
|
com.*,
|
||||||
json_build_object('id', com.target_id) as target,
|
-- TODO use generic object, not article
|
||||||
|
-- json_build_object('id', com.target_id) as target,
|
||||||
|
find_article_by_id(com.target_id) as target,
|
||||||
find_citizen_by_id(com.created_by_id) as created_by
|
find_citizen_by_id(com.created_by_id) as created_by
|
||||||
from "comment" as com
|
from "comment" as com
|
||||||
where id = _id
|
where id = _id
|
||||||
|
|||||||
35
src/test/resources/feature/comment.feature
Normal file
35
src/test/resources/feature/comment.feature
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Feature: comment Article and Constitution
|
||||||
|
|
||||||
|
# Article
|
||||||
|
Scenario: The route for comment article must response a 201 and return object
|
||||||
|
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 POST request to "/articles/9226c1a3-8091-c3fa-7d0d-c2e98c9bee7b/comments" with body:
|
||||||
|
"""
|
||||||
|
Hello mister
|
||||||
|
"""
|
||||||
|
Then the response status code should be 201
|
||||||
|
|
||||||
|
Scenario: The route for get comments of articles must response a 200 and return objects
|
||||||
|
Given I have citizen 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 "/citizens/64b7b379-2298-43ec-b428-ba134930cabd/comments/articles"
|
||||||
|
Then the response status code should be 200
|
||||||
|
And the response should contain object:
|
||||||
|
| current_page | 1 |
|
||||||
|
| limit | 50 |
|
||||||
|
|
||||||
|
Scenario: The route for edit comment must response a 200 and return object
|
||||||
|
Given I am authenticated as username 3 with id "92877af7-0a45-fd6a-2ed7-fe81e1236b78"
|
||||||
|
When I send a PUT request to "/comments/2f01c257-cf20-3466-fb10-a3b8eff12a97" with body:
|
||||||
|
"""
|
||||||
|
Hello boy
|
||||||
|
"""
|
||||||
|
Then the response status code should be 200
|
||||||
|
# TODO check if data is realy edited
|
||||||
|
And the JSON should contain:
|
||||||
|
| content | Hello boy |
|
||||||
|
|
||||||
|
|
||||||
|
# Constitution
|
||||||
|
# TODO
|
||||||
Reference in New Issue
Block a user