improve security.
This commit is contained in:
@@ -1,12 +1,9 @@
|
|||||||
package fr.dcproject.entity
|
package fr.dcproject.entity
|
||||||
|
|
||||||
import fr.postgresjson.entity.EntityCreatedAt
|
import fr.postgresjson.entity.*
|
||||||
import fr.postgresjson.entity.EntityCreatedAtImp
|
|
||||||
import fr.postgresjson.entity.UuidEntity
|
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class Citizen(
|
class Citizen(
|
||||||
id: UUID = UUID.randomUUID(),
|
id: UUID = UUID.randomUUID(),
|
||||||
var name: Name?,
|
var name: Name?,
|
||||||
@@ -16,7 +13,8 @@ class Citizen(
|
|||||||
var followanonymous: Boolean? = null,
|
var followanonymous: Boolean? = null,
|
||||||
var user: User?
|
var user: User?
|
||||||
) : UuidEntity(id),
|
) : UuidEntity(id),
|
||||||
EntityCreatedAt by EntityCreatedAtImp() {
|
EntityCreatedAt by EntityCreatedAtImp(),
|
||||||
|
EntityDeletedAt by EntityDeletedAtImp() {
|
||||||
data class Name(
|
data class Name(
|
||||||
var firstName: String?,
|
var firstName: String?,
|
||||||
var lastName: String?,
|
var lastName: String?,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package fr.dcproject.entity
|
package fr.dcproject.entity
|
||||||
|
|
||||||
import fr.postgresjson.entity.EntityUpdatedAt
|
import fr.postgresjson.entity.*
|
||||||
import fr.postgresjson.entity.EntityUpdatedAtImp
|
|
||||||
import fr.postgresjson.entity.UuidEntity
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
open class Comment <T: UuidEntity> (
|
open class Comment <T: UuidEntity> (
|
||||||
@@ -14,4 +12,5 @@ open class Comment <T: UuidEntity> (
|
|||||||
var parent: Comment<T>? = null,
|
var parent: Comment<T>? = null,
|
||||||
var parentsIds: List<UUID>? = null
|
var parentsIds: List<UUID>? = null
|
||||||
): Extra<T>(id, createdBy),
|
): Extra<T>(id, createdBy),
|
||||||
EntityUpdatedAt by EntityUpdatedAtImp()
|
EntityUpdatedAt by EntityUpdatedAtImp(),
|
||||||
|
EntityDeletedAt by EntityDeletedAtImp()
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import io.ktor.routing.Route
|
|||||||
import fr.dcproject.entity.Article as ArticleEntity
|
import fr.dcproject.entity.Article as ArticleEntity
|
||||||
import fr.dcproject.repository.Article as ArticleRepository
|
import fr.dcproject.repository.Article as ArticleRepository
|
||||||
|
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
object ArticlesPaths {
|
object ArticlesPaths {
|
||||||
@Location("/articles") class ArticlesRequest(page: Int = 1, limit: Int = 50, val sort: String? = null, val direction: RepositoryI.Direction? = null, val search: String? = null) {
|
@Location("/articles") class ArticlesRequest(page: Int = 1, limit: Int = 50, val sort: String? = null, val direction: RepositoryI.Direction? = null, val search: String? = null) {
|
||||||
@@ -30,9 +29,8 @@ object ArticlesPaths {
|
|||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.article(repo: ArticleRepository) {
|
fun Route.article(repo: ArticleRepository) {
|
||||||
get<ArticlesPaths.ArticlesRequest> {
|
get<ArticlesPaths.ArticlesRequest> {
|
||||||
assertCan(VIEW)
|
|
||||||
|
|
||||||
val articles = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
val articles = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
||||||
|
assertCan(VIEW, articles.result)
|
||||||
call.respond(articles)
|
call.respond(articles)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,11 +41,11 @@ fun Route.article(repo: ArticleRepository) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post<ArticlesPaths.PostArticleRequest> {
|
post<ArticlesPaths.PostArticleRequest> {
|
||||||
assertCan(CREATE)
|
|
||||||
|
|
||||||
val article = call.receive<ArticleEntity>()
|
val article = call.receive<ArticleEntity>()
|
||||||
article.createdBy = citizen
|
article.createdBy = citizen
|
||||||
|
|
||||||
|
assertCan(CREATE, article)
|
||||||
|
|
||||||
repo.upsert(article)
|
repo.upsert(article)
|
||||||
|
|
||||||
call.respond(article)
|
call.respond(article)
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ object CitizenPaths {
|
|||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.citizen(repo: CitizenRepository) {
|
fun Route.citizen(repo: CitizenRepository) {
|
||||||
get<CitizenPaths.CitizensRequest> {
|
get<CitizenPaths.CitizensRequest> {
|
||||||
assertCan(VIEW)
|
|
||||||
|
|
||||||
val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
||||||
|
assertCan(VIEW, citizens.result)
|
||||||
call.respond(citizens)
|
call.respond(citizens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,8 @@ object CommentArticlePaths {
|
|||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.commentArticle(repo: CommentArticleRepository) {
|
fun Route.commentArticle(repo: CommentArticleRepository) {
|
||||||
get<CommentArticlePaths.ArticleCommentRequest> {
|
get<CommentArticlePaths.ArticleCommentRequest> {
|
||||||
assertCan(VIEW, it.article)
|
|
||||||
|
|
||||||
val comment = repo.findByTarget(it.article)
|
val comment = repo.findByTarget(it.article)
|
||||||
|
assertCan(VIEW, comment.result)
|
||||||
call.respond(HttpStatusCode.OK, comment)
|
call.respond(HttpStatusCode.OK, comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +48,7 @@ fun Route.commentArticle(repo: CommentArticleRepository) {
|
|||||||
|
|
||||||
get<CommentArticlePaths.CitizenCommentArticleRequest> {
|
get<CommentArticlePaths.CitizenCommentArticleRequest> {
|
||||||
val comments = repo.findByCitizen(it.citizen)
|
val comments = repo.findByCitizen(it.citizen)
|
||||||
|
assertCan(VIEW, comments.result)
|
||||||
call.respond(comments)
|
call.respond(comments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,22 +27,19 @@ object CommentConstitutionPaths {
|
|||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.commentConstitution(repo: CommentConstitutionRepository) {
|
fun Route.commentConstitution(repo: CommentConstitutionRepository) {
|
||||||
get<CommentConstitutionPaths.ConstitutionCommentRequest> {
|
get<CommentConstitutionPaths.ConstitutionCommentRequest> {
|
||||||
assertCan(VIEW, it.constitution)
|
val comments = repo.findByTarget(it.constitution)
|
||||||
|
assertCan(VIEW, comments.result)
|
||||||
val comment = repo.findByTarget(it.constitution)
|
call.respond(HttpStatusCode.OK, comments)
|
||||||
|
|
||||||
call.respond(HttpStatusCode.OK, comment)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
post<CommentConstitutionPaths.ConstitutionCommentRequest> {
|
post<CommentConstitutionPaths.ConstitutionCommentRequest> {
|
||||||
assertCan(CREATE, it.constitution)
|
|
||||||
|
|
||||||
val content = call.receiveText()
|
val content = call.receiveText()
|
||||||
val comment = CommentEntity(
|
val comment = CommentEntity(
|
||||||
target = it.constitution,
|
target = it.constitution,
|
||||||
createdBy = citizen,
|
createdBy = citizen,
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
|
assertCan(CREATE, comment)
|
||||||
repo.comment(comment)
|
repo.comment(comment)
|
||||||
|
|
||||||
call.respond(HttpStatusCode.Created, comment)
|
call.respond(HttpStatusCode.Created, comment)
|
||||||
@@ -50,6 +47,7 @@ fun Route.commentConstitution(repo: CommentConstitutionRepository) {
|
|||||||
|
|
||||||
get<CommentConstitutionPaths.CitizenCommentConstitutionRequest> {
|
get<CommentConstitutionPaths.CitizenCommentConstitutionRequest> {
|
||||||
val comments = repo.findByCitizen(it.citizen)
|
val comments = repo.findByCitizen(it.citizen)
|
||||||
|
assertCan(VIEW, comments.result)
|
||||||
call.respond(comments)
|
call.respond(comments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package fr.dcproject.routes
|
package fr.dcproject.routes
|
||||||
|
|
||||||
import fr.dcproject.citizen
|
import fr.dcproject.citizen
|
||||||
|
import fr.dcproject.security.voter.ConstitutionVoter.Action.CREATE
|
||||||
|
import fr.dcproject.security.voter.ConstitutionVoter.Action.VIEW
|
||||||
|
import fr.dcproject.security.voter.assertCan
|
||||||
import fr.postgresjson.repository.RepositoryI
|
import fr.postgresjson.repository.RepositoryI
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.locations.KtorExperimentalLocationsAPI
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
@@ -28,16 +31,19 @@ object ConstitutionPaths {
|
|||||||
fun Route.constitution(repo: ConstitutionRepository) {
|
fun Route.constitution(repo: ConstitutionRepository) {
|
||||||
get<ConstitutionPaths.ConstitutionsRequest> {
|
get<ConstitutionPaths.ConstitutionsRequest> {
|
||||||
val constitutions = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
val constitutions = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
|
||||||
|
assertCan(VIEW, constitutions.result)
|
||||||
call.respond(constitutions)
|
call.respond(constitutions)
|
||||||
}
|
}
|
||||||
|
|
||||||
get<ConstitutionPaths.ConstitutionRequest> {
|
get<ConstitutionPaths.ConstitutionRequest> {
|
||||||
|
assertCan(VIEW, it.constitution)
|
||||||
call.respond(it.constitution)
|
call.respond(it.constitution)
|
||||||
}
|
}
|
||||||
|
|
||||||
post<ConstitutionPaths.PostConstitutionRequest> {
|
post<ConstitutionPaths.PostConstitutionRequest> {
|
||||||
val constitution = call.receive<ConstitutionEntity>()
|
val constitution = call.receive<ConstitutionEntity>()
|
||||||
constitution.createdBy = citizen
|
constitution.createdBy = citizen
|
||||||
|
assertCan(CREATE, constitution)
|
||||||
|
|
||||||
repo.upsert(constitution)
|
repo.upsert(constitution)
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,25 @@ object FollowArticlePaths {
|
|||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.followArticle(repo: FollowArticleRepository) {
|
fun Route.followArticle(repo: FollowArticleRepository) {
|
||||||
post<FollowArticlePaths.ArticleFollowRequest> {
|
post<FollowArticlePaths.ArticleFollowRequest> {
|
||||||
repo.follow(FollowEntity(target = it.article, createdBy = this.citizen))
|
val follow = FollowEntity(target = it.article, createdBy = this.citizen)
|
||||||
|
// TODO create voter
|
||||||
|
// assertCan(FollowVoter.Action.CREATE, follow)
|
||||||
|
repo.follow(follow)
|
||||||
call.respond(HttpStatusCode.Created)
|
call.respond(HttpStatusCode.Created)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<FollowArticlePaths.ArticleFollowRequest> {
|
delete<FollowArticlePaths.ArticleFollowRequest> {
|
||||||
repo.unfollow(FollowEntity(target = it.article, createdBy = this.citizen))
|
val follow = FollowEntity(target = it.article, createdBy = this.citizen)
|
||||||
|
// TODO create voter
|
||||||
|
// assertCan(FollowVoter.Action.DELETE, follow)
|
||||||
|
repo.unfollow(follow)
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
get<FollowArticlePaths.CitizenFollowArticleRequest> {
|
get<FollowArticlePaths.CitizenFollowArticleRequest> {
|
||||||
val follows = repo.findByCitizen(it.citizen)
|
val follows = repo.findByCitizen(it.citizen)
|
||||||
|
// TODO add security
|
||||||
|
// assertCan(FollowVoter.Action.VIEW, follows)
|
||||||
call.respond(follows)
|
call.respond(follows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,17 +20,25 @@ object FollowConstitutionPaths {
|
|||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.followConstitution(repo: FollowConstitutionRepository) {
|
fun Route.followConstitution(repo: FollowConstitutionRepository) {
|
||||||
post<FollowConstitutionPaths.ConstitutionFollowRequest> {
|
post<FollowConstitutionPaths.ConstitutionFollowRequest> {
|
||||||
repo.follow(FollowEntity(target = it.constitution, createdBy = this.citizen))
|
val follow = FollowEntity(target = it.constitution, createdBy = this.citizen)
|
||||||
|
// TODO create voter
|
||||||
|
// assertCan(FollowVoter.Action.CREATE, follow)
|
||||||
|
repo.follow(follow)
|
||||||
call.respond(HttpStatusCode.Created)
|
call.respond(HttpStatusCode.Created)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete<FollowConstitutionPaths.ConstitutionFollowRequest> {
|
delete<FollowConstitutionPaths.ConstitutionFollowRequest> {
|
||||||
repo.unfollow(FollowEntity(target = it.constitution, createdBy = this.citizen))
|
val follow = FollowEntity(target = it.constitution, createdBy = this.citizen)
|
||||||
|
// TODO create voter
|
||||||
|
// assertCan(FollowVoter.Action.DELETE, follow)
|
||||||
|
repo.unfollow(follow)
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
get<FollowConstitutionPaths.CitizenFollowConstitutionRequest> {
|
get<FollowConstitutionPaths.CitizenFollowConstitutionRequest> {
|
||||||
val follows = repo.findByCitizen(it.citizen)
|
val follows = repo.findByCitizen(it.citizen)
|
||||||
|
// TODO create voter
|
||||||
|
// assertCan(FollowVoter.Action.VIEW, follows)
|
||||||
call.respond(follows)
|
call.respond(follows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package fr.dcproject.security.voter
|
|||||||
import fr.dcproject.entity.User
|
import fr.dcproject.entity.User
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
import fr.dcproject.entity.Article as ArticleEntity
|
import fr.dcproject.entity.Article as ArticleEntity
|
||||||
|
import fr.dcproject.entity.Comment as CommentEntity
|
||||||
import fr.dcproject.entity.Vote as VoteEntity
|
import fr.dcproject.entity.Vote as VoteEntity
|
||||||
|
|
||||||
class ArticleVoter: Voter {
|
class ArticleVoter: Voter {
|
||||||
@@ -15,7 +16,8 @@ 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 || action is CommentVoter.Action || action is VoteVoter.Action)
|
return (action is Action || action is CommentVoter.Action || action is VoteVoter.Action)
|
||||||
&& subject is ArticleEntity?
|
&&
|
||||||
|
(subject is List<*> || subject is ArticleEntity? || subject is VoteEntity<*> || subject is CommentEntity<*>)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
@@ -25,8 +27,20 @@ class ArticleVoter: Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action == Action.VIEW) {
|
if (action == Action.VIEW) {
|
||||||
|
if (subject is ArticleEntity) {
|
||||||
|
return if (subject.isDeleted()) Vote.DENIED
|
||||||
|
else Vote.GRANTED
|
||||||
|
}
|
||||||
|
if (subject is List<*>) {
|
||||||
|
subject.forEach {
|
||||||
|
if (it !is ArticleEntity || it.isDeleted()) {
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
}
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
if (action is CommentVoter.Action) return voteForComment(action)
|
if (action is CommentVoter.Action) return voteForComment(action)
|
||||||
if (action is VoteVoter.Action) return voteForVote(action, subject)
|
if (action is VoteVoter.Action) return voteForVote(action, subject)
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ class CitizenVoter: 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 Citizen?
|
return (action is Action)
|
||||||
|
&&
|
||||||
|
(subject is List<*> || subject is Citizen?)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
@@ -22,9 +24,21 @@ class CitizenVoter: Voter {
|
|||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == Action.VIEW && user != null) {
|
if (action == Action.VIEW) {
|
||||||
|
if (subject is Citizen) {
|
||||||
|
return if (subject.isDeleted()) Vote.DENIED
|
||||||
|
else Vote.GRANTED
|
||||||
|
}
|
||||||
|
if (subject is List<*>) {
|
||||||
|
subject.forEach {
|
||||||
|
if (it !is Citizen || it.isDeleted()) {
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
}
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
if (action == Action.DELETE) {
|
if (action == Action.DELETE) {
|
||||||
return Vote.DENIED
|
return Vote.DENIED
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ class CommentVoter: 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 Comment<*>?
|
return (action is Action) &&
|
||||||
|
(subject is Comment<*>? || subject is List<*>)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
@@ -22,8 +23,20 @@ class CommentVoter: Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action == Action.VIEW) {
|
if (action == Action.VIEW) {
|
||||||
|
if (subject is Comment<*>) {
|
||||||
|
return if (subject.isDeleted()) Vote.DENIED
|
||||||
|
else Vote.GRANTED
|
||||||
|
}
|
||||||
|
if (subject is List<*>) {
|
||||||
|
subject.forEach {
|
||||||
|
if (it !is Comment<*> || it.isDeleted()) {
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
}
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
if (action == Action.UPDATE && user != null && subject is Comment<*> && user.id == subject.createdBy?.userId) {
|
if (action == Action.UPDATE && user != null && subject is Comment<*> && user.id == subject.createdBy?.userId) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package fr.dcproject.security.voter
|
package fr.dcproject.security.voter
|
||||||
|
|
||||||
|
import fr.dcproject.entity.Comment
|
||||||
import fr.dcproject.entity.User
|
import fr.dcproject.entity.User
|
||||||
import io.ktor.application.ApplicationCall
|
import io.ktor.application.ApplicationCall
|
||||||
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
import fr.dcproject.entity.Constitution as ConstitutionEntity
|
||||||
@@ -14,7 +15,9 @@ class ConstitutionVoter: 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 || action is CommentVoter.Action) && subject is ConstitutionEntity?
|
return (action is Action || action is CommentVoter.Action || action is VoteVoter.Action)
|
||||||
|
&&
|
||||||
|
(subject is List<*> || subject is ConstitutionEntity? || subject is VoteEntity<*> || subject is Comment<*>)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
@@ -24,8 +27,20 @@ class ConstitutionVoter: Voter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action == Action.VIEW) {
|
if (action == Action.VIEW) {
|
||||||
|
if (subject is ConstitutionEntity) {
|
||||||
|
return if (subject.isDeleted()) Vote.DENIED
|
||||||
|
else Vote.GRANTED
|
||||||
|
}
|
||||||
|
if (subject is List<*>) {
|
||||||
|
subject.forEach {
|
||||||
|
if (it !is ConstitutionEntity || it.isDeleted()) {
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
}
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
}
|
}
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
if (action == Action.DELETE && user is User && subject is ConstitutionEntity && subject.createdBy?.userId == user.id) {
|
if (action == Action.DELETE && user is User && subject is ConstitutionEntity && subject.createdBy?.userId == user.id) {
|
||||||
return Vote.GRANTED
|
return Vote.GRANTED
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ create table comment
|
|||||||
"content" text not null check ( content != '' and length(content) < 4096),
|
"content" text not null check ( content != '' and length(content) < 4096),
|
||||||
parent_id uuid references comment (id),
|
parent_id uuid references comment (id),
|
||||||
parents_ids uuid[],
|
parents_ids uuid[],
|
||||||
|
deleted_at timestamptz null,
|
||||||
foreign key (created_by_id) references citizen (id),
|
foreign key (created_by_id) references citizen (id),
|
||||||
primary key (id)
|
primary key (id)
|
||||||
) inherits (extra);
|
) inherits (extra);
|
||||||
|
|||||||
Reference in New Issue
Block a user