Implement comment constitution

fix bugs
This commit is contained in:
2019-08-28 23:32:43 +02:00
parent 33f4992b5e
commit 4c2da6ab71
17 changed files with 277 additions and 86 deletions

View File

@@ -12,11 +12,7 @@ import fr.dcproject.entity.Citizen
import fr.dcproject.entity.Constitution
import fr.dcproject.entity.User
import fr.dcproject.routes.*
import fr.dcproject.security.voter.ArticleVoter
import fr.dcproject.security.voter.AuthorizationVoter
import fr.dcproject.security.voter.CitizenVoter
import fr.dcproject.security.voter.CommentVoter
import fr.postgresjson.migration.Migrations
import fr.dcproject.security.voter.*
import io.ktor.application.Application
import io.ktor.application.ApplicationCall
import io.ktor.application.call
@@ -40,7 +36,6 @@ import java.util.*
import java.util.concurrent.CompletionException
import fr.dcproject.repository.Article as RepositoryArticle
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.User as UserRepository
@@ -92,14 +87,6 @@ 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> {
decode { values, _ ->
val id = values.singleOrNull()?.let { UUID.fromString(it) }
@@ -115,6 +102,7 @@ fun Application.module() {
install(AuthorizationVoter) {
voters = mutableListOf(
ArticleVoter(),
ConstitutionVoter(),
CitizenVoter(),
CommentVoter()
)
@@ -166,6 +154,7 @@ fun Application.module() {
followConstitution(get())
comment(get())
commentArticle(get())
commentConstitution(get())
}
}

View File

@@ -8,6 +8,7 @@ import org.koin.dsl.module
import fr.dcproject.repository.Article as ArticleRepository
import fr.dcproject.repository.Citizen as CitizenRepository
import fr.dcproject.repository.CommentArticle as CommentArticleRepository
import fr.dcproject.repository.CommentConstitution as CommentConstitutionRepository
import fr.dcproject.repository.CommentGeneric as CommentGenericRepository
import fr.dcproject.repository.Constitution as ConstitutionRepository
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
@@ -37,8 +38,7 @@ val Module = module {
single { FollowConstitutionRepository(get()) }
single { CommentGenericRepository(get()) }
single { CommentArticleRepository(get()) }
// TODO implment constitution
// single { CommentConstitutionRepository(get()) }
single { CommentConstitutionRepository(get()) }
single { Migrations(connection = get(), directory = config.sqlFiles) }
}

View File

@@ -7,7 +7,7 @@ class Constitution(
id: UUID = UUID.randomUUID(),
var title: String?,
var annonymous: Boolean?,
var titles: List<Title>,
var titles: List<Title> = listOf(),
createdBy: Citizen?
): UuidEntity(id),
EntityVersioning<UUID, Int> by UuidEntityVersioning(),

View File

@@ -14,11 +14,7 @@ import fr.dcproject.entity.Constitution as ConstitutionEntity
abstract class Comment <T: UuidEntity>(override var requester: Requester): RepositoryI<CommentEntity<T>> {
override val entityName = CommentEntity::class as KClass<CommentEntity<T>>
open fun findById(id: UUID): CommentEntity<ArticleEntity>? {
return requester
.getFunction("find_comment_by_id")
.selectOne(mapOf("id" to id))
}
abstract fun findById(id: UUID): CommentEntity<T>?
abstract fun findByCitizen(
citizen: CitizenEntity,
@@ -81,23 +77,29 @@ abstract class Comment <T: UuidEntity>(override var requester: Requester): Repos
}
fun edit(comment: CommentEntity<T>) {
val reference = comment.target::class.simpleName!!.toLowerCase()
requester
.getFunction("edit_comment")
.sendQuery(
"reference" to reference,
"id" to comment.id,
"content" to comment.content
)
}
}
class CommentGeneric (requester: Requester): Comment<UuidEntity>(requester) {
class GenericTargetEntity(id: UUID = UUID.randomUUID()): UuidEntity(id)
class CommentGeneric (requester: Requester): Comment<GenericTargetEntity>(requester) {
override fun findById(id: UUID): CommentEntity<GenericTargetEntity>? {
return requester
.getFunction("find_comment_by_id")
.selectOne(mapOf("id" to id))
}
override fun findByCitizen(
citizen: CitizenEntity,
page: Int,
limit: Int
): Paginated<CommentEntity<UuidEntity>> {
): Paginated<CommentEntity<GenericTargetEntity>> {
return requester.run {
getFunction("find_comments_by_citizen")
.select(page, limit,
@@ -108,6 +110,12 @@ class CommentGeneric (requester: Requester): Comment<UuidEntity>(requester) {
}
class CommentArticle (requester: Requester): Comment<ArticleEntity>(requester) {
override fun findById(id: UUID): CommentEntity<ArticleEntity>? {
return requester
.getFunction("find_comment_by_id")
.selectOne(mapOf("id" to id))
}
override fun findByCitizen(
citizen: CitizenEntity,
page: Int,
@@ -125,6 +133,12 @@ class CommentArticle (requester: Requester): Comment<ArticleEntity>(requester) {
}
class CommentConstitution (requester: Requester): Comment<ConstitutionEntity>(requester) {
override fun findById(id: UUID): CommentEntity<ConstitutionEntity>? {
return requester
.getFunction("find_comment_by_id")
.selectOne(mapOf("id" to id))
}
override fun findByCitizen(
citizen: CitizenEntity,
page: Int,

View File

@@ -33,9 +33,9 @@ class Constitution(override var requester: Requester) : RepositoryI<Constitution
)
}
fun upsert(article: ConstitutionEntity): ConstitutionEntity? {
fun upsert(constitution: ConstitutionEntity): ConstitutionEntity? {
return requester
.getFunction("upsert_constitution")
.selectOne("resource" to article)
.selectOne("resource" to constitution)
}
}

View File

@@ -3,7 +3,6 @@ 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
@@ -14,10 +13,8 @@ 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
@@ -38,7 +35,7 @@ fun Route.comment(repo: CommentRepository) {
assertCan(UPDATE,comment)
comment.content = call.receiveText()
repo.edit(comment as CommentEntity<UuidEntity>)
repo.edit(comment)
call.respond(HttpStatusCode.OK, comment)
}

View File

@@ -11,7 +11,7 @@ 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.request.receiveText
import io.ktor.response.respond
import io.ktor.routing.Route
import fr.dcproject.entity.Article as ArticleEntity
@@ -37,7 +37,7 @@ fun Route.commentArticle(repo: CommentArticleRepository) {
post<CommentArticlePaths.ArticleCommentRequest> {
assertCan(CREATE, it.article)
val content = call.receive<String>()
val content = call.receiveText()
val comment = CommentEntity(
target = it.article,
createdBy = citizen,

View 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.receiveText
import io.ktor.response.respond
import io.ktor.routing.Route
import fr.dcproject.entity.Comment as CommentEntity
import fr.dcproject.entity.Constitution as ConstitutionEntity
import fr.dcproject.repository.CommentConstitution as CommentConstitutionRepository
@KtorExperimentalLocationsAPI
object CommentConstitutionPaths {
@Location("/constitutions/{constitution}/comments") class ConstitutionCommentRequest(val constitution: ConstitutionEntity)
@Location("/citizens/{citizen}/comments/constitutions") class CitizenCommentConstitutionRequest(val citizen: Citizen)
}
@KtorExperimentalLocationsAPI
fun Route.commentConstitution(repo: CommentConstitutionRepository) {
get<CommentConstitutionPaths.ConstitutionCommentRequest> {
assertCan(VIEW, it.constitution)
val comment = repo.findByTarget(it.constitution)
call.respond(HttpStatusCode.OK, comment)
}
post<CommentConstitutionPaths.ConstitutionCommentRequest> {
assertCan(CREATE, it.constitution)
val content = call.receiveText()
val comment = CommentEntity(
target = it.constitution,
createdBy = citizen,
content = content
)
repo.comment(comment)
call.respond(HttpStatusCode.Created, comment)
}
get<CommentConstitutionPaths.CitizenCommentConstitutionRequest> {
val comments = repo.findByCitizen(it.citizen)
call.respond(comments)
}
}

View File

@@ -0,0 +1,47 @@
package fr.dcproject.security.voter
import fr.dcproject.entity.Constitution
import fr.dcproject.entity.User
import io.ktor.application.ApplicationCall
class ConstitutionVoter: Voter {
enum class Action: ActionI {
CREATE,
UPDATE,
VIEW,
DELETE
}
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
return (action is Action || action is CommentVoter.Action) && subject is Constitution?
}
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 == CommentVoter.Action.CREATE) {
return Vote.GRANTED
}
if (action == CommentVoter.Action.VIEW) {
return Vote.GRANTED
}
if (action == Action.DELETE && user is User && subject is Constitution && subject.createdBy?.userId == user.id) {
return Vote.GRANTED
}
if (action == Action.UPDATE && user is User && subject is Constitution && subject.createdBy?.userId == user.id) {
return Vote.GRANTED
}
return Vote.ABSTAIN
}
}