diff --git a/src/main/kotlin/application/Application.kt b/src/main/kotlin/application/Application.kt index 4a4bf86..7e32e15 100644 --- a/src/main/kotlin/application/Application.kt +++ b/src/main/kotlin/application/Application.kt @@ -20,6 +20,7 @@ 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.vote.routes.installVoteRoutes import fr.dcproject.component.workgroup.routes.installWorkgroupRoutes import fr.dcproject.event.EventNotification import fr.dcproject.event.EventSubscriber @@ -27,8 +28,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.voteArticle -import fr.dcproject.routes.voteConstitution import fr.dcproject.voter.VoterDeniedException import fr.postgresjson.migration.Migrations import io.ktor.application.Application @@ -140,13 +139,12 @@ fun Application.module(env: Env = PROD) { installFollowConstitutionRoutes() installWorkgroupRoutes() installOpinionRoutes() + installVoteRoutes() authenticate(optional = true) { /* TODO */ constitution(get(), get()) commentConstitution(get(), get()) - voteArticle(get(), get(), get(), get()) - voteConstitution(get(), get()) definition() } diff --git a/src/main/kotlin/application/Converters.kt b/src/main/kotlin/application/Converters.kt index 504f464..b74404b 100644 --- a/src/main/kotlin/application/Converters.kt +++ b/src/main/kotlin/application/Converters.kt @@ -8,13 +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.OpinionChoiceRepository 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.OpinionChoiceRepository import io.ktor.features.DataConversion import io.ktor.features.NotFoundException import io.ktor.util.KtorExperimentalAPI diff --git a/src/main/kotlin/application/KoinModule.kt b/src/main/kotlin/application/KoinModule.kt index e1efbd8..9d046a0 100644 --- a/src/main/kotlin/application/KoinModule.kt +++ b/src/main/kotlin/application/KoinModule.kt @@ -18,8 +18,14 @@ 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.OpinionChoiceRepository import fr.dcproject.component.opinion.OpinionChoiceVoter import fr.dcproject.component.opinion.OpinionVoter +import fr.dcproject.component.vote.VoteArticleRepository +import fr.dcproject.component.vote.VoteCommentRepository +import fr.dcproject.component.vote.VoteConstitutionRepository +import fr.dcproject.component.vote.VoteRepository +import fr.dcproject.component.vote.VoteVoter import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.event.publisher.Publisher @@ -27,7 +33,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.VoteVoter import fr.postgresjson.connexion.Connection import fr.postgresjson.connexion.Requester import fr.postgresjson.migration.Migrations @@ -43,12 +48,8 @@ import org.koin.dsl.module import fr.dcproject.component.comment.generic.CommentRepository as CommentGenericRepository import fr.dcproject.component.follow.FollowArticleRepository as FollowArticleRepository import fr.dcproject.component.follow.FollowConstitutionRepository as FollowConstitutionRepository +import fr.dcproject.component.opinion.OpinionRepositoryArticle as OpinionArticleRepository import fr.dcproject.repository.Constitution as ConstitutionRepository -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 @KtorExperimentalAPI val KoinModule = module { @@ -116,6 +117,7 @@ val KoinModule = module { single { CommentGenericRepository(get()) } single { CommentArticleRepository(get()) } single { CommentConstitutionRepository(get()) } + single { VoteRepository(get()) } single { VoteArticleRepository(get()) } single { VoteConstitutionRepository(get()) } single { VoteCommentRepository(get()) } diff --git a/src/main/kotlin/component/article/Article.kt b/src/main/kotlin/component/article/Article.kt index fb56e2e..c814426 100644 --- a/src/main/kotlin/component/article/Article.kt +++ b/src/main/kotlin/component/article/Article.kt @@ -9,6 +9,8 @@ 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.vote.entity.Votable +import fr.dcproject.component.vote.entity.VotableImp import fr.dcproject.component.workgroup.WorkgroupCart import fr.dcproject.component.workgroup.WorkgroupCartI import fr.dcproject.component.workgroup.WorkgroupRef @@ -19,8 +21,6 @@ import fr.dcproject.entity.TargetI import fr.dcproject.entity.TargetRef import fr.dcproject.entity.VersionableRef import fr.dcproject.entity.VersionableRefImp -import fr.dcproject.entity.Votable -import fr.dcproject.entity.VotableImp import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.EntityCreatedAtImp import fr.postgresjson.entity.EntityDeletedAt diff --git a/src/main/kotlin/component/article/routes/GetOneArticle.kt b/src/main/kotlin/component/article/routes/GetOneArticle.kt index af71ed0..bc5229f 100644 --- a/src/main/kotlin/component/article/routes/GetOneArticle.kt +++ b/src/main/kotlin/component/article/routes/GetOneArticle.kt @@ -7,10 +7,10 @@ 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.component.vote.dto.Votable import fr.dcproject.dto.CreatedAt import fr.dcproject.dto.Versionable import fr.dcproject.dto.Viewable -import fr.dcproject.dto.Votable import fr.dcproject.voter.assert import io.ktor.application.call import io.ktor.features.NotFoundException diff --git a/src/main/kotlin/component/comment/generic/Comment.kt b/src/main/kotlin/component/comment/generic/Comment.kt index 8bf8b34..87bf671 100644 --- a/src/main/kotlin/component/comment/generic/Comment.kt +++ b/src/main/kotlin/component/comment/generic/Comment.kt @@ -1,13 +1,13 @@ package fr.dcproject.component.comment.generic import fr.dcproject.component.citizen.CitizenRef +import fr.dcproject.component.vote.entity.Votable +import fr.dcproject.component.vote.entity.VotableImp import fr.dcproject.entity.EntityI import fr.dcproject.entity.ExtraI import fr.dcproject.entity.HasTarget import fr.dcproject.entity.TargetI import fr.dcproject.entity.TargetRef -import fr.dcproject.entity.Votable -import fr.dcproject.entity.VotableImp import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.EntityCreatedAtImp import fr.postgresjson.entity.EntityCreatedBy diff --git a/src/main/kotlin/component/opinion/OpinionRepository.kt b/src/main/kotlin/component/opinion/OpinionRepository.kt index b30b472..a34f0da 100644 --- a/src/main/kotlin/component/opinion/OpinionRepository.kt +++ b/src/main/kotlin/component/opinion/OpinionRepository.kt @@ -1,4 +1,4 @@ -package fr.dcproject.repository +package fr.dcproject.component.opinion import com.fasterxml.jackson.core.type.TypeReference import fr.dcproject.component.article.ArticleRef diff --git a/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt index 76d2544..0825064 100644 --- a/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt +++ b/src/main/kotlin/component/opinion/routes/GetCitizenOpinions.kt @@ -15,7 +15,7 @@ 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 +import fr.dcproject.component.opinion.OpinionRepositoryArticle as OpinionArticleRepository @KtorExperimentalLocationsAPI object GetCitizenOpinions { diff --git a/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt b/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt index 67b7cdb..747cb11 100644 --- a/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt +++ b/src/main/kotlin/component/opinion/routes/GetMyOpinionsArticle.kt @@ -13,7 +13,7 @@ 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 +import fr.dcproject.component.opinion.OpinionRepositoryArticle as OpinionArticleRepository @KtorExperimentalLocationsAPI object GetMyOpinionsArticle { diff --git a/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt b/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt index fd43d17..b909f8b 100644 --- a/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt +++ b/src/main/kotlin/component/opinion/routes/GetOpinionChoices.kt @@ -1,6 +1,7 @@ package fr.dcproject.component.opinion.routes import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.opinion.OpinionChoiceRepository import fr.dcproject.component.opinion.OpinionChoiceVoter import fr.dcproject.voter.assert import io.ktor.application.call @@ -9,7 +10,6 @@ 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 { diff --git a/src/main/kotlin/component/opinion/routes/OpinionArticle.kt b/src/main/kotlin/component/opinion/routes/OpinionArticle.kt index 6225bff..0a88b3f 100644 --- a/src/main/kotlin/component/opinion/routes/OpinionArticle.kt +++ b/src/main/kotlin/component/opinion/routes/OpinionArticle.kt @@ -17,7 +17,7 @@ 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 +import fr.dcproject.component.opinion.OpinionRepositoryArticle as OpinionArticleRepository @KtorExperimentalLocationsAPI object OpinionArticle { diff --git a/src/main/kotlin/repository/Vote.kt b/src/main/kotlin/component/vote/VoteRepositoryAbs.kt similarity index 80% rename from src/main/kotlin/repository/Vote.kt rename to src/main/kotlin/component/vote/VoteRepositoryAbs.kt index 96382c0..8423e5e 100644 --- a/src/main/kotlin/repository/Vote.kt +++ b/src/main/kotlin/component/vote/VoteRepositoryAbs.kt @@ -1,22 +1,22 @@ -package fr.dcproject.repository +package fr.dcproject.component.vote import com.fasterxml.jackson.core.type.TypeReference import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.comment.generic.CommentForView +import fr.dcproject.component.vote.entity.VoteAggregation +import fr.dcproject.component.vote.entity.VoteForUpdateI import fr.dcproject.entity.Constitution import fr.dcproject.entity.TargetI import fr.dcproject.entity.TargetRef -import fr.dcproject.entity.VoteAggregation -import fr.dcproject.entity.VoteForUpdateI import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester import fr.postgresjson.repository.RepositoryI import java.util.UUID import fr.dcproject.component.citizen.Citizen as CitizenEntity -import fr.dcproject.entity.Vote as VoteEntity +import fr.dcproject.component.vote.entity.Vote as VoteEntity -open class Vote(override var requester: Requester) : RepositoryI { +abstract class VoteRepositoryAbs(override var requester: Requester) : RepositoryI { fun vote(vote: VoteForUpdateI, anonymous: Boolean? = null): VoteAggregation { val author = vote.createdBy return requester @@ -69,7 +69,9 @@ open class Vote(override var requester: Requester) : RepositoryI { } } -class VoteArticle(requester: Requester) : Vote(requester) { +class VoteRepository(requester: Requester) : VoteRepositoryAbs(requester) + +class VoteArticleRepository(requester: Requester) : VoteRepositoryAbs(requester) { fun findByCitizen( citizen: CitizenEntity, page: Int = 1, @@ -84,7 +86,7 @@ class VoteArticle(requester: Requester) : Vote(requester) { ) } -class VoteArticleComment(requester: Requester) : Vote>(requester) { +class VoteArticleCommentRepository(requester: Requester) : VoteRepositoryAbs>(requester) { fun findByCitizen( citizen: CitizenEntity, page: Int = 1, @@ -99,7 +101,7 @@ class VoteArticleComment(requester: Requester) : Vote>(requester) { +class VoteCommentRepository(requester: Requester) : VoteRepositoryAbs>(requester) { fun findByCitizen( citizen: CitizenEntity, page: Int = 1, @@ -114,7 +116,7 @@ class VoteComment(requester: Requester) : Vote(requester) { +class VoteConstitutionRepository(requester: Requester) : VoteRepositoryAbs(requester) { fun findByCitizen( citizen: CitizenEntity, page: Int = 1, diff --git a/src/main/kotlin/voter/VoteVoter.kt b/src/main/kotlin/component/vote/VoteVoter.kt similarity index 87% rename from src/main/kotlin/voter/VoteVoter.kt rename to src/main/kotlin/component/vote/VoteVoter.kt index bc0903a..7f92730 100644 --- a/src/main/kotlin/voter/VoteVoter.kt +++ b/src/main/kotlin/component/vote/VoteVoter.kt @@ -1,12 +1,12 @@ -package fr.dcproject.security.voter +package fr.dcproject.component.vote import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.component.vote.entity.VoteForUpdateI import fr.dcproject.entity.TargetI -import fr.dcproject.entity.VoteForUpdateI import fr.dcproject.voter.Voter import fr.dcproject.voter.VoterResponse import fr.postgresjson.entity.EntityDeletedAt -import fr.dcproject.entity.Vote as VoteEntity +import fr.dcproject.component.vote.entity.Vote as VoteEntity class VoteVoter : Voter() { fun canCreate(subject: VoteForUpdateI, citizen: CitizenI?): VoterResponse where S : EntityDeletedAt, S : TargetI = when { diff --git a/src/main/kotlin/dto/Votable.kt b/src/main/kotlin/component/vote/dto/Votable.kt similarity index 52% rename from src/main/kotlin/dto/Votable.kt rename to src/main/kotlin/component/vote/dto/Votable.kt index 4930099..70e828b 100644 --- a/src/main/kotlin/dto/Votable.kt +++ b/src/main/kotlin/component/vote/dto/Votable.kt @@ -1,9 +1,9 @@ -package fr.dcproject.dto +package fr.dcproject.component.vote.dto interface Votable { val votes: VoteAggregation - class Imp(parent: fr.dcproject.entity.Votable) : Votable { + class Imp(parent: fr.dcproject.component.vote.entity.Votable) : Votable { override val votes: VoteAggregation = VoteAggregation(parent) } } diff --git a/src/main/kotlin/dto/VoteAggregation.kt b/src/main/kotlin/component/vote/dto/VoteAggregation.kt similarity index 72% rename from src/main/kotlin/dto/VoteAggregation.kt rename to src/main/kotlin/component/vote/dto/VoteAggregation.kt index de169da..b109cb7 100644 --- a/src/main/kotlin/dto/VoteAggregation.kt +++ b/src/main/kotlin/component/vote/dto/VoteAggregation.kt @@ -1,6 +1,6 @@ -package fr.dcproject.dto +package fr.dcproject.component.vote.dto -import fr.dcproject.entity.Votable +import fr.dcproject.component.vote.entity.Votable class VoteAggregation(parent: Votable) { val up: Int = parent.votes.up diff --git a/src/main/kotlin/entity/Votable.kt b/src/main/kotlin/component/vote/entity/Votable.kt similarity index 77% rename from src/main/kotlin/entity/Votable.kt rename to src/main/kotlin/component/vote/entity/Votable.kt index 6fadd00..6971e80 100644 --- a/src/main/kotlin/entity/Votable.kt +++ b/src/main/kotlin/component/vote/entity/Votable.kt @@ -1,4 +1,4 @@ -package fr.dcproject.entity +package fr.dcproject.component.vote.entity interface Votable { val votes: VoteAggregation diff --git a/src/main/kotlin/entity/Vote.kt b/src/main/kotlin/component/vote/entity/Vote.kt similarity index 91% rename from src/main/kotlin/entity/Vote.kt rename to src/main/kotlin/component/vote/entity/Vote.kt index 216223d..a1a6587 100644 --- a/src/main/kotlin/entity/Vote.kt +++ b/src/main/kotlin/component/vote/entity/Vote.kt @@ -1,8 +1,11 @@ -package fr.dcproject.entity +package fr.dcproject.component.vote.entity import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenBasicI import fr.dcproject.component.citizen.CitizenI +import fr.dcproject.entity.ExtraI +import fr.dcproject.entity.HasTarget +import fr.dcproject.entity.TargetI import fr.postgresjson.entity.EntityCreatedAt import fr.postgresjson.entity.EntityCreatedAtImp import fr.postgresjson.entity.EntityCreatedBy diff --git a/src/main/kotlin/entity/VoteAggregation.kt b/src/main/kotlin/component/vote/entity/VoteAggregation.kt similarity index 83% rename from src/main/kotlin/entity/VoteAggregation.kt rename to src/main/kotlin/component/vote/entity/VoteAggregation.kt index c19bdcb..52930c2 100644 --- a/src/main/kotlin/entity/VoteAggregation.kt +++ b/src/main/kotlin/component/vote/entity/VoteAggregation.kt @@ -1,10 +1,10 @@ -package fr.dcproject.entity +package fr.dcproject.component.vote.entity import fr.postgresjson.entity.EntityI import fr.postgresjson.entity.EntityUpdatedAt import fr.postgresjson.entity.EntityUpdatedAtImp -open class VoteAggregation( +class VoteAggregation( val up: Int, val neutral: Int, val down: Int, diff --git a/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt b/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt new file mode 100644 index 0000000..e7b7bc5 --- /dev/null +++ b/src/main/kotlin/component/vote/routes/GetCitizenVotes.kt @@ -0,0 +1,33 @@ +package fr.dcproject.component.vote.routes + +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.vote.VoteRepository +import fr.dcproject.component.vote.VoteVoter +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 java.util.UUID + +@KtorExperimentalLocationsAPI +object GetCitizenVotes { + @Location("/citizens/{citizen}/votes") + class CitizenVotesRequest(val citizen: Citizen, id: List) { + val id: List = id.toUUID() + } + + fun Route.getCitizenVote(repo: VoteRepository, voter: VoteVoter) { + get { + val votes = repo.findCitizenVotesByTargets(it.citizen, it.id) + if (votes.isNotEmpty()) { + voter.assert { canView(votes, citizenOrNull) } + } + call.respond(votes) + } + } +} diff --git a/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt b/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt new file mode 100644 index 0000000..4a62ba7 --- /dev/null +++ b/src/main/kotlin/component/vote/routes/GetCitizenVotesOnArticle.kt @@ -0,0 +1,35 @@ +package fr.dcproject.component.vote.routes + +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.citizen.Citizen +import fr.dcproject.component.vote.VoteArticleRepository +import fr.dcproject.component.vote.VoteVoter +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 + +@KtorExperimentalLocationsAPI +object GetCitizenVotesOnArticle { + @Location("/citizens/{citizen}/votes/articles") + class CitizenVoteArticleRequest( + val citizen: Citizen, + page: Int = 1, + limit: Int = 50, + val search: String? = null + ) : PaginatedRequestI by PaginatedRequest(page, limit) + + fun Route.getCitizenVotesOnArticle(repo: VoteArticleRepository, voter: VoteVoter) { + get { + val votes = repo.findByCitizen(it.citizen, it.page, it.limit) + voter.assert { canView(votes.result, citizenOrNull) } + + call.respond(votes) + } + } +} diff --git a/src/main/kotlin/component/vote/routes/PutVoteOnArticle.kt b/src/main/kotlin/component/vote/routes/PutVoteOnArticle.kt new file mode 100644 index 0000000..73f231b --- /dev/null +++ b/src/main/kotlin/component/vote/routes/PutVoteOnArticle.kt @@ -0,0 +1,39 @@ +package fr.dcproject.component.vote.routes + +import fr.dcproject.component.article.ArticleForView +import fr.dcproject.component.auth.citizen +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.vote.VoteArticleRepository +import fr.dcproject.component.vote.VoteVoter +import fr.dcproject.component.vote.entity.VoteForUpdate +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 + +@KtorExperimentalLocationsAPI +object PutVoteOnArticle { + @Location("/articles/{article}/vote") + class ArticleVoteRequest(val article: ArticleForView) { + data class Content(var note: Int) + } + + fun Route.putVoteOnArticle(repo: VoteArticleRepository, voter: VoteVoter) { + put { + val content = call.receive() + val vote = VoteForUpdate( + target = it.article, + note = content.note, + createdBy = this.citizen + ) + voter.assert { canCreate(vote, citizenOrNull) } + val votes = repo.vote(vote) + call.respond(HttpStatusCode.Created, votes) + } + } +} diff --git a/src/main/kotlin/component/vote/routes/PutVoteOnComment.kt b/src/main/kotlin/component/vote/routes/PutVoteOnComment.kt new file mode 100644 index 0000000..1dc4c7e --- /dev/null +++ b/src/main/kotlin/component/vote/routes/PutVoteOnComment.kt @@ -0,0 +1,41 @@ +package fr.dcproject.component.vote.routes + +import fr.dcproject.component.auth.citizen +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.comment.generic.CommentRepository +import fr.dcproject.component.vote.VoteCommentRepository +import fr.dcproject.component.vote.VoteVoter +import fr.dcproject.component.vote.entity.VoteForUpdate +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 + +@KtorExperimentalLocationsAPI +object PutVoteOnComment { + @Location("/comments/{comment}/vote") + class CommentVoteRequest(val comment: UUID) { + data class Content(var note: Int) + } + + fun Route.putVoteOnComment(voteCommentRepo: VoteCommentRepository, commentRepo: CommentRepository, voter: VoteVoter) { + put { + val comment = commentRepo.findById(it.comment)!! + val content = call.receive() + val vote = VoteForUpdate( + target = comment, + note = content.note, + createdBy = this.citizen + ) + voter.assert { canCreate(vote, citizenOrNull) } + val votes = voteCommentRepo.vote(vote) + call.respond(HttpStatusCode.Created, votes) + } + } +} diff --git a/src/main/kotlin/component/vote/routes/VoteConstitution.kt b/src/main/kotlin/component/vote/routes/VoteConstitution.kt new file mode 100644 index 0000000..d26fb15 --- /dev/null +++ b/src/main/kotlin/component/vote/routes/VoteConstitution.kt @@ -0,0 +1,40 @@ +package fr.dcproject.component.vote.routes + +import fr.dcproject.component.auth.citizen +import fr.dcproject.component.auth.citizenOrNull +import fr.dcproject.component.vote.VoteConstitutionRepository +import fr.dcproject.component.vote.VoteVoter +import fr.dcproject.component.vote.entity.VoteForUpdate +import fr.dcproject.component.vote.routes.VoteConstitution.ConstitutionVoteRequest.Input +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 fr.dcproject.entity.Constitution as ConstitutionEntity + +@KtorExperimentalLocationsAPI +object VoteConstitution { + @Location("/constitutions/{constitution}/vote") + class ConstitutionVoteRequest(val constitution: ConstitutionEntity) { + data class Input(var note: Int) + } + + fun Route.voteConstitution(repo: VoteConstitutionRepository, voter: VoteVoter) { + put { + val content = call.receive() + val vote = VoteForUpdate( + target = it.constitution, + note = content.note, + createdBy = this.citizen + ) + voter.assert { canCreate(vote, citizenOrNull) } + repo.vote(vote) + call.respond(HttpStatusCode.Created) + } + } +} diff --git a/src/main/kotlin/component/vote/routes/install.kt b/src/main/kotlin/component/vote/routes/install.kt new file mode 100644 index 0000000..e4d2753 --- /dev/null +++ b/src/main/kotlin/component/vote/routes/install.kt @@ -0,0 +1,22 @@ +package fr.dcproject.component.vote.routes + +import fr.dcproject.component.vote.routes.GetCitizenVotes.getCitizenVote +import fr.dcproject.component.vote.routes.GetCitizenVotesOnArticle.getCitizenVotesOnArticle +import fr.dcproject.component.vote.routes.PutVoteOnArticle.putVoteOnArticle +import fr.dcproject.component.vote.routes.PutVoteOnComment.putVoteOnComment +import fr.dcproject.component.vote.routes.VoteConstitution.voteConstitution +import io.ktor.auth.authenticate +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.ktor.routing.Routing +import org.koin.ktor.ext.get + +@KtorExperimentalLocationsAPI +fun Routing.installVoteRoutes() { + authenticate(optional = true) { + getCitizenVote(get(), get()) + getCitizenVotesOnArticle(get(), get()) + putVoteOnArticle(get(), get()) + putVoteOnComment(get(), get(), get()) + voteConstitution(get(), get()) + } +} diff --git a/src/main/kotlin/routes/VoteArticle.kt b/src/main/kotlin/routes/VoteArticle.kt deleted file mode 100644 index cafd95b..0000000 --- a/src/main/kotlin/routes/VoteArticle.kt +++ /dev/null @@ -1,94 +0,0 @@ -package fr.dcproject.routes - -import fr.dcproject.component.article.ArticleForView -import fr.dcproject.component.auth.citizen -import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.component.citizen.Citizen -import fr.dcproject.component.comment.generic.CommentRepository -import fr.dcproject.entity.VoteForUpdate -import fr.dcproject.repository.VoteComment -import fr.dcproject.routes.VoteArticlePaths.ArticleVoteRequest -import fr.dcproject.routes.VoteArticlePaths.CommentVoteRequest -import fr.dcproject.security.voter.VoteVoter -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 java.util.UUID -import fr.dcproject.repository.VoteArticle as VoteArticleRepository - -@KtorExperimentalLocationsAPI -object VoteArticlePaths { - @Location("/articles/{article}/vote") - class ArticleVoteRequest(val article: ArticleForView) { - data class Content(var note: Int) - } - - @Location("/comments/{comment}/vote") - class CommentVoteRequest(val comment: UUID) { - data class Content(var note: Int) - } - - @Location("/citizens/{citizen}/votes/articles") - class CitizenVoteArticleRequest( - val citizen: Citizen, - page: Int = 1, - limit: Int = 50, - val search: String? = null - ) : PaginatedRequestI by PaginatedRequest(page, limit) - - @Location("/citizens/{citizen}/votes") - class CitizenVotesByIdsRequest(val citizen: Citizen, id: List) { - val id: List = id.toUUID() - } -} - -@KtorExperimentalLocationsAPI -fun Route.voteArticle(repo: VoteArticleRepository, voteCommentRepo: VoteComment, commentRepo: CommentRepository, voter: VoteVoter) { - put { - val content = call.receive() - val vote = VoteForUpdate( - target = it.article, - note = content.note, - createdBy = this.citizen - ) - voter.assert { canCreate(vote, citizenOrNull) } - val votes = repo.vote(vote) - call.respond(HttpStatusCode.Created, votes) - } - - put { - val comment = commentRepo.findById(it.comment)!! - val content = call.receive() - val vote = VoteForUpdate( - target = comment, - note = content.note, - createdBy = this.citizen - ) - voter.assert { canCreate(vote, citizenOrNull) } - val votes = voteCommentRepo.vote(vote) - call.respond(HttpStatusCode.Created, votes) - } - - get { - val votes = repo.findByCitizen(it.citizen, it.page, it.limit) - voter.assert { canView(votes.result, citizenOrNull) } - - call.respond(votes) - } - - get { - val votes = repo.findCitizenVotesByTargets(it.citizen, it.id) - if (votes.isNotEmpty()) { - voter.assert { canView(votes, citizenOrNull) } - } - call.respond(votes) - } -} diff --git a/src/main/kotlin/routes/VoteConstitution.kt b/src/main/kotlin/routes/VoteConstitution.kt deleted file mode 100644 index 2733d73..0000000 --- a/src/main/kotlin/routes/VoteConstitution.kt +++ /dev/null @@ -1,45 +0,0 @@ -package fr.dcproject.routes - -import fr.dcproject.component.auth.citizen -import fr.dcproject.component.auth.citizenOrNull -import fr.dcproject.component.citizen.Citizen -import fr.dcproject.entity.VoteForUpdate -import fr.dcproject.routes.VoteConstitutionPaths.ConstitutionVoteRequest.Content -import fr.dcproject.security.voter.VoteVoter -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 fr.dcproject.entity.Constitution as ConstitutionEntity -import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository - -@KtorExperimentalLocationsAPI -object VoteConstitutionPaths { - @Location("/constitutions/{constitution}/vote") - class ConstitutionVoteRequest(val constitution: ConstitutionEntity) { - data class Content(var note: Int) - } - - @Location("/citizens/{citizen}/votes/constitutions") - class CitizenVoteConstitutionRequest(val citizen: Citizen) -} - -@KtorExperimentalLocationsAPI -fun Route.voteConstitution(repo: VoteConstitutionRepository, voter: VoteVoter) { - put { - val content = call.receive() - val vote = VoteForUpdate( - target = it.constitution, - note = content.note, - createdBy = this.citizen - ) - voter.assert { canCreate(vote, citizenOrNull) } - repo.vote(vote) - call.respond(HttpStatusCode.Created) - } -} diff --git a/src/test/kotlin/steps/OpinionSteps.kt b/src/test/kotlin/steps/OpinionSteps.kt index 9201b04..b2e991a 100644 --- a/src/test/kotlin/steps/OpinionSteps.kt +++ b/src/test/kotlin/steps/OpinionSteps.kt @@ -3,6 +3,7 @@ package steps import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRepository import fr.dcproject.component.citizen.CitizenRepository +import fr.dcproject.component.opinion.OpinionChoiceRepository import fr.dcproject.component.opinion.entity.OpinionChoice import fr.dcproject.component.opinion.entity.OpinionForUpdate import fr.dcproject.utils.toUUID @@ -11,8 +12,7 @@ import io.cucumber.java8.En import org.koin.test.KoinTest import org.koin.test.get import java.util.UUID -import fr.dcproject.repository.OpinionChoiceRepository as OpinionChoiceRepository -import fr.dcproject.repository.OpinionRepositoryArticle as OpinionRepository +import fr.dcproject.component.opinion.OpinionRepositoryArticle as OpinionRepository class OpinionSteps : En, KoinTest { init { diff --git a/src/test/kotlin/steps/VoteSteps.kt b/src/test/kotlin/steps/VoteSteps.kt index 09da5f8..08b68c6 100644 --- a/src/test/kotlin/steps/VoteSteps.kt +++ b/src/test/kotlin/steps/VoteSteps.kt @@ -2,13 +2,13 @@ package steps import fr.dcproject.component.article.ArticleRepository import fr.dcproject.component.citizen.CitizenRepository -import fr.dcproject.entity.VoteForUpdate +import fr.dcproject.component.vote.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.UUID -import fr.dcproject.repository.VoteArticle as VoteRepository +import fr.dcproject.component.vote.VoteArticleRepository as VoteRepository class VoteSteps : En, KoinTest { init { diff --git a/src/test/kotlin/unit/voter/VoteVoterTest.kt b/src/test/kotlin/unit/voter/VoteVoterTest.kt index e5f2b5d..e1c1201 100644 --- a/src/test/kotlin/unit/voter/VoteVoterTest.kt +++ b/src/test/kotlin/unit/voter/VoteVoterTest.kt @@ -7,8 +7,8 @@ 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.VoteForUpdate -import fr.dcproject.security.voter.VoteVoter +import fr.dcproject.component.vote.VoteVoter +import fr.dcproject.component.vote.entity.VoteForUpdate import fr.dcproject.voter.Vote.DENIED import fr.dcproject.voter.Vote.GRANTED import org.amshove.kluent.`should be` @@ -19,7 +19,7 @@ import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT import java.util.UUID -import fr.dcproject.entity.Vote as VoteEntity +import fr.dcproject.component.vote.entity.Vote as VoteEntity @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Execution(CONCURRENT)