Refactoring of OpinionChoiceVoter
This commit is contained in:
@@ -41,9 +41,7 @@ import fr.dcproject.component.workgroup.routes.members.UpdateMemberOfWorkgroup.u
|
|||||||
import fr.dcproject.event.EventNotification
|
import fr.dcproject.event.EventNotification
|
||||||
import fr.dcproject.event.EventSubscriber
|
import fr.dcproject.event.EventSubscriber
|
||||||
import fr.dcproject.routes.*
|
import fr.dcproject.routes.*
|
||||||
import fr.dcproject.security.voter.OpinionChoiceVoter
|
import fr.dcproject.voter.VoterDeniedException
|
||||||
import fr.ktorVoter.AuthorizationVoter
|
|
||||||
import fr.ktorVoter.VoterException
|
|
||||||
import fr.postgresjson.migration.Migrations
|
import fr.postgresjson.migration.Migrations
|
||||||
import io.ktor.application.*
|
import io.ktor.application.*
|
||||||
import io.ktor.auth.*
|
import io.ktor.auth.*
|
||||||
@@ -89,12 +87,6 @@ fun Application.module(env: Env = PROD) {
|
|||||||
|
|
||||||
install(Locations)
|
install(Locations)
|
||||||
|
|
||||||
install(AuthorizationVoter) {
|
|
||||||
voters = listOf(
|
|
||||||
OpinionChoiceVoter()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpClient(Jetty) {
|
HttpClient(Jetty) {
|
||||||
engine {
|
engine {
|
||||||
}
|
}
|
||||||
@@ -176,7 +168,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
voteArticle(get(), get(), get(), get())
|
voteArticle(get(), get(), get(), get())
|
||||||
voteConstitution(get(), get())
|
voteConstitution(get(), get())
|
||||||
opinionArticle(get(), get())
|
opinionArticle(get(), get())
|
||||||
opinionChoice(get())
|
opinionChoice(get(), get())
|
||||||
definition()
|
definition()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +190,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
exception<NotFoundException> { e ->
|
exception<NotFoundException> { e ->
|
||||||
call.respond(HttpStatusCode.NotFound, e.message!!)
|
call.respond(HttpStatusCode.NotFound, e.message!!)
|
||||||
}
|
}
|
||||||
exception<VoterException> {
|
exception<VoterDeniedException> {
|
||||||
if (call.user == null) call.respond(HttpStatusCode.Unauthorized)
|
if (call.user == null) call.respond(HttpStatusCode.Unauthorized)
|
||||||
else call.respond(HttpStatusCode.Forbidden)
|
else call.respond(HttpStatusCode.Forbidden)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ import fr.dcproject.event.publisher.Publisher
|
|||||||
import fr.dcproject.messages.Mailer
|
import fr.dcproject.messages.Mailer
|
||||||
import fr.dcproject.messages.NotificationEmailSender
|
import fr.dcproject.messages.NotificationEmailSender
|
||||||
import fr.dcproject.repository.CommentConstitutionRepository
|
import fr.dcproject.repository.CommentConstitutionRepository
|
||||||
import fr.dcproject.security.voter.ConstitutionVoter
|
import fr.dcproject.security.voter.*
|
||||||
import fr.dcproject.security.voter.FollowVoter
|
|
||||||
import fr.dcproject.security.voter.OpinionVoter
|
|
||||||
import fr.dcproject.security.voter.VoteVoter
|
|
||||||
import fr.postgresjson.connexion.Connection
|
import fr.postgresjson.connexion.Connection
|
||||||
import fr.postgresjson.connexion.Requester
|
import fr.postgresjson.connexion.Requester
|
||||||
import fr.postgresjson.migration.Migrations
|
import fr.postgresjson.migration.Migrations
|
||||||
@@ -131,6 +128,7 @@ val KoinModule = module {
|
|||||||
single { VoteVoter() }
|
single { VoteVoter() }
|
||||||
single { FollowVoter() }
|
single { FollowVoter() }
|
||||||
single { OpinionVoter() }
|
single { OpinionVoter() }
|
||||||
|
single { OpinionChoiceVoter() }
|
||||||
|
|
||||||
// Elasticsearch Client
|
// Elasticsearch Client
|
||||||
single<RestClient> {
|
single<RestClient> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package fr.dcproject.routes
|
package fr.dcproject.routes
|
||||||
|
|
||||||
|
import fr.dcproject.component.auth.citizenOrNull
|
||||||
import fr.dcproject.entity.OpinionChoice
|
import fr.dcproject.entity.OpinionChoice
|
||||||
import fr.dcproject.security.voter.OpinionChoiceVoter.Action.VIEW
|
import fr.dcproject.security.voter.OpinionChoiceVoter
|
||||||
import fr.ktorVoter.assertCan
|
import fr.dcproject.voter.assert
|
||||||
import fr.ktorVoter.assertCanAll
|
|
||||||
import io.ktor.application.*
|
import io.ktor.application.*
|
||||||
import io.ktor.locations.*
|
import io.ktor.locations.*
|
||||||
import io.ktor.response.*
|
import io.ktor.response.*
|
||||||
@@ -20,17 +20,17 @@ object OpinionChoicePaths {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@KtorExperimentalLocationsAPI
|
@KtorExperimentalLocationsAPI
|
||||||
fun Route.opinionChoice(repo: OpinionChoiceRepository) {
|
fun Route.opinionChoice(repo: OpinionChoiceRepository, voter: OpinionChoiceVoter) {
|
||||||
get<OpinionChoicePaths.OpinionChoiceRequest> {
|
get<OpinionChoicePaths.OpinionChoiceRequest> {
|
||||||
assertCan(VIEW, it.opinionChoice)
|
voter.assert { canView(it.opinionChoice, citizenOrNull) }
|
||||||
|
|
||||||
call.respond(it.opinionChoice)
|
call.respond(it.opinionChoice)
|
||||||
}
|
}
|
||||||
|
|
||||||
get<OpinionChoicePaths.OpinionChoicesRequest> {
|
get<OpinionChoicePaths.OpinionChoicesRequest> {
|
||||||
val opinions = repo.findOpinionsChoices(it.targets)
|
val opinionChoices = repo.findOpinionsChoices(it.targets)
|
||||||
assertCanAll(VIEW, opinions)
|
voter.assert { canView(opinionChoices, citizenOrNull) }
|
||||||
|
|
||||||
call.respond(opinions)
|
call.respond(opinionChoices)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,26 +1,15 @@
|
|||||||
package fr.dcproject.security.voter
|
package fr.dcproject.security.voter
|
||||||
|
|
||||||
|
import fr.dcproject.component.citizen.CitizenI
|
||||||
import fr.dcproject.entity.OpinionChoice
|
import fr.dcproject.entity.OpinionChoice
|
||||||
import fr.dcproject.voter.NoSubjectDefinedException
|
import fr.dcproject.voter.Voter
|
||||||
import fr.ktorVoter.*
|
import fr.dcproject.voter.VoterResponse
|
||||||
import io.ktor.application.*
|
|
||||||
|
|
||||||
class OpinionChoiceVoter : Voter<ApplicationCall> {
|
class OpinionChoiceVoter : Voter() {
|
||||||
enum class Action : ActionI {
|
fun canView(subjects: List<OpinionChoice>, citizen: CitizenI?): VoterResponse =
|
||||||
VIEW
|
canAll(subjects) { canView(it, citizen) }
|
||||||
}
|
|
||||||
|
|
||||||
override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI {
|
fun canView(subject: OpinionChoice, citizen: CitizenI?): VoterResponse {
|
||||||
if (!((action is Action) &&
|
return granted()
|
||||||
(subject is OpinionChoice?))) return abstain()
|
|
||||||
|
|
||||||
if (action == Action.VIEW) {
|
|
||||||
if (subject is OpinionChoice) {
|
|
||||||
return granted()
|
|
||||||
}
|
|
||||||
throw NoSubjectDefinedException(action)
|
|
||||||
}
|
|
||||||
|
|
||||||
return abstain()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,12 @@ package unit.voter
|
|||||||
import fr.dcproject.component.article.ArticleForView
|
import fr.dcproject.component.article.ArticleForView
|
||||||
import fr.dcproject.component.auth.User
|
import fr.dcproject.component.auth.User
|
||||||
import fr.dcproject.component.auth.UserI
|
import fr.dcproject.component.auth.UserI
|
||||||
import fr.dcproject.component.auth.user
|
|
||||||
import fr.dcproject.component.citizen.CitizenBasic
|
import fr.dcproject.component.citizen.CitizenBasic
|
||||||
import fr.dcproject.component.citizen.CitizenCart
|
import fr.dcproject.component.citizen.CitizenCart
|
||||||
import fr.dcproject.component.citizen.CitizenI
|
import fr.dcproject.component.citizen.CitizenI
|
||||||
import fr.dcproject.entity.OpinionChoice
|
import fr.dcproject.entity.OpinionChoice
|
||||||
import fr.dcproject.security.voter.OpinionChoiceVoter
|
import fr.dcproject.security.voter.OpinionChoiceVoter
|
||||||
import fr.ktorVoter.ActionI
|
import fr.dcproject.voter.Vote.GRANTED
|
||||||
import fr.ktorVoter.Vote
|
|
||||||
import fr.ktorVoter.can
|
|
||||||
import fr.ktorVoter.canAll
|
|
||||||
import io.ktor.application.*
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.mockk
|
|
||||||
import io.mockk.mockkStatic
|
import io.mockk.mockkStatic
|
||||||
import org.amshove.kluent.`should be`
|
import org.amshove.kluent.`should be`
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
@@ -68,32 +61,16 @@ internal class OpinionChoiceVoterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `support opinion choice`(): Unit = OpinionChoiceVoter().run {
|
fun `can be view the opinion choice`() {
|
||||||
val p = object : ActionI {}
|
OpinionChoiceVoter()
|
||||||
mockk<ApplicationCall> {
|
.canView(choice1, tesla)
|
||||||
every { user } returns tesla.user
|
.vote `should be` GRANTED
|
||||||
}.let {
|
|
||||||
this(OpinionChoiceVoter.Action.VIEW, it, choice1).vote `should be` Vote.GRANTED
|
|
||||||
this(OpinionChoiceVoter.Action.VIEW, it, article1).vote `should be` Vote.ABSTAIN
|
|
||||||
this(p, it, choice1).vote `should be` Vote.ABSTAIN
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `can be view the opinion choice`(): Unit = listOf(OpinionChoiceVoter()).run {
|
fun `can be view the opinion choice list`() {
|
||||||
mockk<ApplicationCall> {
|
OpinionChoiceVoter()
|
||||||
every { user } returns tesla.user
|
.canView(listOf(choice1), tesla)
|
||||||
}.let {
|
.vote `should be` GRANTED
|
||||||
can(OpinionChoiceVoter.Action.VIEW, it, choice1) `should be` true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `can be view the opinion choice list`(): Unit = listOf(OpinionChoiceVoter()).run {
|
|
||||||
mockk<ApplicationCall> {
|
|
||||||
every { user } returns tesla.user
|
|
||||||
}.let {
|
|
||||||
canAll(OpinionChoiceVoter.Action.VIEW, it, listOf(choice1)) `should be` true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user