Big refactoring #77
@@ -6,7 +6,7 @@ import fr.postgresjson.entity.*
|
|||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class ArticleForView (
|
data class ArticleForView(
|
||||||
override val id: UUID = UUID.randomUUID(),
|
override val id: UUID = UUID.randomUUID(),
|
||||||
override val title: String,
|
override val title: String,
|
||||||
val anonymous: Boolean = true,
|
val anonymous: Boolean = true,
|
||||||
@@ -32,7 +32,7 @@ data class ArticleForView (
|
|||||||
val lastVersion: Boolean = false
|
val lastVersion: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ArticleForUpdateI<C: CitizenRef> : ArticleI, ArticleWithTitleI, VersionableRef, TargetI, CreatedBy<C> {
|
interface ArticleForUpdateI<C : CitizenRef> : ArticleI, ArticleWithTitleI, VersionableRef, TargetI, CreatedBy<C> {
|
||||||
val anonymous: Boolean
|
val anonymous: Boolean
|
||||||
val content: String
|
val content: String
|
||||||
val description: String
|
val description: String
|
||||||
@@ -40,7 +40,7 @@ interface ArticleForUpdateI<C: CitizenRef> : ArticleI, ArticleWithTitleI, Versio
|
|||||||
val workgroup: WorkgroupRef?
|
val workgroup: WorkgroupRef?
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArticleForUpdate (
|
class ArticleForUpdate(
|
||||||
id: UUID? = null,
|
id: UUID? = null,
|
||||||
override val title: String,
|
override val title: String,
|
||||||
override val anonymous: Boolean = true,
|
override val anonymous: Boolean = true,
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ import fr.dcproject.entity.VersionableRef
|
|||||||
import fr.dcproject.voter.Voter
|
import fr.dcproject.voter.Voter
|
||||||
import fr.dcproject.voter.VoterResponse
|
import fr.dcproject.voter.VoterResponse
|
||||||
|
|
||||||
class ArticleVoter(private val articleRepo: ArticleRepository): Voter() {
|
class ArticleVoter(private val articleRepo: ArticleRepository) : Voter() {
|
||||||
fun <S: ArticleAuthI<*>> canView(subjects: List<S>, citizen: CitizenI?): VoterResponse =
|
fun <S : ArticleAuthI<*>> canView(subjects: List<S>, citizen: CitizenI?): VoterResponse =
|
||||||
canAll(subjects) { canView(it, citizen) }
|
canAll(subjects) { canView(it, citizen) }
|
||||||
|
|
||||||
fun <S: ArticleAuthI<*>> canView(subject: S, citizen: CitizenI?): VoterResponse {
|
fun <S : ArticleAuthI<*>> canView(subject: S, citizen: CitizenI?): VoterResponse {
|
||||||
return if (subject.isDeleted()) denied("Article is deleted", "article.deleted")
|
return if (subject.isDeleted()) denied("Article is deleted", "article.deleted")
|
||||||
else if (subject.draft && (citizen == null || subject.createdBy.id != citizen.id)) denied("Article is draft, but it's not yours", "article.draft.not.yours")
|
else if (subject.draft && (citizen == null || subject.createdBy.id != citizen.id)) denied("Article is draft, but it's not yours", "article.draft.not.yours")
|
||||||
else granted()
|
else granted()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <S: CreatedBy<*>> canDelete(subject: S, citizen: CitizenI?): VoterResponse {
|
fun <S : CreatedBy<*>> canDelete(subject: S, citizen: CitizenI?): VoterResponse {
|
||||||
if (citizen == null) return denied("You must be connected to create article", "article.create.notConnected")
|
if (citizen == null) return denied("You must be connected to create article", "article.create.notConnected")
|
||||||
return if (subject.createdBy.id == citizen.id) {
|
return if (subject.createdBy.id == citizen.id) {
|
||||||
granted()
|
granted()
|
||||||
@@ -26,9 +26,9 @@ class ArticleVoter(private val articleRepo: ArticleRepository): Voter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <S> canUpsert(subject: S, citizen: CitizenI?): VoterResponse
|
fun <S> canUpsert(subject: S, citizen: CitizenI?): VoterResponse
|
||||||
where S: ArticleI,
|
where S : ArticleI,
|
||||||
S: CreatedBy<*>,
|
S : CreatedBy<*>,
|
||||||
S: VersionableRef {
|
S : VersionableRef {
|
||||||
if (citizen == null) return denied("You must be connected to create article", "article.create.notConnected")
|
if (citizen == null) return denied("You must be connected to create article", "article.create.notConnected")
|
||||||
/* The new Article must by created by the same citizen of the connected citizen */
|
/* The new Article must by created by the same citizen of the connected citizen */
|
||||||
if (subject.createdBy.id == citizen.id) {
|
if (subject.createdBy.id == citizen.id) {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ private fun ArticleRepository.findArticles(request: ArticlesRequest): Paginated<
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Route.findArticles (repo: ArticleRepository, voter: ArticleVoter) {
|
fun Route.findArticles(repo: ArticleRepository, voter: ArticleVoter) {
|
||||||
get<ArticlesRequest> {
|
get<ArticlesRequest> {
|
||||||
repo.findArticles(it)
|
repo.findArticles(it)
|
||||||
.apply { voter.assert { canView(result, citizenOrNull) } }
|
.apply { voter.assert { canView(result, citizenOrNull) } }
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.koin.core.KoinComponent
|
|||||||
import org.koin.core.inject
|
import org.koin.core.inject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
@Location("/articles/{articleId}")
|
@Location("/articles/{articleId}")
|
||||||
class ArticleRequest(val articleId: UUID) : KoinComponent {
|
class ArticleRequest(val articleId: UUID) : KoinComponent {
|
||||||
|
|||||||
@@ -5,21 +5,21 @@ import fr.dcproject.voter.VoterResponse
|
|||||||
import fr.postgresjson.entity.EntityDeletedAt
|
import fr.postgresjson.entity.EntityDeletedAt
|
||||||
|
|
||||||
class CitizenVoter : Voter() {
|
class CitizenVoter : Voter() {
|
||||||
fun <S> canView(subjects: List<S>, connectedCitizen: CitizenI?): VoterResponse where S : CitizenI, S: EntityDeletedAt =
|
fun <S> canView(subjects: List<S>, connectedCitizen: CitizenI?): VoterResponse where S : CitizenI, S : EntityDeletedAt =
|
||||||
canAll(subjects) { canView(it, connectedCitizen) }
|
canAll(subjects) { canView(it, connectedCitizen) }
|
||||||
|
|
||||||
fun <S> canView(subject: S, connectedCitizen: CitizenI?): VoterResponse where S : CitizenI, S: EntityDeletedAt {
|
fun <S> canView(subject: S, connectedCitizen: CitizenI?): VoterResponse where S : CitizenI, S : EntityDeletedAt {
|
||||||
if (connectedCitizen == null) return denied("You must be connected to view citizen", "citizen.view.connected")
|
if (connectedCitizen == null) return denied("You must be connected to view citizen", "citizen.view.connected")
|
||||||
return if (subject.isDeleted()) denied("You cannot view a deleted citizen", "citizen.view.deleted")
|
return if (subject.isDeleted()) denied("You cannot view a deleted citizen", "citizen.view.deleted")
|
||||||
else granted()
|
else granted()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <S: CitizenI> canUpdate(subject: S, connectedCitizen: CitizenI?): VoterResponse {
|
fun <S : CitizenI> canUpdate(subject: S, connectedCitizen: CitizenI?): VoterResponse {
|
||||||
if (connectedCitizen == null) return denied("You must be connected to update Citizen", "citizen.update.notConnected")
|
if (connectedCitizen == null) return denied("You must be connected to update Citizen", "citizen.update.notConnected")
|
||||||
return if (subject.id == connectedCitizen.id) granted() else denied("You can only update your citizen", "citizen.update.notYours")
|
return if (subject.id == connectedCitizen.id) granted() else denied("You can only update your citizen", "citizen.update.notYours")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <S: CitizenI> canChangePassword(subject: S, connectedCitizen: CitizenI?): VoterResponse {
|
fun <S : CitizenI> canChangePassword(subject: S, connectedCitizen: CitizenI?): VoterResponse {
|
||||||
if (connectedCitizen == null) return denied("You must be connected to change your password", "citizen.changePassword.notConnected")
|
if (connectedCitizen == null) return denied("You must be connected to change your password", "citizen.changePassword.notConnected")
|
||||||
return if (subject.id == connectedCitizen.id) granted() else denied("You can only change your password", "citizen.password.notYours")
|
return if (subject.id == connectedCitizen.id) granted() else denied("You can only change your password", "citizen.password.notYours")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class CommentForView<T : TargetI, C : CitizenRef>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class CommentForUpdate<T : TargetI, C: CitizenRef>(
|
open class CommentForUpdate<T : TargetI, C : CitizenRef>(
|
||||||
override val id: UUID = UUID.randomUUID(),
|
override val id: UUID = UUID.randomUUID(),
|
||||||
override val createdBy: C,
|
override val createdBy: C,
|
||||||
override val target: T,
|
override val target: T,
|
||||||
@@ -61,14 +61,14 @@ open class CommentForUpdate<T : TargetI, C: CitizenRef>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class CommentParent<T: TargetI>(
|
open class CommentParent<T : TargetI>(
|
||||||
override val id: UUID,
|
override val id: UUID,
|
||||||
override val deletedAt: DateTime?,
|
override val deletedAt: DateTime?,
|
||||||
override val target: T
|
override val target: T
|
||||||
) : CommentRef(id),
|
) : CommentRef(id),
|
||||||
CommentParentI<T>
|
CommentParentI<T>
|
||||||
|
|
||||||
interface CommentParentI<T: TargetI> : CommentI, EntityDeletedAt, CommentWithTargetI<T>
|
interface CommentParentI<T : TargetI> : CommentI, EntityDeletedAt, CommentWithTargetI<T>
|
||||||
|
|
||||||
interface CommentWithTargetI<T : TargetI> : CommentI, TargetI, AsTarget<T>
|
interface CommentWithTargetI<T : TargetI> : CommentI, TargetI, AsTarget<T>
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ abstract class CommentRepositoryAbs<T : TargetI>(override var requester: Request
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <I : T, C: CitizenRef> comment(comment: CommentForUpdate<I, C>) {
|
fun <I : T, C : CitizenRef> comment(comment: CommentForUpdate<I, C>) {
|
||||||
requester
|
requester
|
||||||
.getFunction("comment")
|
.getFunction("comment")
|
||||||
.sendQuery(
|
.sendQuery(
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ class CommentChildrenRequest(
|
|||||||
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
@KtorExperimentalAPI
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.getChildrenComments(repo: CommentRepository) {
|
fun Route.getChildrenComments(repo: CommentRepository) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import io.ktor.util.*
|
|||||||
@Location("/comments/{comment}")
|
@Location("/comments/{comment}")
|
||||||
class CommentRequest(val comment: CommentRef)
|
class CommentRequest(val comment: CommentRef)
|
||||||
|
|
||||||
|
|
||||||
@KtorExperimentalAPI
|
@KtorExperimentalAPI
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.getOneComment(repo: CommentRepository) {
|
fun Route.getOneComment(repo: CommentRepository) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ typealias Opinions = Map<String, Int>
|
|||||||
interface Opinionable {
|
interface Opinionable {
|
||||||
val opinions: Opinions
|
val opinions: Opinions
|
||||||
|
|
||||||
class Imp(parent: fr.dcproject.entity.Opinionable): Opinionable {
|
class Imp(parent: fr.dcproject.entity.Opinionable) : Opinionable {
|
||||||
override val opinions: Opinions = parent.opinions
|
override val opinions: Opinions = parent.opinions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,4 +12,3 @@ interface Versionable {
|
|||||||
override val versionId: UUID = parent.versionId
|
override val versionId: UUID = parent.versionId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package fr.dcproject.dto
|
|||||||
interface Votable {
|
interface Votable {
|
||||||
val votes: VoteAggregation
|
val votes: VoteAggregation
|
||||||
|
|
||||||
class Imp(parent: fr.dcproject.entity.Votable): Votable {
|
class Imp(parent: fr.dcproject.entity.Votable) : Votable {
|
||||||
override val votes: VoteAggregation = VoteAggregation(parent)
|
override val votes: VoteAggregation = VoteAggregation(parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory
|
|||||||
fun waitElasticsearchIsUp(client: RestClient) {
|
fun waitElasticsearchIsUp(client: RestClient) {
|
||||||
val logger: Logger = LoggerFactory.getLogger("fr.dcproject.elasticsearch")
|
val logger: Logger = LoggerFactory.getLogger("fr.dcproject.elasticsearch")
|
||||||
val request = Request("GET", "/_cluster/health")
|
val request = Request("GET", "/_cluster/health")
|
||||||
repeat(5*60/2) { // 5 minutes
|
repeat(5*60 / 2) { // 5 minutes
|
||||||
runCatching {
|
runCatching {
|
||||||
client.performRequest(request).statusLine.statusCode
|
client.performRequest(request).statusLine.statusCode
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ interface ExtraI<T : TargetI, C : CitizenI> :
|
|||||||
EntityCreatedAt,
|
EntityCreatedAt,
|
||||||
EntityCreatedBy<C>
|
EntityCreatedBy<C>
|
||||||
|
|
||||||
interface AsTarget<T: TargetI> {
|
interface AsTarget<T : TargetI> {
|
||||||
val target: T
|
val target: T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ open class FollowSimple<T : TargetI, C : CitizenI>(
|
|||||||
EntityCreatedAt by EntityCreatedAtImp(),
|
EntityCreatedAt by EntityCreatedAtImp(),
|
||||||
EntityCreatedBy<C> by EntityCreatedByImp(createdBy)
|
EntityCreatedBy<C> by EntityCreatedByImp(createdBy)
|
||||||
|
|
||||||
class FollowForUpdate<T: TargetI, C: CitizenI>(
|
class FollowForUpdate<T : TargetI, C : CitizenI>(
|
||||||
id: UUID = UUID.randomUUID(),
|
id: UUID = UUID.randomUUID(),
|
||||||
override val target: T,
|
override val target: T,
|
||||||
override val createdBy: C
|
override val createdBy: C
|
||||||
@@ -36,4 +36,4 @@ open class FollowRef(
|
|||||||
override val id: UUID
|
override val id: UUID
|
||||||
) : FollowI
|
) : FollowI
|
||||||
|
|
||||||
interface FollowI: UuidEntityI
|
interface FollowI : UuidEntityI
|
||||||
@@ -30,7 +30,7 @@ class OpinionArticle(
|
|||||||
choice: OpinionChoice
|
choice: OpinionChoice
|
||||||
) : Opinion<ArticleRef>(id, createdBy, target, choice)
|
) : Opinion<ArticleRef>(id, createdBy, target, choice)
|
||||||
|
|
||||||
data class OpinionForUpdate<T: TargetI>(
|
data class OpinionForUpdate<T : TargetI>(
|
||||||
override val id: UUID = UUID.randomUUID(),
|
override val id: UUID = UUID.randomUUID(),
|
||||||
val target: T,
|
val target: T,
|
||||||
val choice: OpinionChoice,
|
val choice: OpinionChoice,
|
||||||
@@ -42,4 +42,4 @@ open class OpinionRef(
|
|||||||
override val id: UUID
|
override val id: UUID
|
||||||
) : OpinionI
|
) : OpinionI
|
||||||
|
|
||||||
interface OpinionI: UuidEntityI
|
interface OpinionI : UuidEntityI
|
||||||
@@ -7,11 +7,11 @@ interface VersionableRef {
|
|||||||
val versionId: UUID
|
val versionId: UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
class VersionableRefImp (
|
class VersionableRefImp(
|
||||||
override val versionId: UUID
|
override val versionId: UUID
|
||||||
) : VersionableRef
|
) : VersionableRef
|
||||||
|
|
||||||
interface Versionable: VersionableRef, EntityVersioning<UUID, Int> {
|
interface Versionable : VersionableRef, EntityVersioning<UUID, Int> {
|
||||||
override val versionId: UUID
|
override val versionId: UUID
|
||||||
override val versionNumber: Int
|
override val versionNumber: Int
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ class Vote<T : TargetI>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VoteForUpdate<T: TargetI, C: CitizenI>(
|
class VoteForUpdate<T : TargetI, C : CitizenI>(
|
||||||
override val id: UUID = UUID.randomUUID(),
|
override val id: UUID = UUID.randomUUID(),
|
||||||
override val note: Int,
|
override val note: Int,
|
||||||
override val target: T,
|
override val target: T,
|
||||||
@@ -33,14 +33,13 @@ class VoteForUpdate<T: TargetI, C: CitizenI>(
|
|||||||
VoteForUpdateI<T, C>,
|
VoteForUpdateI<T, C>,
|
||||||
EntityCreatedBy<C> by EntityCreatedByImp<C>(createdBy)
|
EntityCreatedBy<C> by EntityCreatedByImp<C>(createdBy)
|
||||||
|
|
||||||
interface VoteForUpdateI<T: TargetI, C: CitizenI> : VoteI, AsTarget<T>, EntityCreatedBy<C> {
|
interface VoteForUpdateI<T : TargetI, C : CitizenI> : VoteI, AsTarget<T>, EntityCreatedBy<C> {
|
||||||
override val id: UUID
|
override val id: UUID
|
||||||
val note: Int
|
val note: Int
|
||||||
override val target: T
|
override val target: T
|
||||||
override val createdBy: C
|
override val createdBy: C
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class VoteRef(
|
open class VoteRef(
|
||||||
override val id: UUID
|
override val id: UUID
|
||||||
) : VoteI
|
) : VoteI
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import fr.postgresjson.entity.EntityI
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Deprecated("")
|
@Deprecated("")
|
||||||
data class Workgroup <C: CitizenBasicI>(
|
data class Workgroup <C : CitizenBasicI>(
|
||||||
override val id: UUID = UUID.randomUUID(),
|
override val id: UUID = UUID.randomUUID(),
|
||||||
override var name: String,
|
override var name: String,
|
||||||
override var description: String,
|
override var description: String,
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ class Workgroup(override var requester: Requester) : RepositoryI {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <C: CitizenI, W: WorkgroupSimple<C>> upsert(workgroup: W): WorkgroupEntity<CitizenBasic> = requester
|
fun <C : CitizenI, W : WorkgroupSimple<C>> upsert(workgroup: W): WorkgroupEntity<CitizenBasic> = requester
|
||||||
.getFunction("upsert_workgroup")
|
.getFunction("upsert_workgroup")
|
||||||
.selectOne("resource" to workgroup) ?: error("query 'upsert_workgroup' return null")
|
.selectOne("resource" to workgroup) ?: error("query 'upsert_workgroup' return null")
|
||||||
|
|
||||||
fun <W: WorkgroupRef> delete(workgroup: W) = requester
|
fun <W : WorkgroupRef> delete(workgroup: W) = requester
|
||||||
.getFunction("delete_workgroup")
|
.getFunction("delete_workgroup")
|
||||||
.perform("id" to workgroup.id)
|
.perform("id" to workgroup.id)
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ class ConstitutionVoter : Voter<ApplicationCall> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
||||||
if(!((action is Action || action is CommentVoter.Action || action is VoteVoter.Action)
|
if (!((action is Action || action is CommentVoter.Action || action is VoteVoter.Action) &&
|
||||||
&& (subject is ConstitutionSimple<*, *>? || subject is VoteEntity<*> || subject is CommentForView<*, *>))) return abstain()
|
(subject is ConstitutionSimple<*, *>? || subject is VoteEntity<*> || subject is CommentForView<*, *>))) return abstain()
|
||||||
|
|
||||||
val user = context.user
|
val user = context.user
|
||||||
if (action == Action.CREATE && user != null) {
|
if (action == Action.CREATE && user != null) {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ class OpinionChoiceVoter : Voter<ApplicationCall> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
||||||
if (!((action is Action)
|
if (!((action is Action) &&
|
||||||
&& (subject is OpinionChoice?))) return abstain()
|
(subject is OpinionChoice?))) return abstain()
|
||||||
|
|
||||||
if (action == Action.VIEW) {
|
if (action == Action.VIEW) {
|
||||||
if (subject is OpinionChoice) {
|
if (subject is OpinionChoice) {
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class OpinionVoter : Voter<ApplicationCall> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
||||||
if (!((action is Action)
|
if (!((action is Action) &&
|
||||||
&& (subject is Opinion<*>? || subject is ArticleAuthI<*>))) return abstain()
|
(subject is Opinion<*>? || subject is ArticleAuthI<*>))) return abstain()
|
||||||
|
|
||||||
val user = context.user
|
val user = context.user
|
||||||
if (action == Action.CREATE) {
|
if (action == Action.CREATE) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class VoteVoter : Voter<ApplicationCall> {
|
|||||||
subject.target.let {
|
subject.target.let {
|
||||||
if (it is EntityDeletedAt) {
|
if (it is EntityDeletedAt) {
|
||||||
if (it.isDeleted()) return denied("You cannot vote on deleted target", "vote.create.isDeleted")
|
if (it.isDeleted()) return denied("You cannot vote on deleted target", "vote.create.isDeleted")
|
||||||
} else {
|
} else {
|
||||||
throw NoSubjectDefinedException(action)
|
throw NoSubjectDefinedException(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ abstract class Voter {
|
|||||||
|
|
||||||
private fun VoterResponses.getOneResponse(): VoterResponse = this.firstOrNull { it.vote == Vote.DENIED } ?: granted()
|
private fun VoterResponses.getOneResponse(): VoterResponse = this.firstOrNull { it.vote == Vote.DENIED } ?: granted()
|
||||||
|
|
||||||
protected fun <S: List<T>, T> canAll(items: S, action: (T) -> VoterResponse): VoterResponse = items
|
protected fun <S : List<T>, T> canAll(items: S, action: (T) -> VoterResponse): VoterResponse = items
|
||||||
.map { action(it) }
|
.map { action(it) }
|
||||||
.getOneResponse()
|
.getOneResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T: Voter> T.assert(action: T.() -> VoterResponse) {
|
fun <T : Voter> T.assert(action: T.() -> VoterResponse) {
|
||||||
action().assert()
|
action().assert()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ class VoterDeniedException(private val voterResponses: VoterResponses) : Throwab
|
|||||||
.message
|
.message
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class VoterResponse (
|
sealed class VoterResponse(
|
||||||
val vote: Vote,
|
val vote: Vote,
|
||||||
val voter: Voter,
|
val voter: Voter,
|
||||||
val message: String?,
|
val message: String?,
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ class WorkgroupVoter : Voter<ApplicationCall> {
|
|||||||
|
|
||||||
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
||||||
if ((action is Action && subject == null)) throw NoSubjectDefinedException(action)
|
if ((action is Action && subject == null)) throw NoSubjectDefinedException(action)
|
||||||
if (!((action is Action || action is ActionMembers)
|
if (!((action is Action || action is ActionMembers) &&
|
||||||
&& (subject is WorkgroupI? || (subject is List<*> && subject.first() is WorkgroupI)))) return abstain()
|
(subject is WorkgroupI? || (subject is List<*> && subject.first() is WorkgroupI)))) return abstain()
|
||||||
|
|
||||||
val user = context.user
|
val user = context.user
|
||||||
if (action == Action.CREATE) {
|
if (action == Action.CREATE) {
|
||||||
@@ -38,7 +38,6 @@ class WorkgroupVoter : Voter<ApplicationCall> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (action == Action.VIEW) {
|
if (action == Action.VIEW) {
|
||||||
if (subject is WorkgroupWithAuthI<*>) {
|
if (subject is WorkgroupWithAuthI<*>) {
|
||||||
return if (subject.isDeleted()) denied("You cannot view a deleted workgroup", "workgroup.view.deleted")
|
return if (subject.isDeleted()) denied("You cannot view a deleted workgroup", "workgroup.view.deleted")
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ class ArticleVoterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `can update article if yours`(): Unit {
|
fun `can update article if yours`() {
|
||||||
val article = getArticle(tesla)
|
val article = getArticle(tesla)
|
||||||
ArticleVoter(getRepo(article))
|
ArticleVoter(getRepo(article))
|
||||||
.canUpsert(article, tesla)
|
.canUpsert(article, tesla)
|
||||||
@@ -142,7 +142,7 @@ class ArticleVoterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `can not update article if not yours`(): Unit {
|
fun `can not update article if not yours`() {
|
||||||
val article = getArticle(tesla)
|
val article = getArticle(tesla)
|
||||||
ArticleVoter(getRepo(article))
|
ArticleVoter(getRepo(article))
|
||||||
.canUpsert(article, einstein)
|
.canUpsert(article, einstein)
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ internal class CommentVoterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `can be view the comment`(): Unit {
|
fun `can be view the comment`() {
|
||||||
listOf(CommentVoter()).run {
|
listOf(CommentVoter()).run {
|
||||||
mockk<ApplicationCall> {
|
mockk<ApplicationCall> {
|
||||||
every { citizenOrNull } returns tesla
|
every { citizenOrNull } returns tesla
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ internal class VoteVoterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `can be vote an article`(): Unit {
|
fun `can be vote an article`() {
|
||||||
listOf(VoteVoter()).run {
|
listOf(VoteVoter()).run {
|
||||||
mockk<ApplicationCall> {
|
mockk<ApplicationCall> {
|
||||||
every { citizenOrNull } returns tesla
|
every { citizenOrNull } returns tesla
|
||||||
|
|||||||
Reference in New Issue
Block a user