From 6a8c5bf7171d31e749c136bb4e96380b06176977 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Thu, 14 Jan 2021 15:07:59 +0100 Subject: [PATCH] Refactors Citizen into component Refactor CitizenVoter Split citizens routes --- src/main/kotlin/Application.kt | 13 ++- src/main/kotlin/ApplicationContext.kt | 4 +- src/main/kotlin/Converters.kt | 10 +- src/main/kotlin/KoinModule.kt | 4 +- src/main/kotlin/component/article/Article.kt | 1 + .../component/article/ArticleViewManager.kt | 2 +- .../kotlin/component/article/ArticleVoter.kt | 2 +- .../{entity => component/citizen}/Citizen.kt | 8 +- .../component/citizen/CitizenRepository.kt | 49 ++++++++++ .../kotlin/component/citizen/CitizenVoter.kt | 26 +++++ .../citizen/routes/ChangeMyPassword.kt | 45 +++++++++ .../component/citizen/routes/FindCitizens.kt | 33 +++++++ .../citizen/routes/GetCurrentCitizen.kt | 28 ++++++ .../component/citizen/routes/GetOneCitizen.kt | 23 +++++ src/main/kotlin/entity/Comment.kt | 1 + src/main/kotlin/entity/Constitution.kt | 2 + src/main/kotlin/entity/CreatedBy.kt | 1 + src/main/kotlin/entity/Extra.kt | 1 + src/main/kotlin/entity/Follow.kt | 3 + src/main/kotlin/entity/Opinion.kt | 4 + src/main/kotlin/entity/Vote.kt | 3 + src/main/kotlin/entity/Workgroup.kt | 3 + src/main/kotlin/event/EventNotification.kt | 2 +- .../messages/NotificationEmailSender.kt | 6 +- src/main/kotlin/messages/SsoManager.kt | 6 +- src/main/kotlin/repository/Citizen.kt | 53 ---------- src/main/kotlin/repository/Comment.kt | 2 + src/main/kotlin/repository/Constitution.kt | 2 +- src/main/kotlin/repository/Follow.kt | 7 +- src/main/kotlin/repository/Opinion.kt | 4 +- src/main/kotlin/repository/Vote.kt | 3 +- src/main/kotlin/repository/Workgroup.kt | 7 +- src/main/kotlin/routes/Auth.kt | 25 +++-- src/main/kotlin/routes/Citizen.kt | 96 ------------------- src/main/kotlin/routes/CommentArticle.kt | 2 +- src/main/kotlin/routes/CommentConstitution.kt | 2 +- src/main/kotlin/routes/Constitution.kt | 2 +- src/main/kotlin/routes/FollowArticle.kt | 2 +- src/main/kotlin/routes/FollowConstitution.kt | 2 +- src/main/kotlin/routes/OpinionArticle.kt | 4 +- src/main/kotlin/routes/VoteArticle.kt | 2 +- src/main/kotlin/routes/VoteConstitution.kt | 2 +- src/main/kotlin/routes/Workgroup.kt | 2 +- src/main/kotlin/views/ViewManager.kt | 2 +- src/main/kotlin/voter/CitizenVoter.kt | 61 ------------ src/main/kotlin/voter/FollowVoter.kt | 2 +- src/test/kotlin/ViewTest.kt | 2 +- src/test/kotlin/feature/ArticleSteps.kt | 7 +- src/test/kotlin/feature/CitizenSteps.kt | 6 +- src/test/kotlin/feature/ConstitutionSteps.kt | 9 +- src/test/kotlin/feature/FollowSteps.kt | 2 +- .../kotlin/feature/KtorServerAuthSteps.kt | 2 +- src/test/kotlin/feature/OpinionSteps.kt | 2 +- src/test/kotlin/feature/VoteSteps.kt | 2 +- src/test/kotlin/feature/WorkgroupSteps.kt | 5 +- .../kotlin/security/voter/ArticleVoterTest.kt | 4 +- .../kotlin/security/voter/CitizenVoterTest.kt | 96 +++++++------------ .../kotlin/security/voter/CommentVoterTest.kt | 9 +- .../kotlin/security/voter/FollowVoterTest.kt | 8 +- .../security/voter/OpinionChoiceVoterTest.kt | 7 +- .../kotlin/security/voter/OpinionVoterTest.kt | 9 +- .../kotlin/security/voter/VoteVoterTest.kt | 8 +- .../security/voter/WorkgroupVoterTest.kt | 8 +- 63 files changed, 404 insertions(+), 346 deletions(-) rename src/main/kotlin/{entity => component/citizen}/Citizen.kt (91%) create mode 100644 src/main/kotlin/component/citizen/CitizenRepository.kt create mode 100644 src/main/kotlin/component/citizen/CitizenVoter.kt create mode 100644 src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt create mode 100644 src/main/kotlin/component/citizen/routes/FindCitizens.kt create mode 100644 src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt create mode 100644 src/main/kotlin/component/citizen/routes/GetOneCitizen.kt delete mode 100644 src/main/kotlin/repository/Citizen.kt delete mode 100644 src/main/kotlin/routes/Citizen.kt delete mode 100644 src/main/kotlin/voter/CitizenVoter.kt diff --git a/src/main/kotlin/Application.kt b/src/main/kotlin/Application.kt index bf02291..7d1898d 100644 --- a/src/main/kotlin/Application.kt +++ b/src/main/kotlin/Application.kt @@ -12,6 +12,10 @@ import fr.dcproject.component.article.route.findArticleVersions import fr.dcproject.component.article.route.upsertArticle import fr.dcproject.component.article.routes.findArticles import fr.dcproject.component.article.routes.getOneArticle +import fr.dcproject.component.citizen.routes.changeMyPassword +import fr.dcproject.component.citizen.routes.findCitizen +import fr.dcproject.component.citizen.routes.getCurrentCitizen +import fr.dcproject.component.citizen.routes.getOneCitizen import fr.dcproject.elasticsearch.configElasticIndexes import fr.dcproject.entity.User import fr.dcproject.event.EventNotification @@ -71,7 +75,6 @@ fun Application.module(env: Env = PROD) { install(AuthorizationVoter) { voters = listOf( ConstitutionVoter(), - CitizenVoter(), CommentVoter(), VoteVoter(), FollowVoter(), @@ -151,12 +154,18 @@ fun Application.module(env: Env = PROD) { install(Routing.Feature) { // trace { application.log.trace(it.buildText()) } authenticate(optional = true) { + /* Article */ findArticles(get(), get()) getOneArticle(get(), get()) upsertArticle(get(), get(), get()) findArticleVersions(get(), get()) + /* Citizen */ + findCitizen(get(), get()) + getOneCitizen(get()) + getCurrentCitizen(get()) + changeMyPassword(get(), get()) + auth(get(), get(), get()) - citizen(get(), get()) constitution(get()) followArticle(get()) followConstitution(get()) diff --git a/src/main/kotlin/ApplicationContext.kt b/src/main/kotlin/ApplicationContext.kt index 9cec735..3751b43 100644 --- a/src/main/kotlin/ApplicationContext.kt +++ b/src/main/kotlin/ApplicationContext.kt @@ -1,5 +1,6 @@ package fr.dcproject +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.User import fr.dcproject.entity.UserI import io.ktor.application.* @@ -7,8 +8,7 @@ import io.ktor.auth.* import io.ktor.util.* import io.ktor.util.pipeline.* import org.koin.core.context.GlobalContext -import fr.dcproject.entity.Citizen as CitizenEntity -import fr.dcproject.repository.Citizen as CitizenRepository +import fr.dcproject.component.citizen.Citizen as CitizenEntity class ForbiddenException(message: String) : Exception(message) diff --git a/src/main/kotlin/Converters.kt b/src/main/kotlin/Converters.kt index dae5baa..aa5fc44 100644 --- a/src/main/kotlin/Converters.kt +++ b/src/main/kotlin/Converters.kt @@ -3,7 +3,13 @@ package fr.dcproject import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRepository -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.entity.CommentRef +import fr.dcproject.entity.Constitution +import fr.dcproject.entity.ConstitutionRef +import fr.dcproject.entity.WorkgroupRef import fr.dcproject.repository.OpinionChoice import fr.dcproject.repository.Workgroup import io.ktor.features.* @@ -78,7 +84,7 @@ val converters: ConverterDeclaration = { decode { values, _ -> val id = values.singleOrNull()?.let { UUID.fromString(it) } ?: throw InternalError("Cannot convert $values to UUID") - get().findById(id) ?: throw NotFoundException("Citizen $values not found") + get().findById(id) ?: throw NotFoundException("Citizen $values not found") } } diff --git a/src/main/kotlin/KoinModule.kt b/src/main/kotlin/KoinModule.kt index f9edbf2..51f8eb2 100644 --- a/src/main/kotlin/KoinModule.kt +++ b/src/main/kotlin/KoinModule.kt @@ -11,6 +11,8 @@ import com.rabbitmq.client.ConnectionFactory import fr.dcproject.component.article.ArticleRepository import fr.dcproject.component.article.ArticleViewManager import fr.dcproject.component.article.ArticleVoter +import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.event.publisher.Publisher import fr.dcproject.messages.Mailer import fr.dcproject.messages.NotificationEmailSender @@ -27,7 +29,6 @@ import org.apache.http.HttpHost import org.elasticsearch.client.RestClient import org.koin.core.qualifier.named import org.koin.dsl.module -import fr.dcproject.repository.Citizen as CitizenRepository import fr.dcproject.repository.CommentArticle as CommentArticleRepository import fr.dcproject.repository.CommentConstitution as CommentConstitutionRepository import fr.dcproject.repository.CommentGeneric as CommentGenericRepository @@ -117,6 +118,7 @@ val KoinModule = module { // Voters single { ArticleVoter(get()) } + single { CitizenVoter() } // Elasticsearch Client single { diff --git a/src/main/kotlin/component/article/Article.kt b/src/main/kotlin/component/article/Article.kt index 9c7fa54..e57075d 100644 --- a/src/main/kotlin/component/article/Article.kt +++ b/src/main/kotlin/component/article/Article.kt @@ -1,5 +1,6 @@ package fr.dcproject.component.article +import fr.dcproject.component.citizen.* import fr.dcproject.entity.* import fr.postgresjson.entity.* import org.joda.time.DateTime diff --git a/src/main/kotlin/component/article/ArticleViewManager.kt b/src/main/kotlin/component/article/ArticleViewManager.kt index 76b2530..1e11d5c 100644 --- a/src/main/kotlin/component/article/ArticleViewManager.kt +++ b/src/main/kotlin/component/article/ArticleViewManager.kt @@ -1,6 +1,6 @@ package fr.dcproject.component.article -import fr.dcproject.entity.CitizenI +import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.ViewAggregation import fr.dcproject.utils.contentToString import fr.dcproject.utils.getJsonField diff --git a/src/main/kotlin/component/article/ArticleVoter.kt b/src/main/kotlin/component/article/ArticleVoter.kt index b2762a1..aca592f 100644 --- a/src/main/kotlin/component/article/ArticleVoter.kt +++ b/src/main/kotlin/component/article/ArticleVoter.kt @@ -1,6 +1,6 @@ package fr.dcproject.component.article -import fr.dcproject.entity.CitizenI +import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.CreatedBy import fr.dcproject.entity.VersionableRef import fr.dcproject.voter.Voter diff --git a/src/main/kotlin/entity/Citizen.kt b/src/main/kotlin/component/citizen/Citizen.kt similarity index 91% rename from src/main/kotlin/entity/Citizen.kt rename to src/main/kotlin/component/citizen/Citizen.kt index ed1b6fd..ee515d7 100644 --- a/src/main/kotlin/entity/Citizen.kt +++ b/src/main/kotlin/component/citizen/Citizen.kt @@ -1,6 +1,10 @@ -package fr.dcproject.entity +package fr.dcproject.component.citizen -import fr.dcproject.entity.CitizenI.Name +import fr.dcproject.component.citizen.CitizenI.Name +import fr.dcproject.entity.User +import fr.dcproject.entity.UserI +import fr.dcproject.entity.UserRef +import fr.dcproject.entity.WorkgroupSimple import fr.postgresjson.entity.* import org.joda.time.DateTime import java.util.* diff --git a/src/main/kotlin/component/citizen/CitizenRepository.kt b/src/main/kotlin/component/citizen/CitizenRepository.kt new file mode 100644 index 0000000..6ca0557 --- /dev/null +++ b/src/main/kotlin/component/citizen/CitizenRepository.kt @@ -0,0 +1,49 @@ +package fr.dcproject.component.citizen + +import fr.dcproject.entity.UserI +import fr.postgresjson.connexion.Paginated +import fr.postgresjson.connexion.Requester +import fr.postgresjson.repository.RepositoryI +import net.pearx.kasechange.toSnakeCase +import java.util.* + +class CitizenRepository(override var requester: Requester) : RepositoryI { + fun findById(id: UUID): Citizen? = requester + .getFunction("find_citizen_by_id_with_user_and_workgroups") + .selectOne("id" to id) + + fun findByUser(user: UserI): Citizen? = requester + .getFunction("find_citizen_by_user_id") + .selectOne("user_id" to user.id) + + fun findByUsername(unsername: String): Citizen? = requester + .getFunction("find_citizen_by_username") + .selectOne("username" to unsername) + + fun findByEmail(email: String): Citizen? = requester + .getFunction("find_citizen_by_email") + .selectOne("email" to email) + + fun find( + page: Int = 1, + limit: Int = 50, + sort: String? = null, + direction: RepositoryI.Direction? = null, + search: String? = null + ): Paginated = requester + .getFunction("find_citizens") + .select( + page, limit, + "sort" to sort?.toSnakeCase(), + "direction" to direction, + "search" to search + ) + + fun upsert(citizen: CitizenFull): Citizen? = requester + .getFunction("upsert_citizen") + .selectOne("resource" to citizen) + + fun insertWithUser(citizen: CitizenFull): Citizen? = requester + .getFunction("insert_citizen_with_user") + .selectOne("resource" to citizen) +} diff --git a/src/main/kotlin/component/citizen/CitizenVoter.kt b/src/main/kotlin/component/citizen/CitizenVoter.kt new file mode 100644 index 0000000..a18e7f9 --- /dev/null +++ b/src/main/kotlin/component/citizen/CitizenVoter.kt @@ -0,0 +1,26 @@ +package fr.dcproject.component.citizen + +import fr.dcproject.voter.Voter +import fr.dcproject.voter.VoterResponse +import fr.postgresjson.entity.EntityDeletedAt + +class CitizenVoter : Voter() { + fun canView(subjects: List, connectedCitizen: CitizenI?): VoterResponse where S : CitizenI, S: EntityDeletedAt = + canAll(subjects) { canView(it, connectedCitizen) } + + fun 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") + return if (subject.isDeleted()) denied("You cannot view a deleted citizen", "citizen.view.deleted") + else granted() + } + + fun canUpdate(subject: S, connectedCitizen: CitizenI?): VoterResponse { + 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") + } + + fun canChangePassword(subject: S, connectedCitizen: CitizenI?): VoterResponse { + 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") + } +} \ No newline at end of file diff --git a/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt b/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt new file mode 100644 index 0000000..abbea0d --- /dev/null +++ b/src/main/kotlin/component/citizen/routes/ChangeMyPassword.kt @@ -0,0 +1,45 @@ +package fr.dcproject.component.citizen.routes + +import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException +import fr.dcproject.citizen +import fr.dcproject.citizenOrNull +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenVoter +import fr.dcproject.repository.User +import fr.dcproject.voter.assert +import io.ktor.application.* +import io.ktor.auth.* +import io.ktor.http.* +import io.ktor.locations.* +import io.ktor.request.* +import io.ktor.response.* +import io.ktor.routing.* + +@KtorExperimentalLocationsAPI + +@Location("/citizens/{citizen}/password/change") +class ChangePasswordCitizenRequest(val citizen: Citizen) { + data class Input(val oldPassword: String, val newPassword: String) +} + +@KtorExperimentalLocationsAPI +fun Route.changeMyPassword(voter: CitizenVoter, userRepository: User) { + put { + voter.assert { canChangePassword(it.citizen, citizenOrNull) } + try { + val content = call.receive() + val currentUser = userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) + val user = it.citizen.user + if (currentUser == null || currentUser.id != user.id) { + call.respond(HttpStatusCode.BadRequest, "Bad password") + } else { + user.plainPassword = content.newPassword + userRepository.changePassword(user) + + call.respond(HttpStatusCode.Created) + } + } catch (e: MissingKotlinParameterException) { + call.respond(HttpStatusCode.BadRequest, "Request format is not correct") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/component/citizen/routes/FindCitizens.kt b/src/main/kotlin/component/citizen/routes/FindCitizens.kt new file mode 100644 index 0000000..5ed6b4a --- /dev/null +++ b/src/main/kotlin/component/citizen/routes/FindCitizens.kt @@ -0,0 +1,33 @@ +package fr.dcproject.component.citizen.routes + +import fr.dcproject.citizenOrNull +import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.component.citizen.CitizenVoter +import fr.dcproject.voter.assert +import fr.postgresjson.repository.RepositoryI +import io.ktor.application.* +import io.ktor.locations.* +import io.ktor.response.* +import io.ktor.routing.* + +@KtorExperimentalLocationsAPI +@Location("/citizens") +class CitizensRequest( + page: Int = 1, + limit: Int = 50, + val sort: String? = null, + val direction: RepositoryI.Direction? = null, + val search: String? = null +) { + val page: Int = if (page < 1) 1 else page + val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit +} + +@KtorExperimentalLocationsAPI +fun Route.findCitizen(voter: CitizenVoter, repo: CitizenRepository) { + get { + val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search) + voter.assert { canView(citizens.result, citizenOrNull) } + call.respond(citizens) + } +} \ No newline at end of file diff --git a/src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt b/src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt new file mode 100644 index 0000000..590e184 --- /dev/null +++ b/src/main/kotlin/component/citizen/routes/GetCurrentCitizen.kt @@ -0,0 +1,28 @@ +package fr.dcproject.component.citizen.routes + +import fr.dcproject.citizen +import fr.dcproject.citizenOrNull +import fr.dcproject.component.citizen.CitizenVoter +import fr.dcproject.voter.assert +import io.ktor.application.* +import io.ktor.http.* +import io.ktor.locations.* +import io.ktor.response.* +import io.ktor.routing.* + +@KtorExperimentalLocationsAPI +@Location("/citizens/current") +class CurrentCitizenRequest + +@KtorExperimentalLocationsAPI +fun Route.getCurrentCitizen(voter: CitizenVoter) { + get { + val currentUser = citizenOrNull + if (currentUser === null) { + call.respond(HttpStatusCode.Unauthorized) + } else { + voter.assert { canView(currentUser, citizenOrNull) } + call.respond(citizen) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt b/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt new file mode 100644 index 0000000..f7cd9b4 --- /dev/null +++ b/src/main/kotlin/component/citizen/routes/GetOneCitizen.kt @@ -0,0 +1,23 @@ +package fr.dcproject.component.citizen.routes + +import fr.dcproject.citizenOrNull +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenVoter +import fr.dcproject.voter.assert +import io.ktor.application.* +import io.ktor.locations.* +import io.ktor.response.* +import io.ktor.routing.* + +@KtorExperimentalLocationsAPI +@Location("/citizens/{citizen}") +class CitizenRequest(val citizen: Citizen) + +@KtorExperimentalLocationsAPI +fun Route.getOneCitizen(voter: CitizenVoter) { + get { + voter.assert { canView(it.citizen, citizenOrNull) } + + call.respond(it.citizen) + } +} \ No newline at end of file diff --git a/src/main/kotlin/entity/Comment.kt b/src/main/kotlin/entity/Comment.kt index 4eb0f91..793bf32 100644 --- a/src/main/kotlin/entity/Comment.kt +++ b/src/main/kotlin/entity/Comment.kt @@ -1,5 +1,6 @@ package fr.dcproject.entity +import fr.dcproject.component.citizen.CitizenRef import fr.postgresjson.entity.* import org.joda.time.DateTime import java.util.* diff --git a/src/main/kotlin/entity/Constitution.kt b/src/main/kotlin/entity/Constitution.kt index 5eeb35c..271babb 100644 --- a/src/main/kotlin/entity/Constitution.kt +++ b/src/main/kotlin/entity/Constitution.kt @@ -2,6 +2,8 @@ package fr.dcproject.entity import fr.dcproject.component.article.ArticleI import fr.dcproject.component.article.ArticleSimple +import fr.dcproject.component.citizen.CitizenSimple +import fr.dcproject.component.citizen.CitizenWithUserI import fr.postgresjson.entity.* import java.util.* diff --git a/src/main/kotlin/entity/CreatedBy.kt b/src/main/kotlin/entity/CreatedBy.kt index 84a8d39..af2a122 100644 --- a/src/main/kotlin/entity/CreatedBy.kt +++ b/src/main/kotlin/entity/CreatedBy.kt @@ -1,5 +1,6 @@ package fr.dcproject.entity +import fr.dcproject.component.citizen.CitizenI import fr.postgresjson.entity.EntityCreatedBy import fr.postgresjson.entity.EntityI diff --git a/src/main/kotlin/entity/Extra.kt b/src/main/kotlin/entity/Extra.kt index 0269d0a..9b5daeb 100644 --- a/src/main/kotlin/entity/Extra.kt +++ b/src/main/kotlin/entity/Extra.kt @@ -1,6 +1,7 @@ package fr.dcproject.entity import fr.dcproject.component.article.ArticleRef +import fr.dcproject.component.citizen.CitizenI import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.EntityCreatedBy import fr.postgresjson.entity.UuidEntity diff --git a/src/main/kotlin/entity/Follow.kt b/src/main/kotlin/entity/Follow.kt index f5cd6ec..523c8e2 100644 --- a/src/main/kotlin/entity/Follow.kt +++ b/src/main/kotlin/entity/Follow.kt @@ -1,5 +1,8 @@ package fr.dcproject.entity +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenBasicI +import fr.dcproject.component.citizen.CitizenI import fr.postgresjson.entity.* import java.util.* diff --git a/src/main/kotlin/entity/Opinion.kt b/src/main/kotlin/entity/Opinion.kt index 69dfd3e..a03221d 100644 --- a/src/main/kotlin/entity/Opinion.kt +++ b/src/main/kotlin/entity/Opinion.kt @@ -1,6 +1,10 @@ package fr.dcproject.entity import fr.dcproject.component.article.ArticleRef +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenBasicI +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRef import fr.postgresjson.entity.* import java.util.* diff --git a/src/main/kotlin/entity/Vote.kt b/src/main/kotlin/entity/Vote.kt index dfa9c35..d3c5a77 100644 --- a/src/main/kotlin/entity/Vote.kt +++ b/src/main/kotlin/entity/Vote.kt @@ -1,5 +1,8 @@ package fr.dcproject.entity +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenBasicI +import fr.dcproject.component.citizen.CitizenI import fr.postgresjson.entity.* import java.util.* @Deprecated("") diff --git a/src/main/kotlin/entity/Workgroup.kt b/src/main/kotlin/entity/Workgroup.kt index 627f8a7..80de703 100644 --- a/src/main/kotlin/entity/Workgroup.kt +++ b/src/main/kotlin/entity/Workgroup.kt @@ -1,5 +1,8 @@ package fr.dcproject.entity +import fr.dcproject.component.citizen.CitizenBasicI +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenWithUserI import fr.dcproject.entity.WorkgroupWithMembersI.Member import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role import fr.postgresjson.entity.* diff --git a/src/main/kotlin/event/EventNotification.kt b/src/main/kotlin/event/EventNotification.kt index 2e1f26b..0ef0008 100644 --- a/src/main/kotlin/event/EventNotification.kt +++ b/src/main/kotlin/event/EventNotification.kt @@ -4,7 +4,7 @@ import com.rabbitmq.client.* import com.rabbitmq.client.BuiltinExchangeType.DIRECT import fr.dcproject.Config import fr.dcproject.component.article.ArticleForView -import fr.dcproject.entity.CitizenRef +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.entity.FollowSimple import fr.dcproject.entity.TargetRef import fr.dcproject.event.publisher.Publisher diff --git a/src/main/kotlin/messages/NotificationEmailSender.kt b/src/main/kotlin/messages/NotificationEmailSender.kt index 45d6ab9..7f2b4c3 100644 --- a/src/main/kotlin/messages/NotificationEmailSender.kt +++ b/src/main/kotlin/messages/NotificationEmailSender.kt @@ -5,13 +5,13 @@ import com.sendgrid.helpers.mail.objects.Content import com.sendgrid.helpers.mail.objects.Email import fr.dcproject.component.article.ArticleRepository import fr.dcproject.component.article.ArticleWithTitleI -import fr.dcproject.entity.CitizenBasicI -import fr.dcproject.entity.CitizenRef +import fr.dcproject.component.citizen.CitizenBasicI +import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.FollowSimple import fr.dcproject.entity.TargetRef import fr.postgresjson.entity.UuidEntityI import java.util.* -import fr.dcproject.repository.Citizen as CitizenRepository class NotificationEmailSender( private val mailer: Mailer, diff --git a/src/main/kotlin/messages/SsoManager.kt b/src/main/kotlin/messages/SsoManager.kt index 109b23f..903cc42 100644 --- a/src/main/kotlin/messages/SsoManager.kt +++ b/src/main/kotlin/messages/SsoManager.kt @@ -4,9 +4,9 @@ import com.sendgrid.helpers.mail.Mail import com.sendgrid.helpers.mail.objects.Content import com.sendgrid.helpers.mail.objects.Email import fr.dcproject.JwtConfig -import fr.dcproject.entity.CitizenBasicI -import io.ktor.http.URLBuilder -import fr.dcproject.repository.Citizen as CitizenRepository +import fr.dcproject.component.citizen.CitizenBasicI +import fr.dcproject.component.citizen.CitizenRepository +import io.ktor.http.* class SsoManager( private val mailer: Mailer, diff --git a/src/main/kotlin/repository/Citizen.kt b/src/main/kotlin/repository/Citizen.kt deleted file mode 100644 index 1021e1b..0000000 --- a/src/main/kotlin/repository/Citizen.kt +++ /dev/null @@ -1,53 +0,0 @@ -package fr.dcproject.repository - -import fr.dcproject.entity.CitizenBasic -import fr.dcproject.entity.CitizenFull -import fr.dcproject.entity.UserI -import fr.postgresjson.connexion.Paginated -import fr.postgresjson.connexion.Requester -import fr.postgresjson.repository.RepositoryI -import fr.postgresjson.repository.RepositoryI.Direction -import net.pearx.kasechange.toSnakeCase -import java.util.* -import fr.dcproject.entity.Citizen as CitizenEntity - -class Citizen(override var requester: Requester) : RepositoryI { - fun findById(id: UUID): CitizenEntity? = requester - .getFunction("find_citizen_by_id_with_user_and_workgroups") - .selectOne("id" to id) - - fun findByUser(user: UserI): CitizenEntity? = requester - .getFunction("find_citizen_by_user_id") - .selectOne("user_id" to user.id) - - fun findByUsername(unsername: String): CitizenEntity? = requester - .getFunction("find_citizen_by_username") - .selectOne("username" to unsername) - - fun findByEmail(email: String): CitizenEntity? = requester - .getFunction("find_citizen_by_email") - .selectOne("email" to email) - - fun find( - page: Int = 1, - limit: Int = 50, - sort: String? = null, - direction: Direction? = null, - search: String? = null - ): Paginated = requester - .getFunction("find_citizens") - .select( - page, limit, - "sort" to sort?.toSnakeCase(), - "direction" to direction, - "search" to search - ) - - fun upsert(citizen: CitizenFull): CitizenEntity? = requester - .getFunction("upsert_citizen") - .selectOne("resource" to citizen) - - fun insertWithUser(citizen: CitizenFull): CitizenEntity? = requester - .getFunction("insert_citizen_with_user") - .selectOne("resource" to citizen) -} diff --git a/src/main/kotlin/repository/Comment.kt b/src/main/kotlin/repository/Comment.kt index 2b76fad..7d44867 100644 --- a/src/main/kotlin/repository/Comment.kt +++ b/src/main/kotlin/repository/Comment.kt @@ -2,6 +2,8 @@ package fr.dcproject.repository import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRef +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.entity.* import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester diff --git a/src/main/kotlin/repository/Constitution.kt b/src/main/kotlin/repository/Constitution.kt index 3a5fe39..2d6edb8 100644 --- a/src/main/kotlin/repository/Constitution.kt +++ b/src/main/kotlin/repository/Constitution.kt @@ -1,7 +1,7 @@ package fr.dcproject.repository import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.CitizenWithUserI +import fr.dcproject.component.citizen.CitizenWithUserI import fr.dcproject.entity.ConstitutionSimple import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester diff --git a/src/main/kotlin/repository/Follow.kt b/src/main/kotlin/repository/Follow.kt index 0c1e6ff..3616b3c 100644 --- a/src/main/kotlin/repository/Follow.kt +++ b/src/main/kotlin/repository/Follow.kt @@ -2,7 +2,12 @@ package fr.dcproject.repository import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.entity.ConstitutionRef +import fr.dcproject.entity.FollowForUpdate +import fr.dcproject.entity.FollowSimple +import fr.dcproject.entity.TargetRef import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester import fr.postgresjson.entity.UuidEntity diff --git a/src/main/kotlin/repository/Opinion.kt b/src/main/kotlin/repository/Opinion.kt index 779e3c1..a891f0d 100644 --- a/src/main/kotlin/repository/Opinion.kt +++ b/src/main/kotlin/repository/Opinion.kt @@ -2,7 +2,7 @@ package fr.dcproject.repository import com.fasterxml.jackson.core.type.TypeReference import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.CitizenRef +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.entity.OpinionChoiceRef import fr.dcproject.entity.OpinionForUpdate import fr.dcproject.entity.TargetRef @@ -11,7 +11,7 @@ import fr.postgresjson.connexion.Requester import fr.postgresjson.repository.RepositoryI import net.pearx.kasechange.toSnakeCase import java.util.* -import fr.dcproject.entity.Citizen as CitizenEntity +import fr.dcproject.component.citizen.Citizen as CitizenEntity import fr.dcproject.entity.Opinion as OpinionEntity import fr.dcproject.entity.OpinionArticle as OpinionArticleEntity import fr.dcproject.entity.OpinionChoice as OpinionChoiceEntity diff --git a/src/main/kotlin/repository/Vote.kt b/src/main/kotlin/repository/Vote.kt index 3bb3da7..534329f 100644 --- a/src/main/kotlin/repository/Vote.kt +++ b/src/main/kotlin/repository/Vote.kt @@ -2,13 +2,14 @@ package fr.dcproject.repository import com.fasterxml.jackson.core.type.TypeReference import fr.dcproject.component.article.ArticleForView +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.entity.* import fr.dcproject.entity.Constitution import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester import fr.postgresjson.repository.RepositoryI import java.util.* -import fr.dcproject.entity.Citizen as CitizenEntity +import fr.dcproject.component.citizen.Citizen as CitizenEntity import fr.dcproject.entity.Vote as VoteEntity open class Vote(override var requester: Requester) : RepositoryI { diff --git a/src/main/kotlin/repository/Workgroup.kt b/src/main/kotlin/repository/Workgroup.kt index 056b48e..59d4883 100644 --- a/src/main/kotlin/repository/Workgroup.kt +++ b/src/main/kotlin/repository/Workgroup.kt @@ -1,6 +1,11 @@ package fr.dcproject.repository -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.WorkgroupI +import fr.dcproject.entity.WorkgroupRef +import fr.dcproject.entity.WorkgroupSimple +import fr.dcproject.entity.WorkgroupWithMembersI import fr.dcproject.entity.WorkgroupWithMembersI.Member import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester diff --git a/src/main/kotlin/routes/Auth.kt b/src/main/kotlin/routes/Auth.kt index e65cae9..91a461e 100644 --- a/src/main/kotlin/routes/Auth.kt +++ b/src/main/kotlin/routes/Auth.kt @@ -3,25 +3,22 @@ package fr.dcproject.routes import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException import fr.dcproject.JwtConfig +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.UserI.Roles.ROLE_USER import fr.dcproject.messages.SsoManager import fr.dcproject.routes.AuthPaths.LoginRequest import fr.dcproject.routes.AuthPaths.RegisterRequest import fr.dcproject.routes.AuthPaths.SsoRequest -import io.ktor.application.call -import io.ktor.auth.UserPasswordCredential -import io.ktor.features.BadRequestException -import io.ktor.http.HttpStatusCode -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.Location -import io.ktor.locations.post -import io.ktor.request.receive -import io.ktor.response.respond -import io.ktor.response.respondText -import io.ktor.routing.Route -import io.ktor.util.KtorExperimentalAPI -import fr.dcproject.entity.Citizen as CitizenEntity -import fr.dcproject.repository.Citizen as CitizenRepository +import io.ktor.application.* +import io.ktor.auth.* +import io.ktor.features.* +import io.ktor.http.* +import io.ktor.locations.* +import io.ktor.request.* +import io.ktor.response.* +import io.ktor.routing.* +import io.ktor.util.* +import fr.dcproject.component.citizen.Citizen as CitizenEntity import fr.dcproject.repository.User as UserRepository @KtorExperimentalLocationsAPI diff --git a/src/main/kotlin/routes/Citizen.kt b/src/main/kotlin/routes/Citizen.kt deleted file mode 100644 index dbe1036..0000000 --- a/src/main/kotlin/routes/Citizen.kt +++ /dev/null @@ -1,96 +0,0 @@ -package fr.dcproject.routes - -import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException -import fr.dcproject.citizen -import fr.dcproject.citizenOrNull -import fr.dcproject.entity.Citizen -import fr.dcproject.routes.CitizenPaths.ChangePasswordCitizenRequest -import fr.dcproject.routes.CitizenPaths.CitizenRequest -import fr.dcproject.routes.CitizenPaths.CitizensRequest -import fr.dcproject.routes.CitizenPaths.CurrentCitizenRequest -import fr.dcproject.security.voter.CitizenVoter.Action.CHANGE_PASSWORD -import fr.dcproject.security.voter.CitizenVoter.Action.VIEW -import fr.ktorVoter.assertCan -import fr.ktorVoter.assertCanAll -import fr.postgresjson.repository.RepositoryI.Direction -import io.ktor.application.* -import io.ktor.auth.* -import io.ktor.http.* -import io.ktor.locations.* -import io.ktor.request.* -import io.ktor.response.* -import io.ktor.routing.* -import fr.dcproject.repository.Citizen as CitizenRepository -import fr.dcproject.repository.User as UserRepository - -@KtorExperimentalLocationsAPI -object CitizenPaths { - @Location("/citizens") - class CitizensRequest( - page: Int = 1, - limit: Int = 50, - val sort: String? = null, - val direction: Direction? = null, - val search: String? = null - ) { - val page: Int = if (page < 1) 1 else page - val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit - } - - @Location("/citizens/{citizen}") - class CitizenRequest(val citizen: Citizen) - - @Location("/citizens/current") - class CurrentCitizenRequest - - @Location("/citizens/{citizen}/password/change") - class ChangePasswordCitizenRequest(val citizen: Citizen) { - data class Content(val oldPassword: String, val newPassword: String) - } -} - -@KtorExperimentalLocationsAPI -fun Route.citizen( - repo: CitizenRepository, - userRepository: UserRepository -) { - get { - val citizens = repo.find(it.page, it.limit, it.sort, it.direction, it.search) - assertCanAll(VIEW, citizens.result) - call.respond(citizens) - } - - get { - assertCan(VIEW, it.citizen) - - call.respond(it.citizen) - } - - get { - if (citizenOrNull === null) { - call.respond(HttpStatusCode.Unauthorized) - } else { - assertCan(VIEW, citizen) - call.respond(citizen) - } - } - - put { - assertCan(CHANGE_PASSWORD, it.citizen) - try { - val content = call.receive() - val currentUser = userRepository.findByCredentials(UserPasswordCredential(citizen.user.username, content.oldPassword)) - val user = it.citizen.user - if (currentUser == null || currentUser.id != user.id) { - call.respond(HttpStatusCode.BadRequest, "Bad password") - } else { - user.plainPassword = content.newPassword - userRepository.changePassword(user) - - call.respond(HttpStatusCode.Created) - } - } catch (e: MissingKotlinParameterException) { - call.respond(HttpStatusCode.BadRequest, "Request format is not correct") - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/routes/CommentArticle.kt b/src/main/kotlin/routes/CommentArticle.kt index 3a430cd..a916591 100644 --- a/src/main/kotlin/routes/CommentArticle.kt +++ b/src/main/kotlin/routes/CommentArticle.kt @@ -3,7 +3,7 @@ package fr.dcproject.routes import fr.dcproject.citizen import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.Citizen +import fr.dcproject.component.citizen.Citizen import fr.dcproject.entity.CommentForUpdate import fr.dcproject.repository.CommentArticle.Sort import fr.dcproject.security.voter.CommentVoter.Action.CREATE diff --git a/src/main/kotlin/routes/CommentConstitution.kt b/src/main/kotlin/routes/CommentConstitution.kt index 1f5f25a..d47dad4 100644 --- a/src/main/kotlin/routes/CommentConstitution.kt +++ b/src/main/kotlin/routes/CommentConstitution.kt @@ -1,7 +1,7 @@ package fr.dcproject.routes import fr.dcproject.citizen -import fr.dcproject.entity.Citizen +import fr.dcproject.component.citizen.Citizen import fr.dcproject.entity.CommentForUpdate import fr.dcproject.entity.ConstitutionRef import fr.dcproject.security.voter.CommentVoter.Action.CREATE diff --git a/src/main/kotlin/routes/Constitution.kt b/src/main/kotlin/routes/Constitution.kt index ab5d151..d1de166 100644 --- a/src/main/kotlin/routes/Constitution.kt +++ b/src/main/kotlin/routes/Constitution.kt @@ -2,7 +2,7 @@ package fr.dcproject.routes import fr.dcproject.citizen import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.CitizenWithUserI +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 diff --git a/src/main/kotlin/routes/FollowArticle.kt b/src/main/kotlin/routes/FollowArticle.kt index 06f3291..d809e9c 100644 --- a/src/main/kotlin/routes/FollowArticle.kt +++ b/src/main/kotlin/routes/FollowArticle.kt @@ -2,7 +2,7 @@ package fr.dcproject.routes import fr.dcproject.citizen import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.Citizen +import fr.dcproject.component.citizen.Citizen import fr.dcproject.entity.FollowForUpdate import fr.dcproject.security.voter.FollowVoter.Action.* import fr.ktorVoter.assertCan diff --git a/src/main/kotlin/routes/FollowConstitution.kt b/src/main/kotlin/routes/FollowConstitution.kt index d5f5601..689c217 100644 --- a/src/main/kotlin/routes/FollowConstitution.kt +++ b/src/main/kotlin/routes/FollowConstitution.kt @@ -1,7 +1,7 @@ package fr.dcproject.routes import fr.dcproject.citizen -import fr.dcproject.entity.CitizenRef +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.entity.ConstitutionRef import fr.dcproject.entity.FollowForUpdate import fr.dcproject.security.voter.FollowVoter.Action.* diff --git a/src/main/kotlin/routes/OpinionArticle.kt b/src/main/kotlin/routes/OpinionArticle.kt index 72491b4..29ef292 100644 --- a/src/main/kotlin/routes/OpinionArticle.kt +++ b/src/main/kotlin/routes/OpinionArticle.kt @@ -2,7 +2,7 @@ package fr.dcproject.routes import fr.dcproject.citizen import fr.dcproject.component.article.ArticleForView -import fr.dcproject.entity.CitizenRef +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.entity.OpinionChoiceRef import fr.dcproject.security.voter.OpinionVoter.Action.CREATE import fr.dcproject.security.voter.OpinionVoter.Action.VIEW @@ -19,7 +19,7 @@ import io.ktor.util.* import org.koin.core.KoinComponent import org.koin.core.get import java.util.* -import fr.dcproject.entity.Citizen as CitizenEntity +import fr.dcproject.component.citizen.Citizen as CitizenEntity import fr.dcproject.repository.OpinionArticle as OpinionArticleRepository @KtorExperimentalLocationsAPI diff --git a/src/main/kotlin/routes/VoteArticle.kt b/src/main/kotlin/routes/VoteArticle.kt index c964796..28c3e9c 100644 --- a/src/main/kotlin/routes/VoteArticle.kt +++ b/src/main/kotlin/routes/VoteArticle.kt @@ -2,7 +2,7 @@ package fr.dcproject.routes import fr.dcproject.citizen import fr.dcproject.component.article.ArticleForView -import fr.dcproject.entity.Citizen +import fr.dcproject.component.citizen.Citizen import fr.dcproject.entity.VoteForUpdate import fr.dcproject.repository.CommentGeneric import fr.dcproject.repository.VoteComment diff --git a/src/main/kotlin/routes/VoteConstitution.kt b/src/main/kotlin/routes/VoteConstitution.kt index ea2869b..ee58a03 100644 --- a/src/main/kotlin/routes/VoteConstitution.kt +++ b/src/main/kotlin/routes/VoteConstitution.kt @@ -1,7 +1,7 @@ package fr.dcproject.routes import fr.dcproject.citizen -import fr.dcproject.entity.Citizen +import fr.dcproject.component.citizen.Citizen import fr.dcproject.entity.VoteForUpdate import fr.dcproject.routes.VoteConstitutionPaths.ConstitutionVoteRequest.Content import fr.dcproject.security.voter.VoteVoter.Action.CREATE diff --git a/src/main/kotlin/routes/Workgroup.kt b/src/main/kotlin/routes/Workgroup.kt index 1789514..3cc128e 100644 --- a/src/main/kotlin/routes/Workgroup.kt +++ b/src/main/kotlin/routes/Workgroup.kt @@ -1,7 +1,7 @@ package fr.dcproject.routes import fr.dcproject.citizen -import fr.dcproject.entity.CitizenRef +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.entity.WorkgroupSimple import fr.dcproject.entity.WorkgroupWithMembersI.Member import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role diff --git a/src/main/kotlin/views/ViewManager.kt b/src/main/kotlin/views/ViewManager.kt index cad702d..a5ce970 100644 --- a/src/main/kotlin/views/ViewManager.kt +++ b/src/main/kotlin/views/ViewManager.kt @@ -1,6 +1,6 @@ package fr.dcproject.views -import fr.dcproject.entity.CitizenI +import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.ViewAggregation import org.elasticsearch.client.Response import org.joda.time.DateTime diff --git a/src/main/kotlin/voter/CitizenVoter.kt b/src/main/kotlin/voter/CitizenVoter.kt deleted file mode 100644 index 4e9182f..0000000 --- a/src/main/kotlin/voter/CitizenVoter.kt +++ /dev/null @@ -1,61 +0,0 @@ -package fr.dcproject.security.voter - -import fr.dcproject.entity.CitizenBasicI -import fr.dcproject.entity.CitizenWithUserI -import fr.dcproject.user -import fr.dcproject.voter.NoRuleDefinedException -import fr.dcproject.voter.NoSubjectDefinedException -import fr.ktorVoter.* -import io.ktor.application.* -import io.ktor.locations.* - -@KtorExperimentalLocationsAPI -class CitizenVoter : Voter { - enum class Action : ActionI { - CREATE, - UPDATE, - VIEW, - DELETE, - CHANGE_PASSWORD - } - - override fun invoke(action: Any, context: ApplicationCall, subject: Any?): VoterResponseI { - if (!((action is Action) - && (subject is CitizenBasicI?))) return abstain() - - val user = context.user - if (action == Action.CREATE && user != null) { - return granted() - } - - if (action == Action.VIEW) { - if (user == null) return denied("You must be connected to view citizen", "citizen.view.connected") - if (subject is CitizenBasicI) { - return if (subject.isDeleted()) denied("You cannot view a deleted citizen", "citizen.view.deleted") - else granted() - } - throw NoRuleDefinedException(action) - } - - if (action == Action.DELETE) { - return denied("You can never deleted a citizen", "citizen.delete.never") - } - - if (action == Action.UPDATE) { - if (user == null) return denied("You must be connected to update Citizen", "citizen.update.notConnected") - if (subject !is CitizenWithUserI) throw NoSubjectDefinedException(action) - return if (subject.user.id == user.id) granted() else denied("You can only update your citizen", "citizen.update.notYours") - } - - if (action == Action.CHANGE_PASSWORD && user != null && subject is CitizenBasicI) { - val userToChange = subject.user - return if (user.id == userToChange.id) { - granted() - } else { - denied("You can only change your password", "citizen.password.notYours") - } - } - - throw NoRuleDefinedException(action) - } -} diff --git a/src/main/kotlin/voter/FollowVoter.kt b/src/main/kotlin/voter/FollowVoter.kt index e0db7e1..43f74a7 100644 --- a/src/main/kotlin/voter/FollowVoter.kt +++ b/src/main/kotlin/voter/FollowVoter.kt @@ -1,7 +1,7 @@ package fr.dcproject.security.voter import fr.dcproject.citizenOrNull -import fr.dcproject.entity.CitizenI +import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.FollowI import fr.dcproject.voter.NoSubjectDefinedException import fr.ktorVoter.* diff --git a/src/test/kotlin/ViewTest.kt b/src/test/kotlin/ViewTest.kt index 2fddc8b..88c2437 100644 --- a/src/test/kotlin/ViewTest.kt +++ b/src/test/kotlin/ViewTest.kt @@ -1,7 +1,7 @@ import fr.dcproject.Env import fr.dcproject.component.article.ArticleRefVersioning import fr.dcproject.component.article.ArticleViewManager -import fr.dcproject.entity.CitizenRef +import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.module import io.ktor.locations.* import io.ktor.server.testing.* diff --git a/src/test/kotlin/feature/ArticleSteps.kt b/src/test/kotlin/feature/ArticleSteps.kt index ab1f900..2fad5a4 100644 --- a/src/test/kotlin/feature/ArticleSteps.kt +++ b/src/test/kotlin/feature/ArticleSteps.kt @@ -3,7 +3,11 @@ package feature import fr.dcproject.component.article.ArticleForUpdate import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRepository -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.entity.CommentForUpdate +import fr.dcproject.entity.WorkgroupRef import fr.dcproject.repository.CommentArticle import fr.dcproject.utils.toUUID import io.cucumber.datatable.DataTable @@ -13,7 +17,6 @@ import org.koin.test.KoinTest import org.koin.test.get import java.util.* import fr.dcproject.entity.User as UserEntity -import fr.dcproject.repository.Citizen as CitizenRepository class ArticleSteps : En, KoinTest { init { diff --git a/src/test/kotlin/feature/CitizenSteps.kt b/src/test/kotlin/feature/CitizenSteps.kt index 0db6c35..fbe62a6 100644 --- a/src/test/kotlin/feature/CitizenSteps.kt +++ b/src/test/kotlin/feature/CitizenSteps.kt @@ -1,7 +1,8 @@ package feature -import fr.dcproject.entity.Citizen -import fr.dcproject.entity.CitizenI +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.User import io.cucumber.datatable.DataTable import io.cucumber.java8.En @@ -9,7 +10,6 @@ import org.joda.time.DateTime import org.koin.test.KoinTest import org.koin.test.get import java.util.* -import fr.dcproject.repository.Citizen as CitizenRepository class CitizenSteps : En, KoinTest { init { diff --git a/src/test/kotlin/feature/ConstitutionSteps.kt b/src/test/kotlin/feature/ConstitutionSteps.kt index a054a5c..0f19225 100644 --- a/src/test/kotlin/feature/ConstitutionSteps.kt +++ b/src/test/kotlin/feature/ConstitutionSteps.kt @@ -1,7 +1,13 @@ package feature import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.component.citizen.CitizenWithUserI +import fr.dcproject.entity.CommentForUpdate +import fr.dcproject.entity.ConstitutionRef +import fr.dcproject.entity.ConstitutionSimple import fr.dcproject.repository.CommentConstitution import fr.dcproject.utils.toUUID import io.cucumber.datatable.DataTable @@ -11,7 +17,6 @@ import org.koin.test.KoinTest import org.koin.test.get import java.util.* import fr.dcproject.entity.User as UserEntity -import fr.dcproject.repository.Citizen as CitizenRepository import fr.dcproject.repository.Constitution as ConstitutionRepository class ConstitutionSteps : En, KoinTest { diff --git a/src/test/kotlin/feature/FollowSteps.kt b/src/test/kotlin/feature/FollowSteps.kt index 3df0799..eade2cf 100644 --- a/src/test/kotlin/feature/FollowSteps.kt +++ b/src/test/kotlin/feature/FollowSteps.kt @@ -1,13 +1,13 @@ package feature import fr.dcproject.component.article.ArticleRef +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.ConstitutionRef import fr.dcproject.entity.FollowForUpdate import fr.dcproject.utils.toUUID import io.cucumber.java8.En import org.koin.test.KoinTest import org.koin.test.get -import fr.dcproject.repository.Citizen as CitizenRepository import fr.dcproject.repository.FollowArticle as FollowArticleRepository import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository diff --git a/src/test/kotlin/feature/KtorServerAuthSteps.kt b/src/test/kotlin/feature/KtorServerAuthSteps.kt index df19dba..a02d422 100644 --- a/src/test/kotlin/feature/KtorServerAuthSteps.kt +++ b/src/test/kotlin/feature/KtorServerAuthSteps.kt @@ -2,11 +2,11 @@ package feature import com.auth0.jwt.JWT import fr.dcproject.JwtConfig +import fr.dcproject.component.citizen.CitizenRepository import io.cucumber.java8.En import io.ktor.http.* import org.koin.test.KoinTest import org.koin.test.get -import fr.dcproject.repository.Citizen as CitizenRepository class KtorServerAuthSteps : En, KoinTest { init { diff --git a/src/test/kotlin/feature/OpinionSteps.kt b/src/test/kotlin/feature/OpinionSteps.kt index c3ba4c9..1a22833 100644 --- a/src/test/kotlin/feature/OpinionSteps.kt +++ b/src/test/kotlin/feature/OpinionSteps.kt @@ -2,6 +2,7 @@ package feature import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRepository +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.OpinionChoice import fr.dcproject.entity.OpinionForUpdate import fr.dcproject.utils.toUUID @@ -10,7 +11,6 @@ import io.cucumber.java8.En import org.koin.test.KoinTest import org.koin.test.get import java.util.* -import fr.dcproject.repository.Citizen as CitizenRepository import fr.dcproject.repository.OpinionArticle as OpinionRepository import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository diff --git a/src/test/kotlin/feature/VoteSteps.kt b/src/test/kotlin/feature/VoteSteps.kt index 466103d..c93ac2c 100644 --- a/src/test/kotlin/feature/VoteSteps.kt +++ b/src/test/kotlin/feature/VoteSteps.kt @@ -1,13 +1,13 @@ package feature import fr.dcproject.component.article.ArticleRepository +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.VoteForUpdate import fr.dcproject.utils.toUUID import io.cucumber.java8.En import org.koin.test.KoinTest import org.koin.test.get import java.util.* -import fr.dcproject.repository.Citizen as CitizenRepository import fr.dcproject.repository.VoteArticle as VoteRepository class VoteSteps : En, KoinTest { diff --git a/src/test/kotlin/feature/WorkgroupSteps.kt b/src/test/kotlin/feature/WorkgroupSteps.kt index 72be884..b87282c 100644 --- a/src/test/kotlin/feature/WorkgroupSteps.kt +++ b/src/test/kotlin/feature/WorkgroupSteps.kt @@ -1,5 +1,9 @@ package feature +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.entity.* import fr.dcproject.entity.WorkgroupWithMembersI.Member import fr.dcproject.utils.toUUID @@ -10,7 +14,6 @@ import org.junit.Assert import org.koin.test.KoinTest import org.koin.test.get import java.util.* -import fr.dcproject.repository.Citizen as CitizenRepository import fr.dcproject.repository.Workgroup as WorkgroupRepository class WorkgroupSteps : En, KoinTest { diff --git a/src/test/kotlin/security/voter/ArticleVoterTest.kt b/src/test/kotlin/security/voter/ArticleVoterTest.kt index 736730d..676ab18 100644 --- a/src/test/kotlin/security/voter/ArticleVoterTest.kt +++ b/src/test/kotlin/security/voter/ArticleVoterTest.kt @@ -2,8 +2,8 @@ package fr.dcproject.security.voter import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleVoter -import fr.dcproject.entity.CitizenCart -import fr.dcproject.entity.CitizenI +import fr.dcproject.component.citizen.CitizenCart +import fr.dcproject.component.citizen.CitizenI import fr.dcproject.entity.User import fr.dcproject.entity.UserI import fr.dcproject.voter.Vote.DENIED diff --git a/src/test/kotlin/security/voter/CitizenVoterTest.kt b/src/test/kotlin/security/voter/CitizenVoterTest.kt index 8f5124b..990f24e 100644 --- a/src/test/kotlin/security/voter/CitizenVoterTest.kt +++ b/src/test/kotlin/security/voter/CitizenVoterTest.kt @@ -1,22 +1,19 @@ package fr.dcproject.security.voter -import fr.dcproject.entity.CitizenBasic -import fr.dcproject.entity.CitizenI +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.entity.User import fr.dcproject.entity.UserI -import fr.dcproject.user -import fr.ktorVoter.* -import io.ktor.application.* +import fr.dcproject.voter.Vote.DENIED +import fr.dcproject.voter.Vote.GRANTED import io.ktor.locations.* -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 import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance -import org.junit.jupiter.api.assertThrows @KtorExperimentalLocationsAPI @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -57,78 +54,51 @@ class CitizenVoterTest { } @Test - fun `support citizen`(): Unit = CitizenVoter().run { - val p = object : ActionI {} - mockk { - every { user } returns tesla.user - }.let { - this(CitizenVoter.Action.VIEW, it, einstein).vote `should be` Vote.GRANTED - this(p, it, einstein).vote `should be` Vote.ABSTAIN - } + fun `can be view the citizen`() { + CitizenVoter() + .canView(subject = einstein, connectedCitizen = tesla) + .vote `should be` GRANTED } @Test - fun `can be view the citizen`(): Unit = listOf(CitizenVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(CitizenVoter.Action.VIEW, it, einstein) `should be` true - } + fun `can be view the citizen list`() { + CitizenVoter() + .canView(subjects = listOf(tesla, einstein), connectedCitizen = einstein) + .vote `should be` GRANTED } @Test - fun `can be view the citizen list`(): Unit = listOf(CitizenVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - canAll(CitizenVoter.Action.VIEW, it, listOf(einstein, tesla)) `should be` true - } + fun `can not view deleted citizen`() { + CitizenVoter() + .canView(subject = curie, connectedCitizen = tesla) + .vote `should be` DENIED } @Test - fun `can not view deleted citizen`(): Unit = listOf(CitizenVoter()).run { - mockk { - every { user } returns tesla.user - }.let { - can(CitizenVoter.Action.VIEW, it, curie) `should be` false - } + fun `can be update itself`() { + CitizenVoter() + .canUpdate(subject = einstein, connectedCitizen = einstein) + .vote `should be` GRANTED } @Test - fun `can be update itself`(): Unit = listOf(CitizenVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - can(CitizenVoter.Action.UPDATE, it, einstein) `should be` true - } + fun `can not be update other citizen`() { + CitizenVoter() + .canUpdate(subject = tesla, connectedCitizen = einstein) + .vote `should be` DENIED } @Test - fun `can not be update other citizen`(): Unit = listOf(CitizenVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - assertThrows { - assertCan(CitizenVoter.Action.UPDATE, it, tesla) - } - } + fun `can be change password of itself`() { + CitizenVoter() + .canChangePassword(subject = einstein, connectedCitizen = einstein) + .vote `should be` GRANTED } @Test - fun `can be change password of itself`(): Unit = listOf(CitizenVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - can(CitizenVoter.Action.CHANGE_PASSWORD, it, einstein) `should be` true - } - } - - @Test - fun `can not be change password of other citizen`(): Unit = listOf(CitizenVoter()).run { - mockk { - every { user } returns einstein.user - }.let { - can(CitizenVoter.Action.CHANGE_PASSWORD, it, tesla) `should be` false - } + fun `can not be change password of other citizen`() { + CitizenVoter() + .canChangePassword(subject = tesla, connectedCitizen = einstein) + .vote `should be` DENIED } } \ No newline at end of file diff --git a/src/test/kotlin/security/voter/CommentVoterTest.kt b/src/test/kotlin/security/voter/CommentVoterTest.kt index be751e4..949de64 100644 --- a/src/test/kotlin/security/voter/CommentVoterTest.kt +++ b/src/test/kotlin/security/voter/CommentVoterTest.kt @@ -3,10 +3,15 @@ package fr.dcproject.security.voter import fr.dcproject.citizenOrNull import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenCart +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.CommentForUpdate +import fr.dcproject.entity.CommentForView +import fr.dcproject.entity.User +import fr.dcproject.entity.UserI import fr.dcproject.voter.NoSubjectDefinedException import fr.ktorVoter.* -import fr.ktorVoter.Vote import fr.postgresjson.connexion.Paginated import io.ktor.application.* import io.ktor.locations.* diff --git a/src/test/kotlin/security/voter/FollowVoterTest.kt b/src/test/kotlin/security/voter/FollowVoterTest.kt index 64e11a1..836da2a 100644 --- a/src/test/kotlin/security/voter/FollowVoterTest.kt +++ b/src/test/kotlin/security/voter/FollowVoterTest.kt @@ -2,7 +2,13 @@ package fr.dcproject.security.voter import fr.dcproject.citizenOrNull import fr.dcproject.component.article.ArticleForView -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenCart +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.Follow +import fr.dcproject.entity.User +import fr.dcproject.entity.UserI import fr.dcproject.voter.NoSubjectDefinedException import fr.ktorVoter.ActionI import fr.ktorVoter.Vote diff --git a/src/test/kotlin/security/voter/OpinionChoiceVoterTest.kt b/src/test/kotlin/security/voter/OpinionChoiceVoterTest.kt index 1e60c0e..3f5fad6 100644 --- a/src/test/kotlin/security/voter/OpinionChoiceVoterTest.kt +++ b/src/test/kotlin/security/voter/OpinionChoiceVoterTest.kt @@ -1,7 +1,12 @@ package fr.dcproject.security.voter import fr.dcproject.component.article.ArticleForView -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenCart +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.OpinionChoice +import fr.dcproject.entity.User +import fr.dcproject.entity.UserI import fr.dcproject.user import fr.ktorVoter.ActionI import fr.ktorVoter.Vote diff --git a/src/test/kotlin/security/voter/OpinionVoterTest.kt b/src/test/kotlin/security/voter/OpinionVoterTest.kt index 8fe1de9..42494eb 100644 --- a/src/test/kotlin/security/voter/OpinionVoterTest.kt +++ b/src/test/kotlin/security/voter/OpinionVoterTest.kt @@ -1,11 +1,16 @@ package fr.dcproject.security.voter import fr.dcproject.component.article.ArticleForView -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenCart +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.Opinion +import fr.dcproject.entity.OpinionChoice +import fr.dcproject.entity.User +import fr.dcproject.entity.UserI import fr.dcproject.user import fr.dcproject.voter.NoSubjectDefinedException import fr.ktorVoter.* -import fr.ktorVoter.Vote import io.ktor.application.* import io.ktor.locations.* import io.mockk.every diff --git a/src/test/kotlin/security/voter/VoteVoterTest.kt b/src/test/kotlin/security/voter/VoteVoterTest.kt index 22ee87d..499f987 100644 --- a/src/test/kotlin/security/voter/VoteVoterTest.kt +++ b/src/test/kotlin/security/voter/VoteVoterTest.kt @@ -3,7 +3,13 @@ package fr.dcproject.security.voter import fr.dcproject.citizenOrNull import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleRef -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenCart +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.User +import fr.dcproject.entity.UserI +import fr.dcproject.entity.VoteForUpdate import fr.dcproject.voter.NoSubjectDefinedException import fr.ktorVoter.ActionI import fr.ktorVoter.Vote diff --git a/src/test/kotlin/security/voter/WorkgroupVoterTest.kt b/src/test/kotlin/security/voter/WorkgroupVoterTest.kt index 2d65e44..ec32ad3 100644 --- a/src/test/kotlin/security/voter/WorkgroupVoterTest.kt +++ b/src/test/kotlin/security/voter/WorkgroupVoterTest.kt @@ -1,7 +1,13 @@ package fr.dcproject.security.voter import fr.dcproject.component.article.ArticleForView -import fr.dcproject.entity.* +import fr.dcproject.component.citizen.CitizenBasic +import fr.dcproject.component.citizen.CitizenCart +import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.User +import fr.dcproject.entity.UserI +import fr.dcproject.entity.WorkgroupRef +import fr.dcproject.entity.WorkgroupWithMembersI import fr.dcproject.user import fr.dcproject.voter.NoSubjectDefinedException import fr.ktorVoter.ActionI