Big refactoring #77

Merged
flecomte merged 166 commits from refactoring-component-and-immutable into master 2021-03-24 19:06:07 +01:00
29 changed files with 263 additions and 187 deletions
Showing only changes of commit c1b8b508ac - Show all commits

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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()) }

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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<T : TargetI>(override var requester: Requester) : RepositoryI {
abstract class VoteRepositoryAbs<T : TargetI>(override var requester: Requester) : RepositoryI {
fun vote(vote: VoteForUpdateI<T, *>, anonymous: Boolean? = null): VoteAggregation {
val author = vote.createdBy
return requester
@@ -69,7 +69,9 @@ open class Vote<T : TargetI>(override var requester: Requester) : RepositoryI {
}
}
class VoteArticle(requester: Requester) : Vote<ArticleForView>(requester) {
class VoteRepository(requester: Requester) : VoteRepositoryAbs<TargetRef>(requester)
class VoteArticleRepository(requester: Requester) : VoteRepositoryAbs<ArticleForView>(requester) {
fun findByCitizen(
citizen: CitizenEntity,
page: Int = 1,
@@ -84,7 +86,7 @@ class VoteArticle(requester: Requester) : Vote<ArticleForView>(requester) {
)
}
class VoteArticleComment(requester: Requester) : Vote<CommentForView<ArticleForView, CitizenRef>>(requester) {
class VoteArticleCommentRepository(requester: Requester) : VoteRepositoryAbs<CommentForView<ArticleForView, CitizenRef>>(requester) {
fun findByCitizen(
citizen: CitizenEntity,
page: Int = 1,
@@ -99,7 +101,7 @@ class VoteArticleComment(requester: Requester) : Vote<CommentForView<ArticleForV
)
}
class VoteComment(requester: Requester) : Vote<CommentForView<TargetRef, CitizenRef>>(requester) {
class VoteCommentRepository(requester: Requester) : VoteRepositoryAbs<CommentForView<TargetRef, CitizenRef>>(requester) {
fun findByCitizen(
citizen: CitizenEntity,
page: Int = 1,
@@ -114,7 +116,7 @@ class VoteComment(requester: Requester) : Vote<CommentForView<TargetRef, Citizen
)
}
class VoteConstitution(requester: Requester) : Vote<Constitution>(requester) {
class VoteConstitutionRepository(requester: Requester) : VoteRepositoryAbs<Constitution>(requester) {
fun findByCitizen(
citizen: CitizenEntity,
page: Int = 1,

View File

@@ -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 <S> canCreate(subject: VoteForUpdateI<S, *>, citizen: CitizenI?): VoterResponse where S : EntityDeletedAt, S : TargetI = when {

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -1,4 +1,4 @@
package fr.dcproject.entity
package fr.dcproject.component.vote.entity
interface Votable {
val votes: VoteAggregation

View File

@@ -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

View File

@@ -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,

View File

@@ -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<String>) {
val id: List<UUID> = id.toUUID()
}
fun Route.getCitizenVote(repo: VoteRepository, voter: VoteVoter) {
get<CitizenVotesRequest> {
val votes = repo.findCitizenVotesByTargets(it.citizen, it.id)
if (votes.isNotEmpty()) {
voter.assert { canView(votes, citizenOrNull) }
}
call.respond(votes)
}
}
}

View File

@@ -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<CitizenVoteArticleRequest> {
val votes = repo.findByCitizen(it.citizen, it.page, it.limit)
voter.assert { canView(votes.result, citizenOrNull) }
call.respond(votes)
}
}
}

View File

@@ -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<ArticleVoteRequest> {
val content = call.receive<ArticleVoteRequest.Content>()
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)
}
}
}

View File

@@ -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<CommentVoteRequest> {
val comment = commentRepo.findById(it.comment)!!
val content = call.receive<CommentVoteRequest.Content>()
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)
}
}
}

View File

@@ -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<ConstitutionVoteRequest> {
val content = call.receive<Input>()
val vote = VoteForUpdate(
target = it.constitution,
note = content.note,
createdBy = this.citizen
)
voter.assert { canCreate(vote, citizenOrNull) }
repo.vote(vote)
call.respond(HttpStatusCode.Created)
}
}
}

View File

@@ -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())
}
}

View File

@@ -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<String>) {
val id: List<UUID> = id.toUUID()
}
}
@KtorExperimentalLocationsAPI
fun Route.voteArticle(repo: VoteArticleRepository, voteCommentRepo: VoteComment, commentRepo: CommentRepository, voter: VoteVoter) {
put<ArticleVoteRequest> {
val content = call.receive<ArticleVoteRequest.Content>()
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<CommentVoteRequest> {
val comment = commentRepo.findById(it.comment)!!
val content = call.receive<CommentVoteRequest.Content>()
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<VoteArticlePaths.CitizenVoteArticleRequest> {
val votes = repo.findByCitizen(it.citizen, it.page, it.limit)
voter.assert { canView(votes.result, citizenOrNull) }
call.respond(votes)
}
get<VoteArticlePaths.CitizenVotesByIdsRequest> {
val votes = repo.findCitizenVotesByTargets(it.citizen, it.id)
if (votes.isNotEmpty()) {
voter.assert { canView(votes, citizenOrNull) }
}
call.respond(votes)
}
}

View File

@@ -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<VoteConstitutionPaths.ConstitutionVoteRequest> {
val content = call.receive<Content>()
val vote = VoteForUpdate(
target = it.constitution,
note = content.note,
createdBy = this.citizen
)
voter.assert { canCreate(vote, citizenOrNull) }
repo.vote(vote)
call.respond(HttpStatusCode.Created)
}
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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)