From c92d0b56405f52591ab2b6fc194737a958e5bcb4 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Fri, 22 Jan 2021 21:11:04 +0100 Subject: [PATCH] Move opinions to component --- src/main/kotlin/application/Application.kt | 6 +- src/main/kotlin/application/Converters.kt | 7 +- src/main/kotlin/application/KoinModule.kt | 8 +- src/main/kotlin/component/article/Article.kt | 6 +- .../component/article/routes/GetOneArticle.kt | 2 +- .../opinion}/OpinionChoiceVoter.kt | 4 +- .../opinion/OpinionRepository.kt} | 14 +-- .../opinion}/OpinionVoter.kt | 4 +- .../opinion}/dto/Opinionable.kt | 4 +- .../{ => component/opinion}/entity/Opinion.kt | 6 +- .../opinion}/entity/OpinionChoice.kt | 2 +- .../opinion}/entity/Opinionable.kt | 2 +- .../opinion/routes/GetCitizenOpinions.kt | 38 ++++++++ .../opinion/routes/GetMyOpinionsArticle.kt | 37 ++++++++ .../opinion/routes/GetOpinionChoice.kt | 26 ++++++ .../opinion/routes/GetOpinionChoices.kt | 27 ++++++ .../opinion/routes/OpinionArticle.kt | 50 ++++++++++ .../component/opinion/routes/install.kt | 22 +++++ src/main/kotlin/entity/Extra.kt | 1 + src/main/kotlin/routes/OpinionArticle.kt | 92 ------------------- src/main/kotlin/routes/OpinionChoice.kt | 38 -------- src/test/kotlin/steps/OpinionSteps.kt | 8 +- .../unit/voter/OpinionChoiceVoterTest.kt | 4 +- .../kotlin/unit/voter/OpinionVoterTest.kt | 6 +- 24 files changed, 244 insertions(+), 170 deletions(-) rename src/main/kotlin/{voter => component/opinion}/OpinionChoiceVoter.kt (80%) rename src/main/kotlin/{repository/Opinion.kt => component/opinion/OpinionRepository.kt} (88%) rename src/main/kotlin/{voter => component/opinion}/OpinionVoter.kt (94%) rename src/main/kotlin/{ => component/opinion}/dto/Opinionable.kt (54%) rename src/main/kotlin/{ => component/opinion}/entity/Opinion.kt (88%) rename src/main/kotlin/{ => component/opinion}/entity/OpinionChoice.kt (92%) rename src/main/kotlin/{ => component/opinion}/entity/Opinionable.kt (84%) create mode 100644 src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt create mode 100644 src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt create mode 100644 src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt create mode 100644 src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt create mode 100644 src/main/kotlin/component/opinion/routes/OpinionArticle.kt create mode 100644 src/main/kotlin/component/opinion/routes/install.kt delete mode 100644 src/main/kotlin/routes/OpinionArticle.kt delete mode 100644 src/main/kotlin/routes/OpinionChoice.kt diff --git a/src/main/kotlin/application/Application.kt b/src/main/kotlin/application/Application.kt index 1b85d03..4a4bf86 100644 --- a/src/main/kotlin/application/Application.kt +++ b/src/main/kotlin/application/Application.kt @@ -18,6 +18,7 @@ import fr.dcproject.component.comment.article.routes.installCommentArticleRoutes import fr.dcproject.component.comment.generic.routes.installCommentRoutes import fr.dcproject.component.follow.routes.article.installFollowArticleRoutes import fr.dcproject.component.follow.routes.constitution.installFollowConstitutionRoutes +import fr.dcproject.component.opinion.routes.installOpinionRoutes import fr.dcproject.component.views.ConfigViews import fr.dcproject.component.workgroup.routes.installWorkgroupRoutes import fr.dcproject.event.EventNotification @@ -26,8 +27,6 @@ import fr.dcproject.routes.commentConstitution import fr.dcproject.routes.constitution import fr.dcproject.routes.definition import fr.dcproject.routes.notificationArticle -import fr.dcproject.routes.opinionArticle -import fr.dcproject.routes.opinionChoice import fr.dcproject.routes.voteArticle import fr.dcproject.routes.voteConstitution import fr.dcproject.voter.VoterDeniedException @@ -140,6 +139,7 @@ fun Application.module(env: Env = PROD) { installFollowArticleRoutes() installFollowConstitutionRoutes() installWorkgroupRoutes() + installOpinionRoutes() authenticate(optional = true) { /* TODO */ @@ -147,8 +147,6 @@ fun Application.module(env: Env = PROD) { commentConstitution(get(), get()) voteArticle(get(), get(), get(), get()) voteConstitution(get(), get()) - opinionArticle(get(), get()) - opinionChoice(get(), get()) definition() } diff --git a/src/main/kotlin/application/Converters.kt b/src/main/kotlin/application/Converters.kt index ba651ce..504f464 100644 --- a/src/main/kotlin/application/Converters.kt +++ b/src/main/kotlin/application/Converters.kt @@ -8,12 +8,13 @@ import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.component.comment.generic.CommentRef +import fr.dcproject.component.opinion.entity.OpinionChoice import fr.dcproject.component.workgroup.Workgroup import fr.dcproject.component.workgroup.WorkgroupRef import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.entity.Constitution import fr.dcproject.entity.ConstitutionRef -import fr.dcproject.repository.OpinionChoice +import fr.dcproject.repository.OpinionChoiceRepository import io.ktor.features.DataConversion import io.ktor.features.NotFoundException import io.ktor.util.KtorExperimentalAPI @@ -99,11 +100,11 @@ val converters: ConverterDeclaration = { } } - convert { + convert { decode { values, _ -> val id = values.singleOrNull()?.let { UUID.fromString(it) } ?: throw InternalError("Cannot convert $values to UUID") - get().findOpinionChoiceById(id) + get().findOpinionChoiceById(id) ?: throw NotFoundException("OpinionChoice $values not found") } } diff --git a/src/main/kotlin/application/KoinModule.kt b/src/main/kotlin/application/KoinModule.kt index 3ef51bf..e1efbd8 100644 --- a/src/main/kotlin/application/KoinModule.kt +++ b/src/main/kotlin/application/KoinModule.kt @@ -18,6 +18,8 @@ import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.component.comment.article.CommentArticleRepository import fr.dcproject.component.comment.generic.CommentVoter import fr.dcproject.component.follow.FollowVoter +import fr.dcproject.component.opinion.OpinionChoiceVoter +import fr.dcproject.component.opinion.OpinionVoter import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.event.publisher.Publisher @@ -25,8 +27,6 @@ import fr.dcproject.messages.Mailer import fr.dcproject.messages.NotificationEmailSender import fr.dcproject.repository.CommentConstitutionRepository import fr.dcproject.security.voter.ConstitutionVoter -import fr.dcproject.security.voter.OpinionChoiceVoter -import fr.dcproject.security.voter.OpinionVoter import fr.dcproject.security.voter.VoteVoter import fr.postgresjson.connexion.Connection import fr.postgresjson.connexion.Requester @@ -44,8 +44,8 @@ import fr.dcproject.component.comment.generic.CommentRepository as CommentGeneri import fr.dcproject.component.follow.FollowArticleRepository as FollowArticleRepository import fr.dcproject.component.follow.FollowConstitutionRepository as FollowConstitutionRepository import fr.dcproject.repository.Constitution as ConstitutionRepository -import fr.dcproject.repository.OpinionArticle as OpinionArticleRepository -import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository +import fr.dcproject.repository.OpinionChoiceRepository as OpinionChoiceRepository +import fr.dcproject.repository.OpinionRepositoryArticle as OpinionArticleRepository import fr.dcproject.repository.VoteArticle as VoteArticleRepository import fr.dcproject.repository.VoteComment as VoteCommentRepository import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository diff --git a/src/main/kotlin/component/article/Article.kt b/src/main/kotlin/component/article/Article.kt index eef9729..fb56e2e 100644 --- a/src/main/kotlin/component/article/Article.kt +++ b/src/main/kotlin/component/article/Article.kt @@ -6,15 +6,15 @@ import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenCartI import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.opinion.entity.Opinionable +import fr.dcproject.component.opinion.entity.OpinionableImp +import fr.dcproject.component.opinion.entity.Opinions import fr.dcproject.component.workgroup.WorkgroupCart import fr.dcproject.component.workgroup.WorkgroupCartI import fr.dcproject.component.workgroup.WorkgroupRef import fr.dcproject.component.workgroup.WorkgroupSimple import fr.dcproject.entity.CreatedBy import fr.dcproject.entity.CreatedByImp -import fr.dcproject.entity.Opinionable -import fr.dcproject.entity.OpinionableImp -import fr.dcproject.entity.Opinions import fr.dcproject.entity.TargetI import fr.dcproject.entity.TargetRef import fr.dcproject.entity.VersionableRef diff --git a/src/main/kotlin/component/article/routes/GetOneArticle.kt b/src/main/kotlin/component/article/routes/GetOneArticle.kt index f178116..af71ed0 100644 --- a/src/main/kotlin/component/article/routes/GetOneArticle.kt +++ b/src/main/kotlin/component/article/routes/GetOneArticle.kt @@ -6,8 +6,8 @@ import fr.dcproject.component.article.ArticleViewManager import fr.dcproject.component.article.ArticleVoter import fr.dcproject.component.article.routes.GetOneArticle.ArticleRequest.Output import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.opinion.dto.Opinionable import fr.dcproject.dto.CreatedAt -import fr.dcproject.dto.Opinionable import fr.dcproject.dto.Versionable import fr.dcproject.dto.Viewable import fr.dcproject.dto.Votable diff --git a/src/main/kotlin/voter/OpinionChoiceVoter.kt b/src/main/kotlin/component/opinion/OpinionChoiceVoter.kt similarity index 80% rename from src/main/kotlin/voter/OpinionChoiceVoter.kt rename to src/main/kotlin/component/opinion/OpinionChoiceVoter.kt index b2eedf7..24a9428 100644 --- a/src/main/kotlin/voter/OpinionChoiceVoter.kt +++ b/src/main/kotlin/component/opinion/OpinionChoiceVoter.kt @@ -1,7 +1,7 @@ -package fr.dcproject.security.voter +package fr.dcproject.component.opinion import fr.dcproject.component.citizen.CitizenI -import fr.dcproject.entity.OpinionChoice +import fr.dcproject.component.opinion.entity.OpinionChoice import fr.dcproject.voter.Voter import fr.dcproject.voter.VoterResponse diff --git a/src/main/kotlin/repository/Opinion.kt b/src/main/kotlin/component/opinion/OpinionRepository.kt similarity index 88% rename from src/main/kotlin/repository/Opinion.kt rename to src/main/kotlin/component/opinion/OpinionRepository.kt index eac1f93..b30b472 100644 --- a/src/main/kotlin/repository/Opinion.kt +++ b/src/main/kotlin/component/opinion/OpinionRepository.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.OpinionForUpdate +import fr.dcproject.component.opinion.entity.OpinionForUpdate import fr.dcproject.entity.TargetRef import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester @@ -10,11 +10,11 @@ import fr.postgresjson.repository.RepositoryI import net.pearx.kasechange.toSnakeCase import java.util.UUID 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 +import fr.dcproject.component.opinion.entity.Opinion as OpinionEntity +import fr.dcproject.component.opinion.entity.OpinionArticle as OpinionArticleEntity +import fr.dcproject.component.opinion.entity.OpinionChoice as OpinionChoiceEntity -open class OpinionChoice(override val requester: Requester) : RepositoryI { +open class OpinionChoiceRepository(override val requester: Requester) : RepositoryI { /** * find all opinion choices * can be filtered by target compatibility @@ -61,7 +61,7 @@ open class OpinionChoice(override val requester: Requester) : RepositoryI { )!! } -abstract class Opinion(requester: Requester) : OpinionChoice(requester) { +abstract class OpinionRepository(requester: Requester) : OpinionChoiceRepository(requester) { /** * Create an Opinion on target (article,...) */ @@ -133,7 +133,7 @@ abstract class Opinion(requester: Requester) : OpinionChoice(requ } } -class OpinionArticle(requester: Requester) : Opinion(requester) { +class OpinionRepositoryArticle(requester: Requester) : OpinionRepository(requester) { /** * Update Opinions on Article (Delete old one) */ diff --git a/src/main/kotlin/voter/OpinionVoter.kt b/src/main/kotlin/component/opinion/OpinionVoter.kt similarity index 94% rename from src/main/kotlin/voter/OpinionVoter.kt rename to src/main/kotlin/component/opinion/OpinionVoter.kt index dd4e5c8..e72d192 100644 --- a/src/main/kotlin/voter/OpinionVoter.kt +++ b/src/main/kotlin/component/opinion/OpinionVoter.kt @@ -1,8 +1,8 @@ -package fr.dcproject.security.voter +package fr.dcproject.component.opinion import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.opinion.entity.OpinionI import fr.dcproject.entity.HasTarget -import fr.dcproject.entity.OpinionI import fr.dcproject.voter.Voter import fr.dcproject.voter.VoterResponse import fr.postgresjson.entity.EntityCreatedBy diff --git a/src/main/kotlin/dto/Opinionable.kt b/src/main/kotlin/component/opinion/dto/Opinionable.kt similarity index 54% rename from src/main/kotlin/dto/Opinionable.kt rename to src/main/kotlin/component/opinion/dto/Opinionable.kt index 52ab9c6..50ae170 100644 --- a/src/main/kotlin/dto/Opinionable.kt +++ b/src/main/kotlin/component/opinion/dto/Opinionable.kt @@ -1,11 +1,11 @@ -package fr.dcproject.dto +package fr.dcproject.component.opinion.dto typealias Opinions = Map interface Opinionable { val opinions: Opinions - class Imp(parent: fr.dcproject.entity.Opinionable) : Opinionable { + class Imp(parent: fr.dcproject.component.opinion.entity.Opinionable) : Opinionable { override val opinions: Opinions = parent.opinions } } diff --git a/src/main/kotlin/entity/Opinion.kt b/src/main/kotlin/component/opinion/entity/Opinion.kt similarity index 88% rename from src/main/kotlin/entity/Opinion.kt rename to src/main/kotlin/component/opinion/entity/Opinion.kt index ec5bbbc..b3eba62 100644 --- a/src/main/kotlin/entity/Opinion.kt +++ b/src/main/kotlin/component/opinion/entity/Opinion.kt @@ -1,10 +1,14 @@ -package fr.dcproject.entity +package fr.dcproject.component.opinion.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.dcproject.entity.ExtraI +import fr.dcproject.entity.HasTarget +import fr.dcproject.entity.TargetI +import fr.dcproject.entity.TargetRef import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.EntityCreatedAtImp import fr.postgresjson.entity.EntityCreatedBy diff --git a/src/main/kotlin/entity/OpinionChoice.kt b/src/main/kotlin/component/opinion/entity/OpinionChoice.kt similarity index 92% rename from src/main/kotlin/entity/OpinionChoice.kt rename to src/main/kotlin/component/opinion/entity/OpinionChoice.kt index 2a50da5..660a4ca 100644 --- a/src/main/kotlin/entity/OpinionChoice.kt +++ b/src/main/kotlin/component/opinion/entity/OpinionChoice.kt @@ -1,4 +1,4 @@ -package fr.dcproject.entity +package fr.dcproject.component.opinion.entity import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.EntityCreatedAtImp diff --git a/src/main/kotlin/entity/Opinionable.kt b/src/main/kotlin/component/opinion/entity/Opinionable.kt similarity index 84% rename from src/main/kotlin/entity/Opinionable.kt rename to src/main/kotlin/component/opinion/entity/Opinionable.kt index 55eb2f2..61a2684 100644 --- a/src/main/kotlin/entity/Opinionable.kt +++ b/src/main/kotlin/component/opinion/entity/Opinionable.kt @@ -1,4 +1,4 @@ -package fr.dcproject.entity +package fr.dcproject.component.opinion.entity typealias Opinions = Map typealias OpinionsMutable = MutableMap diff --git a/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt new file mode 100644 index 0000000..76d2544 --- /dev/null +++ b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt @@ -0,0 +1,38 @@ +package fr.dcproject.component.opinion.routes + +import fr.dcproject.component.article.ArticleRef +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.opinion.entity.Opinion +import fr.dcproject.utils.toUUID +import fr.dcproject.voter.assert +import io.ktor.application.call +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.ktor.locations.Location +import io.ktor.locations.get +import io.ktor.response.respond +import io.ktor.routing.Route +import org.koin.core.KoinComponent +import java.util.UUID +import fr.dcproject.component.citizen.Citizen as CitizenEntity +import fr.dcproject.repository.OpinionRepositoryArticle as OpinionArticleRepository + +@KtorExperimentalLocationsAPI +object GetCitizenOpinions { + /** + * Get all Opinion of citizen on targets by target ids + */ + @Location("/citizens/{citizen}/opinions") + class CitizenOpinions(val citizen: CitizenEntity, id: List) : KoinComponent { + val id: List = id.toUUID() + } + + fun Route.getCitizenOpinions(repo: OpinionArticleRepository, voter: OpinionVoter) { + get { + val opinionsEntities: List> = repo.findCitizenOpinionsByTargets(it.citizen, it.id) + voter.assert { canView(opinionsEntities, citizenOrNull) } + + call.respond(opinionsEntities) + } + } +} diff --git a/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt b/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt new file mode 100644 index 0000000..67b7cdb --- /dev/null +++ b/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt @@ -0,0 +1,37 @@ +package fr.dcproject.component.opinion.routes + +import fr.dcproject.component.auth.citizen +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.routes.PaginatedRequest +import fr.dcproject.routes.PaginatedRequestI +import fr.dcproject.voter.assert +import io.ktor.application.call +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.ktor.locations.Location +import io.ktor.locations.get +import io.ktor.response.respond +import io.ktor.routing.Route +import fr.dcproject.repository.OpinionRepositoryArticle as OpinionArticleRepository + +@KtorExperimentalLocationsAPI +object GetMyOpinionsArticle { + /** + * Get paginated opinions of citizen for all articles + */ + @Location("/citizens/{citizen}/opinions/articles") + class CitizenOpinionsArticleRequest( + val citizen: CitizenRef, + page: Int = 1, + limit: Int = 50 + ) : PaginatedRequestI by PaginatedRequest(page, limit) + + fun Route.getMyOpinionsArticle(repo: OpinionArticleRepository, voter: OpinionVoter) { + get { + val opinions = repo.findCitizenOpinions(citizen, it.page, it.limit) + voter.assert { canView(opinions.result, citizenOrNull) } + call.respond(opinions) + } + } +} diff --git a/src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt b/src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt new file mode 100644 index 0000000..fb83c69 --- /dev/null +++ b/src/main/kotlin/component/opinion/routes/GetOpinionChoice.kt @@ -0,0 +1,26 @@ +package fr.dcproject.component.opinion.routes + +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.opinion.OpinionChoiceVoter +import fr.dcproject.component.opinion.entity.OpinionChoice +import fr.dcproject.voter.assert +import io.ktor.application.call +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.ktor.locations.Location +import io.ktor.locations.get +import io.ktor.response.respond +import io.ktor.routing.Route + +@KtorExperimentalLocationsAPI +object GetOpinionChoice { + @Location("/opinions/{opinionChoice}") + class OpinionChoiceRequest(val opinionChoice: OpinionChoice) + + fun Route.getOpinionChoice(voter: OpinionChoiceVoter) { + get { + voter.assert { canView(it.opinionChoice, citizenOrNull) } + + call.respond(it.opinionChoice) + } + } +} diff --git a/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt b/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt new file mode 100644 index 0000000..fd43d17 --- /dev/null +++ b/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt @@ -0,0 +1,27 @@ +package fr.dcproject.component.opinion.routes + +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.opinion.OpinionChoiceVoter +import fr.dcproject.voter.assert +import io.ktor.application.call +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.ktor.locations.Location +import io.ktor.locations.get +import io.ktor.response.respond +import io.ktor.routing.Route +import fr.dcproject.repository.OpinionChoiceRepository as OpinionChoiceRepository + +@KtorExperimentalLocationsAPI +object GetOpinionChoices { + @Location("/opinions") + class OpinionChoicesRequest(val targets: List = emptyList()) + + fun Route.getOpinionChoices(repo: OpinionChoiceRepository, voter: OpinionChoiceVoter) { + get { + val opinionChoices = repo.findOpinionsChoices(it.targets) + voter.assert { canView(opinionChoices, citizenOrNull) } + + call.respond(opinionChoices) + } + } +} diff --git a/src/main/kotlin/component/opinion/routes/OpinionArticle.kt b/src/main/kotlin/component/opinion/routes/OpinionArticle.kt new file mode 100644 index 0000000..6225bff --- /dev/null +++ b/src/main/kotlin/component/opinion/routes/OpinionArticle.kt @@ -0,0 +1,50 @@ +package fr.dcproject.component.opinion.routes + +import fr.dcproject.component.article.ArticleForView +import fr.dcproject.component.auth.citizen +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.opinion.entity.OpinionChoiceRef +import fr.dcproject.component.opinion.entity.OpinionForUpdate +import fr.dcproject.utils.toUUID +import fr.dcproject.voter.assert +import io.ktor.application.call +import io.ktor.http.HttpStatusCode +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.ktor.locations.Location +import io.ktor.locations.put +import io.ktor.request.receive +import io.ktor.response.respond +import io.ktor.routing.Route +import java.util.UUID +import fr.dcproject.repository.OpinionRepositoryArticle as OpinionArticleRepository + +@KtorExperimentalLocationsAPI +object OpinionArticle { + /** + * Put an opinion on one article + */ + @Location("/articles/{article}/opinions") + class ArticleOpinion(val article: ArticleForView) { + class Body(ids: List) { + val ids: List = ids.map { it.toUUID() } + } + } + + fun Route.setOpinionOnArticle(repo: OpinionArticleRepository, voter: OpinionVoter) { + put { + call.receive().ids.map { id -> + OpinionForUpdate( + choice = OpinionChoiceRef(id), + target = it.article, + createdBy = citizen + ) + }.let { opinions -> + voter.assert { canCreate(opinions, citizenOrNull) } + repo.updateOpinions(opinions) + }.let { + call.respond(HttpStatusCode.Created, it) + } + } + } +} diff --git a/src/main/kotlin/component/opinion/routes/install.kt b/src/main/kotlin/component/opinion/routes/install.kt new file mode 100644 index 0000000..59851a1 --- /dev/null +++ b/src/main/kotlin/component/opinion/routes/install.kt @@ -0,0 +1,22 @@ +package fr.dcproject.component.opinion.routes + +import fr.dcproject.component.opinion.routes.GetCitizenOpinions.getCitizenOpinions +import fr.dcproject.component.opinion.routes.GetMyOpinionsArticle.getMyOpinionsArticle +import fr.dcproject.component.opinion.routes.GetOpinionChoice.getOpinionChoice +import fr.dcproject.component.opinion.routes.GetOpinionChoices.getOpinionChoices +import fr.dcproject.component.opinion.routes.OpinionArticle.setOpinionOnArticle +import io.ktor.auth.authenticate +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.ktor.routing.Routing +import org.koin.ktor.ext.get + +@KtorExperimentalLocationsAPI +fun Routing.installOpinionRoutes() { + authenticate(optional = true) { + getCitizenOpinions(get(), get()) + getMyOpinionsArticle(get(), get()) + setOpinionOnArticle(get(), get()) + getOpinionChoice(get()) + getOpinionChoices(get(), get()) + } +} diff --git a/src/main/kotlin/entity/Extra.kt b/src/main/kotlin/entity/Extra.kt index 2d82146..023831f 100644 --- a/src/main/kotlin/entity/Extra.kt +++ b/src/main/kotlin/entity/Extra.kt @@ -3,6 +3,7 @@ package fr.dcproject.entity import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.comment.generic.CommentRef +import fr.dcproject.component.opinion.entity.OpinionRef import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.EntityCreatedBy import fr.postgresjson.entity.UuidEntity diff --git a/src/main/kotlin/routes/OpinionArticle.kt b/src/main/kotlin/routes/OpinionArticle.kt deleted file mode 100644 index 6c7e6af..0000000 --- a/src/main/kotlin/routes/OpinionArticle.kt +++ /dev/null @@ -1,92 +0,0 @@ -package fr.dcproject.routes - -import fr.dcproject.component.article.ArticleForView -import fr.dcproject.component.article.ArticleRef -import fr.dcproject.component.auth.citizen -import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.component.citizen.CitizenRef -import fr.dcproject.entity.Opinion -import fr.dcproject.entity.OpinionChoiceRef -import fr.dcproject.entity.OpinionForUpdate -import fr.dcproject.security.voter.OpinionVoter -import fr.dcproject.utils.toUUID -import fr.dcproject.voter.assert -import io.ktor.application.call -import io.ktor.http.HttpStatusCode -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.Location -import io.ktor.locations.get -import io.ktor.locations.put -import io.ktor.request.receive -import io.ktor.response.respond -import io.ktor.routing.Route -import io.ktor.util.KtorExperimentalAPI -import org.koin.core.KoinComponent -import org.koin.core.get -import java.util.UUID -import fr.dcproject.component.citizen.Citizen as CitizenEntity -import fr.dcproject.repository.OpinionArticle as OpinionArticleRepository - -@KtorExperimentalLocationsAPI -object OpinionArticlePaths { - /** - * Get paginated opinions of citizen for all articles - */ - @Location("/citizens/{citizen}/opinions/articles") - class CitizenOpinionArticleRequest( - val citizen: CitizenRef, - page: Int = 1, - limit: Int = 50 - ) : PaginatedRequestI by PaginatedRequest(page, limit) - - /** - * Put an opinion on one article - */ - @Location("/articles/{article}/opinions") - @KtorExperimentalAPI - class ArticleOpinion(val article: ArticleForView) { - class Body(ids: List) { - val ids: List = ids.map { it.toUUID() } - } - } - - /** - * Get all Opinion of citizen on targets by target ids - */ - @Location("/citizens/{citizen}/opinions") - class CitizenOpinions(val citizen: CitizenEntity, id: List) : KoinComponent { - val id: List = id.toUUID() - val opinionsEntities: List> = get() - .findCitizenOpinionsByTargets(citizen, this.id) - } -} - -@KtorExperimentalAPI -@KtorExperimentalLocationsAPI -fun Route.opinionArticle(repo: OpinionArticleRepository, voter: OpinionVoter) { - get { - val opinions = repo.findCitizenOpinions(citizen, it.page, it.limit) - call.respond(opinions) - } - - get { - voter.assert { canView(it.opinionsEntities, citizenOrNull) } - - call.respond(it.opinionsEntities) - } - - put { - call.receive().ids.map { id -> - OpinionForUpdate( - choice = OpinionChoiceRef(id), - target = it.article, - createdBy = citizen - ) - }.let { opinions -> - voter.assert { canCreate(opinions, citizenOrNull) } - repo.updateOpinions(opinions) - }.let { - call.respond(HttpStatusCode.Created, it) - } - } -} diff --git a/src/main/kotlin/routes/OpinionChoice.kt b/src/main/kotlin/routes/OpinionChoice.kt deleted file mode 100644 index da13cd4..0000000 --- a/src/main/kotlin/routes/OpinionChoice.kt +++ /dev/null @@ -1,38 +0,0 @@ -package fr.dcproject.routes - -import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.entity.OpinionChoice -import fr.dcproject.security.voter.OpinionChoiceVoter -import fr.dcproject.voter.assert -import io.ktor.application.call -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.Location -import io.ktor.locations.get -import io.ktor.response.respond -import io.ktor.routing.Route -import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository - -@KtorExperimentalLocationsAPI -object OpinionChoicePaths { - @Location("/opinions/{opinionChoice}") - class OpinionChoiceRequest(val opinionChoice: OpinionChoice) - - @Location("/opinions") - class OpinionChoicesRequest(val targets: List = emptyList()) -} - -@KtorExperimentalLocationsAPI -fun Route.opinionChoice(repo: OpinionChoiceRepository, voter: OpinionChoiceVoter) { - get { - voter.assert { canView(it.opinionChoice, citizenOrNull) } - - call.respond(it.opinionChoice) - } - - get { - val opinionChoices = repo.findOpinionsChoices(it.targets) - voter.assert { canView(opinionChoices, citizenOrNull) } - - call.respond(opinionChoices) - } -} diff --git a/src/test/kotlin/steps/OpinionSteps.kt b/src/test/kotlin/steps/OpinionSteps.kt index f6a3b01..9201b04 100644 --- a/src/test/kotlin/steps/OpinionSteps.kt +++ b/src/test/kotlin/steps/OpinionSteps.kt @@ -3,16 +3,16 @@ package steps 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.component.opinion.entity.OpinionChoice +import fr.dcproject.component.opinion.entity.OpinionForUpdate import fr.dcproject.utils.toUUID import io.cucumber.datatable.DataTable import io.cucumber.java8.En import org.koin.test.KoinTest import org.koin.test.get import java.util.UUID -import fr.dcproject.repository.OpinionArticle as OpinionRepository -import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository +import fr.dcproject.repository.OpinionChoiceRepository as OpinionChoiceRepository +import fr.dcproject.repository.OpinionRepositoryArticle as OpinionRepository class OpinionSteps : En, KoinTest { init { diff --git a/src/test/kotlin/unit/voter/OpinionChoiceVoterTest.kt b/src/test/kotlin/unit/voter/OpinionChoiceVoterTest.kt index 50bce1c..136c124 100644 --- a/src/test/kotlin/unit/voter/OpinionChoiceVoterTest.kt +++ b/src/test/kotlin/unit/voter/OpinionChoiceVoterTest.kt @@ -6,8 +6,8 @@ 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.entity.OpinionChoice -import fr.dcproject.security.voter.OpinionChoiceVoter +import fr.dcproject.component.opinion.OpinionChoiceVoter +import fr.dcproject.component.opinion.entity.OpinionChoice import fr.dcproject.voter.Vote.GRANTED import org.amshove.kluent.`should be` import org.joda.time.DateTime diff --git a/src/test/kotlin/unit/voter/OpinionVoterTest.kt b/src/test/kotlin/unit/voter/OpinionVoterTest.kt index 055b6c2..4c1f694 100644 --- a/src/test/kotlin/unit/voter/OpinionVoterTest.kt +++ b/src/test/kotlin/unit/voter/OpinionVoterTest.kt @@ -6,9 +6,9 @@ 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.entity.Opinion -import fr.dcproject.entity.OpinionChoice -import fr.dcproject.security.voter.OpinionVoter +import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.opinion.entity.Opinion +import fr.dcproject.component.opinion.entity.OpinionChoice import fr.dcproject.voter.Vote.DENIED import fr.dcproject.voter.Vote.GRANTED import org.amshove.kluent.`should be`