Big refactoring #77

Merged
flecomte merged 166 commits from refactoring-component-and-immutable into master 2021-03-24 19:06:07 +01:00
4 changed files with 33 additions and 66 deletions
Showing only changes of commit 308a284280 - Show all commits

View File

@@ -96,7 +96,6 @@ fun Application.module(env: Env = PROD) {
install(AuthorizationVoter) {
voters = listOf(
ConstitutionVoter(),
VoteVoter(),
FollowVoter(),
OpinionVoter(),
@@ -208,7 +207,7 @@ fun Application.module(env: Env = PROD) {
deleteMemberOfWorkgroup(get(), get())
updateMemberOfWorkgroup(get(), get())
/* TODO */
constitution(get())
constitution(get(), get())
followArticle(get())
followConstitution(get())
commentConstitution(get(), get())

View File

@@ -23,6 +23,7 @@ import fr.dcproject.event.publisher.Publisher
import fr.dcproject.messages.Mailer
import fr.dcproject.messages.NotificationEmailSender
import fr.dcproject.repository.CommentConstitutionRepository
import fr.dcproject.security.voter.ConstitutionVoter
import fr.postgresjson.connexion.Connection
import fr.postgresjson.connexion.Requester
import fr.postgresjson.migration.Migrations
@@ -123,6 +124,7 @@ val KoinModule = module {
single { CitizenVoter() }
single { CommentVoter() }
single { WorkgroupVoter() }
single { ConstitutionVoter() }
// Elasticsearch Client
single<RestClient> {

View File

@@ -2,13 +2,12 @@ package fr.dcproject.routes
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.CitizenWithUserI
import fr.dcproject.entity.ConstitutionSimple
import fr.dcproject.entity.ConstitutionSimple.TitleSimple
import fr.dcproject.security.voter.ConstitutionVoter.Action.CREATE
import fr.dcproject.security.voter.ConstitutionVoter.Action.VIEW
import fr.ktorVoter.assertCan
import fr.ktorVoter.assertCanAll
import fr.dcproject.security.voter.ConstitutionVoter
import fr.dcproject.voter.assert
import fr.postgresjson.entity.UuidEntity
import fr.postgresjson.repository.RepositoryI
import io.ktor.application.*
@@ -82,21 +81,21 @@ object ConstitutionPaths {
}
@KtorExperimentalLocationsAPI
fun Route.constitution(repo: ConstitutionRepository) {
fun Route.constitution(repo: ConstitutionRepository, voter: ConstitutionVoter) {
get<ConstitutionPaths.ConstitutionsRequest> {
val constitutions = repo.find(it.page, it.limit, it.sort, it.direction, it.search)
assertCanAll(VIEW, constitutions.result)
voter.assert { canView(constitutions.result, citizenOrNull) }
call.respond(constitutions)
}
get<ConstitutionPaths.ConstitutionRequest> {
assertCan(VIEW, it.constitution)
voter.assert { canView(it.constitution, citizenOrNull) }
call.respond(it.constitution)
}
post<ConstitutionPaths.PostConstitutionRequest> {
it.getNewConstitution(call).let { constitution ->
assertCan(CREATE, constitution)
voter.assert { canCreate(constitution, citizenOrNull) }
repo.upsert(constitution)
call.respond(constitution)
}

View File

@@ -1,67 +1,34 @@
package fr.dcproject.security.voter
import fr.dcproject.component.auth.UserI
import fr.dcproject.component.auth.user
import fr.dcproject.component.comment.generic.CommentForView
import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.entity.ConstitutionS
import fr.dcproject.entity.ConstitutionSimple
import fr.dcproject.voter.NoRuleDefinedException
import fr.dcproject.voter.NoSubjectDefinedException
import fr.ktorVoter.*
import io.ktor.application.*
import fr.dcproject.entity.Vote as VoteEntity
import fr.dcproject.voter.Voter
import fr.dcproject.voter.VoterResponse
class ConstitutionVoter : Voter<ApplicationCall> {
enum class Action : ActionI {
CREATE,
UPDATE,
VIEW,
DELETE
class ConstitutionVoter : Voter() {
fun canCreate(subject: ConstitutionS, citizen: CitizenI?): VoterResponse = when {
citizen == null -> denied("You must be connected to create constitution", "constitution.create.notConnected")
else -> granted()
}
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
if (!((action is Action || action is VoteVoter.Action) &&
(subject is ConstitutionSimple<*, *>? || subject is VoteEntity<*> || subject is CommentForView<*, *>))) return abstain()
fun <S : ConstitutionSimple<*, *>> canView(subjects: List<S>, citizen: CitizenI?): VoterResponse =
canAll(subjects) { canView(it, citizen) }
val user = context.user
if (action == Action.CREATE && user != null) {
return granted()
}
if (action == Action.VIEW) {
if (subject is ConstitutionSimple<*, *>) {
return if (subject.isDeleted()) denied("You cannot view a deleted constitution", "constitution.view.deleted")
else granted()
}
throw NoSubjectDefinedException(action as ActionI)
}
if (action == Action.DELETE && user is UserI && subject is ConstitutionSimple<*, *> && subject.createdBy.user.id == user.id) {
return granted()
}
if (action == Action.UPDATE && user is UserI && subject is ConstitutionSimple<*, *> && subject.createdBy.user.id == user.id) {
return granted()
}
if (action is VoteVoter.Action) return voteForVote(action, subject)
if (action is Action) {
throw NoRuleDefinedException(action)
}
return abstain()
fun canView(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): VoterResponse = when {
subject.isDeleted() -> denied("You cannot view a deleted constitution", "constitution.view.deleted")
else -> granted()
}
private fun voteForVote(action: VoteVoter.Action, subject: Any?): VoterResponseI {
if (action == VoteVoter.Action.CREATE && subject is VoteEntity<*>) {
val target = subject.target
if (target !is ConstitutionSimple<*, *>) {
return abstain()
}
if (target.isDeleted()) {
return denied("You cannot vote a deleted constitution", "constitution.vote.deleted")
}
}
return abstain()
fun canDelete(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): VoterResponse = when {
citizen == null -> denied("You must be connected to delete constitution", "constitution.delete.notConnected")
subject.createdBy.id != citizen.id -> denied("You cannot delete the constitution of other citizen", "constitution.delete.otherCitizen")
else -> granted()
}
fun canUpdate(subject: ConstitutionSimple<*, *>, citizen: CitizenI?): VoterResponse = when {
citizen == null -> denied("You must be connected to update constitution", "constitution.update.notConnected")
subject.createdBy.id != citizen.id -> denied("You cannot update the constitution of other citizen", "constitution.update.otherCitizen")
else -> granted()
}
}