From c380ba47a52aaba363cfa3162be1ea23e1b2652f Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Sun, 17 Jan 2021 15:01:49 +0100 Subject: [PATCH] Refactoring of WorkgroupVoter --- src/main/kotlin/Application.kt | 20 +- src/main/kotlin/KoinModule.kt | 2 + .../kotlin/component/workgroup/Workgroup.kt | 2 +- .../component/workgroup/WorkgroupVoter.kt | 51 +++++ .../workgroup/routes/CreateWorkgroup.kt | 9 +- .../workgroup/routes/DeleteWorkgroup.kt | 9 +- .../workgroup/routes/EditWorkgroup.kt | 9 +- .../workgroup/routes/GetWorkgroup.kt | 9 +- .../workgroup/routes/GetWorkgroups.kt | 9 +- .../routes/members/AddMemberToWorkgroup.kt | 9 +- .../members/DeleteMembersOfWorkgroup.kt | 9 +- .../routes/members/UpdateMemberOfWorkgroup.kt | 9 +- src/main/kotlin/voter/WorkgroupVoter.kt | 95 --------- .../kotlin/unit/voter/ArticleVoterTest.kt | 5 - .../kotlin/unit/voter/CitizenVoterTest.kt | 5 - .../kotlin/unit/voter/CommentVoterTest.kt | 5 - .../kotlin/unit/voter/WorkgroupVoterTest.kt | 183 +++++------------- 17 files changed, 154 insertions(+), 286 deletions(-) create mode 100644 src/main/kotlin/component/workgroup/WorkgroupVoter.kt delete mode 100644 src/main/kotlin/voter/WorkgroupVoter.kt diff --git a/src/main/kotlin/Application.kt b/src/main/kotlin/Application.kt index 9af5eb4..b94c789 100644 --- a/src/main/kotlin/Application.kt +++ b/src/main/kotlin/Application.kt @@ -28,7 +28,6 @@ import fr.dcproject.component.comment.generic.routes.createCommentChildren import fr.dcproject.component.comment.generic.routes.editComment import fr.dcproject.component.comment.generic.routes.getChildrenComments import fr.dcproject.component.comment.generic.routes.getOneComment -import fr.dcproject.component.workgroup.routes.* import fr.dcproject.component.workgroup.routes.CreateWorkgroup.createWorkgroup import fr.dcproject.component.workgroup.routes.DeleteWorkgroup.deleteWorkgroup import fr.dcproject.component.workgroup.routes.EditWorkgroup.editWorkgroup @@ -97,8 +96,7 @@ fun Application.module(env: Env = PROD) { VoteVoter(), FollowVoter(), OpinionVoter(), - OpinionChoiceVoter(), - WorkgroupVoter() + OpinionChoiceVoter() ) } @@ -196,15 +194,15 @@ fun Application.module(env: Env = PROD) { authRegister(get()) authSso(get()) /* Workgroup */ - getWorkgroups(get()) - getWorkgroup(get()) - createWorkgroup(get()) - editWorkgroup(get()) - deleteWorkgroup(get()) + getWorkgroups(get(), get()) + getWorkgroup(get(), get()) + createWorkgroup(get(), get()) + editWorkgroup(get(), get()) + deleteWorkgroup(get(), get()) /* Workgroup members */ - addMemberToWorkgroup(get()) - deleteMemberOfWorkgroup(get()) - updateMemberOfWorkgroup(get()) + addMemberToWorkgroup(get(), get()) + deleteMemberOfWorkgroup(get(), get()) + updateMemberOfWorkgroup(get(), get()) /* TODO */ constitution(get()) followArticle(get()) diff --git a/src/main/kotlin/KoinModule.kt b/src/main/kotlin/KoinModule.kt index b7c0b83..75c31cd 100644 --- a/src/main/kotlin/KoinModule.kt +++ b/src/main/kotlin/KoinModule.kt @@ -18,6 +18,7 @@ import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.component.comment.article.CommentArticleRepository import fr.dcproject.component.comment.generic.CommentVoter import fr.dcproject.component.workgroup.WorkgroupRepository +import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.event.publisher.Publisher import fr.dcproject.messages.Mailer import fr.dcproject.messages.NotificationEmailSender @@ -121,6 +122,7 @@ val KoinModule = module { single { ArticleVoter(get()) } single { CitizenVoter() } single { CommentVoter() } + single { WorkgroupVoter() } // Elasticsearch Client single { diff --git a/src/main/kotlin/component/workgroup/Workgroup.kt b/src/main/kotlin/component/workgroup/Workgroup.kt index 57b43a9..affc473 100644 --- a/src/main/kotlin/component/workgroup/Workgroup.kt +++ b/src/main/kotlin/component/workgroup/Workgroup.kt @@ -59,7 +59,7 @@ interface WorkgroupWithAuthI : WorkgroupWithMembersI, E val anonymous: Boolean fun isMember(user: UserI): Boolean = members.isMember(user) - fun isMember(citizen: CitizenWithUserI): Boolean = members.isMember(citizen) + fun isMember(citizen: CitizenI): Boolean = members.isMember(citizen) fun hasRole(expectedRole: Role, user: UserI): Boolean = members.hasRole(expectedRole, user) fun hasRole(expectedRole: Role, citizen: CitizenI): Boolean = members.hasRole(expectedRole, citizen) diff --git a/src/main/kotlin/component/workgroup/WorkgroupVoter.kt b/src/main/kotlin/component/workgroup/WorkgroupVoter.kt new file mode 100644 index 0000000..6d0419c --- /dev/null +++ b/src/main/kotlin/component/workgroup/WorkgroupVoter.kt @@ -0,0 +1,51 @@ +package fr.dcproject.component.workgroup + +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member.Role +import fr.dcproject.voter.Voter +import fr.dcproject.voter.VoterResponse + +class WorkgroupVoter : Voter() { + fun canCreate(subject: WorkgroupI, citizen: CitizenI?): VoterResponse { + if (citizen == null) return denied("You must be connected to create workgroup", "workgroup.create.notConnected") + return granted() + } + + fun > canView(subjects: List, citizen: CitizenI?): VoterResponse = + canAll(subjects) { canView(it, citizen) } + + fun canView(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = + if (subject.isDeleted()) denied("You cannot view a deleted workgroup", "workgroup.view.deleted") + else if (!subject.anonymous) granted() + else if (subject.anonymous && citizen != null && subject.isMember(citizen)) granted() + else denied("You cannot view anonymous workgroup", "workgroup.view.anonymous") + + fun canDelete(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse { + if (citizen == null) return denied("You must be connected to delete workgroup", "workgroup.delete.notConnected") + return if (subject.hasRole(Role.MASTER, citizen)) granted() + else denied("You must hase role MASTER to delete workgroup", "workgroup.delete.role") + } + fun canUpdate(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse { + if (citizen == null) return denied("You must be connected to update workgroup", "workgroup.update.notConnected") + return if (subject.hasRole(Role.MASTER, citizen)) granted() + else denied("You must hase role MASTER to delete workgroup", "workgroup.delete.role") + } + + fun canAddMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = when { + citizen == null -> denied("You must be connected to add member to the workgroup", "workgroup.addMember.notConnected") + subject.hasRole(Role.MASTER, citizen) -> granted() + else -> denied("You must have MASTER Role for add member to workgroup", "workgroup.addMember.role") + } + + fun canUpdateMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = when { + citizen == null -> denied("You must be connected to update member of the workgroup", "workgroup.updateMember.notConnected") + subject.hasRole(Role.MASTER, citizen) -> granted() + else -> denied("You must have MASTER Role for update members of workgroup", "workgroup.updateMember.role") + } + + fun canRemoveMembers(subject: WorkgroupWithAuthI<*>, citizen: CitizenI?): VoterResponse = when { + citizen == null -> denied("You must be connected to remove member of the workgroup", "workgroup.removeMember.notConnected") + subject.hasRole(Role.MASTER, citizen) -> granted() + else -> denied("You must have MASTER Role for remove members of workgroup", "workgroup.removeMember.role") + } +} diff --git a/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt index 2044998..2ba5d23 100644 --- a/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/CreateWorkgroup.kt @@ -1,11 +1,12 @@ package fr.dcproject.component.workgroup.routes import fr.dcproject.citizen +import fr.dcproject.citizenOrNull import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupSimple import fr.dcproject.component.workgroup.routes.CreateWorkgroup.PostWorkgroupRequest.Input -import fr.dcproject.security.voter.WorkgroupVoter -import fr.ktorVoter.assertCan +import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.voter.assert import io.ktor.application.* import io.ktor.http.* import io.ktor.locations.* @@ -27,7 +28,7 @@ object CreateWorkgroup { ) } - fun Route.createWorkgroup(repo: WorkgroupRepository) { + fun Route.createWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { post { call.receive().run { WorkgroupSimple( @@ -39,7 +40,7 @@ object CreateWorkgroup { citizen ) }.let { workgroup -> - assertCan(WorkgroupVoter.Action.CREATE, workgroup) + voter.assert { canCreate(workgroup, citizenOrNull) } repo.upsert(workgroup) }.let { call.respond(HttpStatusCode.Created, it) diff --git a/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt index 653055a..d584993 100644 --- a/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/DeleteWorkgroup.kt @@ -1,8 +1,9 @@ package fr.dcproject.component.workgroup.routes +import fr.dcproject.citizenOrNull import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.security.voter.WorkgroupVoter -import fr.ktorVoter.assertCan +import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.voter.assert import io.ktor.application.* import io.ktor.http.* import io.ktor.locations.* @@ -15,10 +16,10 @@ object DeleteWorkgroup { @Location("/workgroups/{workgroupId}") class DeleteWorkgroupRequest(val workgroupId: UUID) - fun Route.deleteWorkgroup(repo: WorkgroupRepository) { + fun Route.deleteWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { delete { repo.findById(it.workgroupId)?.let { workgroup -> - assertCan(WorkgroupVoter.Action.DELETE, workgroup) + voter.assert { canDelete(workgroup, citizenOrNull) } repo.delete(workgroup) call.respond(HttpStatusCode.NoContent) } ?: call.respond(HttpStatusCode.NotFound) diff --git a/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt index 17da336..486c102 100644 --- a/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/EditWorkgroup.kt @@ -1,9 +1,10 @@ package fr.dcproject.component.workgroup.routes +import fr.dcproject.citizenOrNull import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.routes.EditWorkgroup.PutWorkgroupRequest.Input -import fr.dcproject.security.voter.WorkgroupVoter -import fr.ktorVoter.assertCan +import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.voter.assert import io.ktor.application.* import io.ktor.http.* import io.ktor.locations.* @@ -25,7 +26,7 @@ object EditWorkgroup { ) } - fun Route.editWorkgroup(repo: WorkgroupRepository) { + fun Route.editWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { put { repo.findById(it.workgroupId)?.let { old -> call.receive().run { @@ -35,7 +36,7 @@ object EditWorkgroup { logo = logo ?: old.logo, anonymous = anonymous ?: old.anonymous ).let { workgroup -> - assertCan(WorkgroupVoter.Action.UPDATE, workgroup) + voter.assert { canUpdate(workgroup, citizenOrNull) } repo.upsert(workgroup) call.respond(HttpStatusCode.OK, it) } diff --git a/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt index 9252784..720274d 100644 --- a/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/GetWorkgroup.kt @@ -1,8 +1,9 @@ package fr.dcproject.component.workgroup.routes +import fr.dcproject.citizenOrNull import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.security.voter.WorkgroupVoter -import fr.ktorVoter.assertCan +import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.voter.assert import io.ktor.application.* import io.ktor.http.* import io.ktor.locations.* @@ -15,10 +16,10 @@ object GetWorkgroup { @Location("/workgroups/{workgroupId}") class WorkgroupRequest(val workgroupId: UUID) - fun Route.getWorkgroup(repo: WorkgroupRepository) { + fun Route.getWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { get { repo.findById(it.workgroupId)?.let { workgroup -> - assertCan(WorkgroupVoter.Action.VIEW, workgroup) + voter.assert { canView(workgroup, citizenOrNull) } call.respond(workgroup) } ?: call.respond(HttpStatusCode.NotFound) } diff --git a/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt b/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt index 474b252..2951a02 100644 --- a/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt +++ b/src/main/kotlin/component/workgroup/routes/GetWorkgroups.kt @@ -1,9 +1,10 @@ package fr.dcproject.component.workgroup.routes +import fr.dcproject.citizenOrNull import fr.dcproject.component.workgroup.WorkgroupRepository -import fr.dcproject.security.voter.WorkgroupVoter +import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.utils.toUUID -import fr.ktorVoter.assertCanAll +import fr.dcproject.voter.assert import fr.postgresjson.repository.RepositoryI import io.ktor.application.* import io.ktor.locations.* @@ -28,13 +29,13 @@ object GetWorkgroups { val members: List? = members?.toUUID() } - fun Route.getWorkgroups(repo: WorkgroupRepository) { + fun Route.getWorkgroups(repo: WorkgroupRepository, voter: WorkgroupVoter) { get { val workgroups = repo.find(it.page, it.limit, it.sort, it.direction, it.search, WorkgroupRepository.Filter(createdById = it.createdBy, members = it.members) ) - assertCanAll(WorkgroupVoter.Action.VIEW, workgroups.result) + voter.assert { canView(workgroups.result, citizenOrNull) } call.respond(workgroups) } } diff --git a/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt index a727804..2b147c7 100644 --- a/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/members/AddMemberToWorkgroup.kt @@ -1,10 +1,11 @@ package fr.dcproject.component.workgroup.routes.members +import fr.dcproject.citizenOrNull import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.security.voter.WorkgroupVoter -import fr.ktorVoter.assertCan +import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.voter.assert import io.ktor.application.* import io.ktor.http.* import io.ktor.locations.* @@ -36,12 +37,12 @@ object AddMemberToWorkgroup { } @KtorExperimentalLocationsAPI - fun Route.addMemberToWorkgroup(repo: WorkgroupRepository) { + fun Route.addMemberToWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { /* Add members to workgroup */ post { repo.findById(it.workgroupId)?.let { workgroup -> call.getMembersFromRequest().let { members -> - assertCan(WorkgroupVoter.ActionMembers.ADD, workgroup) + voter.assert { canAddMembers(workgroup, citizenOrNull) } repo.addMembers(workgroup, members) }.let { members -> call.respond(HttpStatusCode.Created, members) diff --git a/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt index 417b2f7..dcf1b20 100644 --- a/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/members/DeleteMembersOfWorkgroup.kt @@ -1,10 +1,11 @@ package fr.dcproject.component.workgroup.routes.members +import fr.dcproject.citizenOrNull import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.security.voter.WorkgroupVoter -import fr.ktorVoter.assertCan +import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.voter.assert import io.ktor.application.* import io.ktor.http.* import io.ktor.locations.* @@ -34,12 +35,12 @@ object DeleteMembersOfWorkgroup { ) } - fun Route.deleteMemberOfWorkgroup(repo: WorkgroupRepository) { + fun Route.deleteMemberOfWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { /* Delete members of workgroup */ delete { repo.findById(it.workgroupId)?.let { workgroup -> call.getMembersFromRequest().let { members -> - assertCan(WorkgroupVoter.ActionMembers.REMOVE, workgroup) + voter.assert { canView(workgroup, citizenOrNull) } repo.removeMembers(workgroup, members) }.let { members -> call.respond(HttpStatusCode.OK, members) diff --git a/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt b/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt index 5629612..bf78cb2 100644 --- a/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt +++ b/src/main/kotlin/component/workgroup/routes/members/UpdateMemberOfWorkgroup.kt @@ -1,10 +1,11 @@ package fr.dcproject.component.workgroup.routes.members +import fr.dcproject.citizenOrNull import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.security.voter.WorkgroupVoter -import fr.ktorVoter.assertCan +import fr.dcproject.component.workgroup.WorkgroupVoter +import fr.dcproject.voter.assert import io.ktor.application.* import io.ktor.http.* import io.ktor.locations.* @@ -34,12 +35,12 @@ object UpdateMemberOfWorkgroup { ) } - fun Route.updateMemberOfWorkgroup(repo: WorkgroupRepository) { + fun Route.updateMemberOfWorkgroup(repo: WorkgroupRepository, voter: WorkgroupVoter) { /* Update members of workgroup */ put { repo.findById(it.workgroupId)?.let { workgroup -> call.getMembersFromRequest().let { members -> - assertCan(WorkgroupVoter.ActionMembers.UPDATE, workgroup) + voter.assert { canUpdateMembers(workgroup, citizenOrNull) } repo.updateMembers(workgroup, members) }.let { members -> call.respond(HttpStatusCode.OK, members) diff --git a/src/main/kotlin/voter/WorkgroupVoter.kt b/src/main/kotlin/voter/WorkgroupVoter.kt deleted file mode 100644 index f213770..0000000 --- a/src/main/kotlin/voter/WorkgroupVoter.kt +++ /dev/null @@ -1,95 +0,0 @@ -package fr.dcproject.security.voter - -import fr.dcproject.component.auth.UserI -import fr.dcproject.component.workgroup.WorkgroupI -import fr.dcproject.component.workgroup.WorkgroupWithAuthI -import fr.dcproject.component.workgroup.WorkgroupWithMembersI.Member.Role -import fr.dcproject.user -import fr.dcproject.voter.NoRuleDefinedException -import fr.dcproject.voter.NoSubjectDefinedException -import fr.ktorVoter.* -import io.ktor.application.* - -class WorkgroupVoter : Voter { - enum class Action : ActionI { - CREATE, - UPDATE, - VIEW, - DELETE, - } - - enum class ActionMembers : ActionI { - ADD, - UPDATE, - VIEW, - REMOVE, - } - - override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI { - if ((action is Action && subject == null)) throw NoSubjectDefinedException(action) - if (!((action is Action || action is ActionMembers) && - (subject is WorkgroupI? || (subject is List<*> && subject.first() is WorkgroupI)))) return abstain() - - val user = context.user - if (action == Action.CREATE) { - if (user == null) return denied("You must be connected to delete workgroup", "workgroup.delete.notConnected") - if (subject is WorkgroupI) { - return granted() - } - } - - if (action == Action.VIEW) { - if (subject is WorkgroupWithAuthI<*>) { - return if (subject.isDeleted()) denied("You cannot view a deleted workgroup", "workgroup.view.deleted") - else if (!subject.anonymous) granted() - else if (subject.anonymous && user != null && subject.isMember(user)) granted() - else denied("You cannot view anonymous workgroup", "workgroup.view.anonymous") - } - throw NoSubjectDefinedException(action as ActionI) - } - - if (subject is WorkgroupWithAuthI<*> && (action == Action.DELETE || action == Action.UPDATE)) { - if (action == Action.DELETE) { - if (user == null) return denied("You must be connected to delete workgroup", "workgroup.delete.notConnected") - return if (subject.hasRole(Role.MASTER, user)) granted() - else denied("You must hase role MASTER to delete workgroup", "workgroup.delete.role") - } - if (action == Action.UPDATE) { - if (user == null) return denied("You must be connected to delete workgroup", "workgroup.delete.notConnected") - return if (subject.hasRole(Role.MASTER, user)) granted() - else denied("You must hase role MASTER to delete workgroup", "workgroup.delete.role") - } - - throw NoRuleDefinedException(action as ActionI) - } else if (subject !is WorkgroupWithAuthI<*> && (action == Action.DELETE || action == Action.UPDATE)) { - throw NoSubjectDefinedException(action as ActionI) - } - - if (action == ActionMembers.ADD) { - // TODO create ROLES - if (user !is UserI) return denied("You must be connected to add member to the workgroup", "workgroup.addMember.notConnected") - if (subject !is WorkgroupWithAuthI<*>) throw NoSubjectDefinedException(action as ActionI) - return if (subject.hasRole(Role.MASTER, user)) granted() else denied("You must have MASTER Role for add member to workgroup", "workgroup.addMember.role") - } - - if (action == ActionMembers.UPDATE) { - // TODO create ROLES - if (user !is UserI) return denied("You must be connected to update member of the workgroup", "workgroup.updateMember.notConnected") - if (subject !is WorkgroupWithAuthI<*>) throw NoSubjectDefinedException(action as ActionI) - return if (subject.hasRole(Role.MASTER, user)) granted() else denied("You must have MASTER Role for update members of workgroup", "workgroup.updateMember.role") - } - - if (action == ActionMembers.REMOVE) { - // TODO create ROLES - if (user !is UserI) return denied("You must be connected to remove member of the workgroup", "workgroup.removeMember.notConnected") - if (subject !is WorkgroupWithAuthI<*>) throw NoSubjectDefinedException(action as ActionI) - return if (subject.hasRole(Role.MASTER, user)) granted() else denied("You must have MASTER Role for remove members of workgroup", "workgroup.removeMember.role") - } - - if (action is Action) { - throw NoRuleDefinedException(action) - } - - return abstain() - } -} diff --git a/src/test/kotlin/unit/voter/ArticleVoterTest.kt b/src/test/kotlin/unit/voter/ArticleVoterTest.kt index 16b6b4a..b96e30a 100644 --- a/src/test/kotlin/unit/voter/ArticleVoterTest.kt +++ b/src/test/kotlin/unit/voter/ArticleVoterTest.kt @@ -11,7 +11,6 @@ import fr.dcproject.voter.Vote.GRANTED import fr.postgresjson.connexion.Paginated import io.mockk.every import io.mockk.mockk -import io.mockk.mockkStatic import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -48,10 +47,6 @@ internal class ArticleVoterTest { } } - init { - mockkStatic("fr.dcproject.ApplicationContextKt") - } - @Test fun `creator can be view the article`() { val article = getArticle(tesla).copy(draft = true) diff --git a/src/test/kotlin/unit/voter/CitizenVoterTest.kt b/src/test/kotlin/unit/voter/CitizenVoterTest.kt index 0f939de..d7afe88 100644 --- a/src/test/kotlin/unit/voter/CitizenVoterTest.kt +++ b/src/test/kotlin/unit/voter/CitizenVoterTest.kt @@ -7,7 +7,6 @@ import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.voter.Vote.DENIED import fr.dcproject.voter.Vote.GRANTED -import io.mockk.mockkStatic import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -50,10 +49,6 @@ internal class CitizenVoterTest { deletedAt = DateTime.now() ) - init { - mockkStatic("fr.dcproject.ApplicationContextKt") - } - @Test fun `can be view the citizen`() { CitizenVoter() diff --git a/src/test/kotlin/unit/voter/CommentVoterTest.kt b/src/test/kotlin/unit/voter/CommentVoterTest.kt index 0617a38..c6d7e5e 100644 --- a/src/test/kotlin/unit/voter/CommentVoterTest.kt +++ b/src/test/kotlin/unit/voter/CommentVoterTest.kt @@ -15,7 +15,6 @@ import fr.dcproject.voter.Vote.GRANTED import fr.postgresjson.connexion.Paginated import io.mockk.every import io.mockk.mockk -import io.mockk.mockkStatic import org.amshove.kluent.`should be` import org.joda.time.DateTime import org.junit.jupiter.api.Tag @@ -106,10 +105,6 @@ internal class CommentVoterTest { every { findVersionsByVersionId(1, 1, any()) } returns Paginated(listOf(article1), 0, 1, 1) } - init { - mockkStatic("fr.dcproject.ApplicationContextKt") - } - @Test fun `can be view the comment`() { CommentVoter() diff --git a/src/test/kotlin/unit/voter/WorkgroupVoterTest.kt b/src/test/kotlin/unit/voter/WorkgroupVoterTest.kt index 6c45cae..9579799 100644 --- a/src/test/kotlin/unit/voter/WorkgroupVoterTest.kt +++ b/src/test/kotlin/unit/voter/WorkgroupVoterTest.kt @@ -1,27 +1,19 @@ package unit.voter -import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.auth.User import fr.dcproject.component.auth.UserI import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.component.workgroup.WorkgroupRef +import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.component.workgroup.WorkgroupWithMembersI -import fr.dcproject.security.voter.WorkgroupVoter -import fr.dcproject.user -import fr.dcproject.voter.NoSubjectDefinedException -import fr.ktorVoter.ActionI -import fr.ktorVoter.Vote -import fr.ktorVoter.VoterException -import fr.ktorVoter.can -import io.ktor.application.* -import io.mockk.every -import io.mockk.mockk -import io.mockk.mockkStatic +import fr.dcproject.voter.Vote.DENIED +import fr.dcproject.voter.Vote.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime -import org.junit.jupiter.api.* +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT import java.util.* @@ -63,13 +55,6 @@ internal class WorkgroupVoterTest { name = CitizenI.Name("Albert", "Einstein") ) - private val article1 = ArticleForView( - content = "Hi", - createdBy = einstein2, - description = "blablabla", - title = "Super article" - ) - private val workgroupPublic = WorkgroupEntity( createdBy = tesla, description = "Super desc", @@ -86,146 +71,80 @@ internal class WorkgroupVoterTest { anonymous = true ) - private val workgroupref = WorkgroupRef() - - init { - mockkStatic("fr.dcproject.ApplicationContextKt") + @Test + fun `can be view your workgroup`() { + WorkgroupVoter() + .canView(workgroupPublic, tesla) + .vote `should be` GRANTED } @Test - fun `support workgroup`(): Unit = WorkgroupVoter().run { - val p = object : ActionI {} - mockk { - every { user } returns tesla.user - }.let { - this(WorkgroupVoter.Action.VIEW, it, workgroupPublic).vote `should be` Vote.GRANTED - this(WorkgroupVoter.Action.VIEW, it, article1).vote `should be` Vote.ABSTAIN - this(p, it, workgroupPublic).vote `should be` Vote.ABSTAIN - } + fun `can be view your workgroup if is not public`() { + WorkgroupVoter() + .canView(workgroupAnon, tesla) + .vote `should be` GRANTED } @Test - fun `can be view your workgroup`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(WorkgroupVoter.Action.VIEW, it, workgroupPublic) `should be` true - } + fun `can be view workgroup of other if is public`() { + WorkgroupVoter() + .canView(workgroupPublic, einstein) + .vote `should be` GRANTED } @Test - fun `can be view your workgroup if is not public`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(WorkgroupVoter.Action.VIEW, it, workgroupAnon) `should be` true - } + fun `can not be view workgroup of other if is not public`() { + WorkgroupVoter() + .canView(workgroupAnon, einstein) + .vote `should be` DENIED } @Test - fun `can be view workgroup of other if is public`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - can(WorkgroupVoter.Action.VIEW, it, workgroupPublic) `should be` true - } + fun `can be view your workgroup list`() { + WorkgroupVoter() + .canView(listOf(workgroupPublic, workgroupAnon), tesla) + .vote `should be` GRANTED } @Test - fun `can not be view workgroup of other if is not public`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - can(WorkgroupVoter.Action.VIEW, it, workgroupAnon) `should be` false - } + fun `can be create workgroup`() { + WorkgroupVoter() + .canCreate(workgroupPublic, tesla) + .vote `should be` GRANTED } @Test - fun `can be not view the workgroup if is null`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - assertThrows { - can(WorkgroupVoter.Action.VIEW, it, null) - } - } + fun `can not be create workgroup if not connected`() { + WorkgroupVoter() + .canCreate(workgroupPublic, null) + .vote `should be` DENIED } @Test - fun `can be view your workgroup list`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - listOf(workgroupPublic).map { workgroup -> - can(WorkgroupVoter.Action.VIEW, it, workgroup) - }.all { it } `should be` true - } + fun `can be delete workgroup if owner`() { + WorkgroupVoter() + .canDelete(workgroupPublic, tesla) + .vote `should be` GRANTED } @Test - fun `can be create workgroup`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(WorkgroupVoter.Action.CREATE, it, workgroupPublic) `should be` true - } + fun `can not be delete workgroup if not owner`() { + WorkgroupVoter() + .canDelete(workgroupPublic, einstein) + .vote `should be` DENIED } @Test - fun `can not be create workgroup if not connected`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns null - }.let { - can(WorkgroupVoter.Action.CREATE, it, workgroupPublic) `should be` false - } + fun `can be update workgroup if owner`() { + WorkgroupVoter() + .canUpdate(workgroupPublic, tesla) + .vote `should be` GRANTED } @Test - fun `can be delete workgroup if owner`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(WorkgroupVoter.Action.DELETE, it, workgroupPublic) `should be` true - } - } - - @Test - fun `can not be delete workgroup if not owner`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - can(WorkgroupVoter.Action.DELETE, it, workgroupPublic) `should be` false - } - } - - @Test - fun `can be update workgroup if owner`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(WorkgroupVoter.Action.UPDATE, it, workgroupPublic) `should be` true - } - } - - @Test - fun `can not be update workgroup if not owner`(): Unit = listOf(WorkgroupVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - can(WorkgroupVoter.Action.UPDATE, it, workgroupPublic) `should be` false - } - } - - @Test - fun `can not be update workgroup if workgroup has no user`() { - Assertions.assertThrows(VoterException::class.java) { - listOf(WorkgroupVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(WorkgroupVoter.Action.UPDATE, it, workgroupref) - } - } - } + fun `can not be update workgroup if not owner`() { + WorkgroupVoter() + .canUpdate(workgroupPublic, einstein) + .vote `should be` DENIED } } \ No newline at end of file