Move Follow to a component

This commit is contained in:
2021-01-18 21:45:48 +01:00
parent 6cdc526335
commit 6a32895571
23 changed files with 280 additions and 181 deletions

View File

@@ -29,6 +29,14 @@ import fr.dcproject.component.comment.generic.routes.createCommentChildren
import fr.dcproject.component.comment.generic.routes.editComment import fr.dcproject.component.comment.generic.routes.editComment
import fr.dcproject.component.comment.generic.routes.getChildrenComments import fr.dcproject.component.comment.generic.routes.getChildrenComments
import fr.dcproject.component.comment.generic.routes.getOneComment import fr.dcproject.component.comment.generic.routes.getOneComment
import fr.dcproject.component.follow.routes.article.FollowArticle.followArticle
import fr.dcproject.component.follow.routes.article.GetFollowArticle.getFollowArticle
import fr.dcproject.component.follow.routes.article.GetMyFollowsArticle.getMyFollowsArticle
import fr.dcproject.component.follow.routes.article.UnfollowArticle.unfollowArticle
import fr.dcproject.component.follow.routes.constitution.FollowConstitution.followConstitution
import fr.dcproject.component.follow.routes.constitution.GetFollowConstitution.getFollowConstitution
import fr.dcproject.component.follow.routes.constitution.GetMyFollowsConstitution.getMyFollowsConstitution
import fr.dcproject.component.follow.routes.constitution.UnfollowConstitution.unfollowConstitution
import fr.dcproject.component.views.ConfigViews import fr.dcproject.component.views.ConfigViews
import fr.dcproject.component.workgroup.routes.CreateWorkgroup.createWorkgroup import fr.dcproject.component.workgroup.routes.CreateWorkgroup.createWorkgroup
import fr.dcproject.component.workgroup.routes.DeleteWorkgroup.deleteWorkgroup import fr.dcproject.component.workgroup.routes.DeleteWorkgroup.deleteWorkgroup
@@ -43,8 +51,6 @@ import fr.dcproject.event.EventSubscriber
import fr.dcproject.routes.commentConstitution import fr.dcproject.routes.commentConstitution
import fr.dcproject.routes.constitution import fr.dcproject.routes.constitution
import fr.dcproject.routes.definition import fr.dcproject.routes.definition
import fr.dcproject.routes.followArticle
import fr.dcproject.routes.followConstitution
import fr.dcproject.routes.notificationArticle import fr.dcproject.routes.notificationArticle
import fr.dcproject.routes.opinionArticle import fr.dcproject.routes.opinionArticle
import fr.dcproject.routes.opinionChoice import fr.dcproject.routes.opinionChoice
@@ -186,10 +192,18 @@ fun Application.module(env: Env = PROD) {
addMemberToWorkgroup(get(), get()) addMemberToWorkgroup(get(), get())
deleteMemberOfWorkgroup(get(), get()) deleteMemberOfWorkgroup(get(), get())
updateMemberOfWorkgroup(get(), get()) updateMemberOfWorkgroup(get(), get())
/* TODO */ /* Follows */
constitution(get(), get())
followArticle(get(), get()) followArticle(get(), get())
followConstitution(get(), get()) followConstitution(get(), get())
unfollowArticle(get(), get())
unfollowConstitution(get(), get())
getFollowArticle(get(), get())
getFollowConstitution(get(), get())
getMyFollowsArticle(get(), get())
getMyFollowsConstitution(get(), get())
/* TODO */
constitution(get(), get())
commentConstitution(get(), get()) commentConstitution(get(), get())
voteArticle(get(), get(), get(), get()) voteArticle(get(), get(), get(), get())
voteConstitution(get(), get()) voteConstitution(get(), get())

View File

@@ -17,6 +17,7 @@ import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.component.citizen.CitizenVoter import fr.dcproject.component.citizen.CitizenVoter
import fr.dcproject.component.comment.article.CommentArticleRepository import fr.dcproject.component.comment.article.CommentArticleRepository
import fr.dcproject.component.comment.generic.CommentVoter import fr.dcproject.component.comment.generic.CommentVoter
import fr.dcproject.component.follow.FollowVoter
import fr.dcproject.component.workgroup.WorkgroupRepository import fr.dcproject.component.workgroup.WorkgroupRepository
import fr.dcproject.component.workgroup.WorkgroupVoter import fr.dcproject.component.workgroup.WorkgroupVoter
import fr.dcproject.event.publisher.Publisher import fr.dcproject.event.publisher.Publisher
@@ -24,7 +25,6 @@ import fr.dcproject.messages.Mailer
import fr.dcproject.messages.NotificationEmailSender import fr.dcproject.messages.NotificationEmailSender
import fr.dcproject.repository.CommentConstitutionRepository import fr.dcproject.repository.CommentConstitutionRepository
import fr.dcproject.security.voter.ConstitutionVoter import fr.dcproject.security.voter.ConstitutionVoter
import fr.dcproject.security.voter.FollowVoter
import fr.dcproject.security.voter.OpinionChoiceVoter import fr.dcproject.security.voter.OpinionChoiceVoter
import fr.dcproject.security.voter.OpinionVoter import fr.dcproject.security.voter.OpinionVoter
import fr.dcproject.security.voter.VoteVoter import fr.dcproject.security.voter.VoteVoter
@@ -41,9 +41,9 @@ import org.elasticsearch.client.RestClient
import org.koin.core.qualifier.named import org.koin.core.qualifier.named
import org.koin.dsl.module import org.koin.dsl.module
import fr.dcproject.component.comment.generic.CommentRepository as CommentGenericRepository 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.repository.Constitution as ConstitutionRepository import fr.dcproject.repository.Constitution as ConstitutionRepository
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository
import fr.dcproject.repository.OpinionArticle as OpinionArticleRepository import fr.dcproject.repository.OpinionArticle as OpinionArticleRepository
import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository
import fr.dcproject.repository.VoteArticle as VoteArticleRepository import fr.dcproject.repository.VoteArticle as VoteArticleRepository

View File

@@ -1,8 +1,11 @@
package fr.dcproject.entity package fr.dcproject.component.follow
import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenBasic
import fr.dcproject.component.citizen.CitizenBasicI import fr.dcproject.component.citizen.CitizenBasicI
import fr.dcproject.component.citizen.CitizenI 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.EntityCreatedAt
import fr.postgresjson.entity.EntityCreatedAtImp import fr.postgresjson.entity.EntityCreatedAtImp
import fr.postgresjson.entity.EntityCreatedBy import fr.postgresjson.entity.EntityCreatedBy

View File

@@ -1,12 +1,10 @@
package fr.dcproject.repository package fr.dcproject.component.follow
import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleForView
import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.entity.ConstitutionRef import fr.dcproject.entity.ConstitutionRef
import fr.dcproject.entity.FollowForUpdate
import fr.dcproject.entity.FollowSimple
import fr.dcproject.entity.TargetRef import fr.dcproject.entity.TargetRef
import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Paginated
import fr.postgresjson.connexion.Requester import fr.postgresjson.connexion.Requester
@@ -15,10 +13,10 @@ import fr.postgresjson.repository.RepositoryI
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import java.util.UUID import java.util.UUID
import fr.dcproject.component.follow.Follow as FollowEntity
import fr.dcproject.entity.Constitution as ConstitutionEntity import fr.dcproject.entity.Constitution as ConstitutionEntity
import fr.dcproject.entity.Follow as FollowEntity
sealed class Follow<IN : TargetRef, OUT : TargetRef>(override var requester: Requester) : RepositoryI { sealed class FollowRepository<IN : TargetRef, OUT : TargetRef>(override var requester: Requester) : RepositoryI {
open fun findByCitizen( open fun findByCitizen(
citizen: CitizenI, citizen: CitizenI,
page: Int = 1, page: Int = 1,
@@ -93,7 +91,7 @@ sealed class Follow<IN : TargetRef, OUT : TargetRef>(override var requester: Req
): Paginated<FollowSimple<IN, CitizenRef>> ): Paginated<FollowSimple<IN, CitizenRef>>
} }
class FollowArticle(requester: Requester) : Follow<ArticleRef, ArticleForView>(requester) { class FollowArticleRepository(requester: Requester) : FollowRepository<ArticleRef, ArticleForView>(requester) {
override fun findByCitizen( override fun findByCitizen(
citizenId: UUID, citizenId: UUID,
page: Int, page: Int,
@@ -124,7 +122,7 @@ class FollowArticle(requester: Requester) : Follow<ArticleRef, ArticleForView>(r
} }
} }
class FollowConstitution(requester: Requester) : Follow<ConstitutionRef, ConstitutionEntity>(requester) { class FollowConstitutionRepository(requester: Requester) : FollowRepository<ConstitutionRef, ConstitutionEntity>(requester) {
override fun findByCitizen( override fun findByCitizen(
citizenId: UUID, citizenId: UUID,
page: Int, page: Int,

View File

@@ -1,10 +1,9 @@
package fr.dcproject.security.voter package fr.dcproject.component.follow
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.entity.FollowI
import fr.dcproject.voter.Voter import fr.dcproject.voter.Voter
import fr.dcproject.voter.VoterResponse import fr.dcproject.voter.VoterResponse
import fr.dcproject.entity.Follow as FollowEntity import fr.dcproject.component.follow.Follow as FollowEntity
class FollowVoter : Voter() { class FollowVoter : Voter() {
fun canCreate(subject: FollowI, citizen: CitizenI?): VoterResponse { fun canCreate(subject: FollowI, citizen: CitizenI?): VoterResponse {

View File

@@ -0,0 +1,31 @@
package fr.dcproject.component.follow.routes.article
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.follow.FollowArticleRepository
import fr.dcproject.component.follow.FollowForUpdate
import fr.dcproject.component.follow.FollowVoter
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.post
import io.ktor.response.respond
import io.ktor.routing.Route
@KtorExperimentalLocationsAPI
object FollowArticle {
@Location("/articles/{article}/follows")
class ArticleFollowRequest(val article: ArticleRef)
fun Route.followArticle(repo: FollowArticleRepository, voter: FollowVoter) {
post<ArticleFollowRequest> {
val follow = FollowForUpdate(target = it.article, createdBy = this.citizen)
voter.assert { canCreate(follow, citizenOrNull) }
repo.follow(follow)
call.respond(HttpStatusCode.Created)
}
}
}

View File

@@ -0,0 +1,30 @@
package fr.dcproject.component.follow.routes.article
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.follow.FollowArticleRepository
import fr.dcproject.component.follow.FollowVoter
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.response.respond
import io.ktor.routing.Route
@KtorExperimentalLocationsAPI
object GetFollowArticle {
@Location("/articles/{article}/follows")
class ArticleFollowRequest(val article: ArticleRef)
fun Route.getFollowArticle(repo: FollowArticleRepository, voter: FollowVoter) {
get<ArticleFollowRequest> {
repo.findFollow(citizen, it.article)?.let { follow ->
voter.assert { canView(follow, citizenOrNull) }
call.respond(follow)
} ?: call.respond(HttpStatusCode.NoContent)
}
}
}

View File

@@ -0,0 +1,27 @@
package fr.dcproject.component.follow.routes.article
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.follow.FollowArticleRepository
import fr.dcproject.component.follow.FollowVoter
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 GetMyFollowsArticle {
@Location("/citizens/{citizen}/follows/articles")
class CitizenFollowArticleRequest(val citizen: Citizen)
fun Route.getMyFollowsArticle(repo: FollowArticleRepository, voter: FollowVoter) {
get<CitizenFollowArticleRequest> {
val follows = repo.findByCitizen(it.citizen)
voter.assert { canView(follows.result, citizenOrNull) }
call.respond(follows)
}
}
}

View File

@@ -0,0 +1,31 @@
package fr.dcproject.component.follow.routes.article
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.follow.FollowArticleRepository
import fr.dcproject.component.follow.FollowForUpdate
import fr.dcproject.component.follow.FollowVoter
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.delete
import io.ktor.response.respond
import io.ktor.routing.Route
@KtorExperimentalLocationsAPI
object UnfollowArticle {
@Location("/articles/{article}/follows")
class ArticleFollowRequest(val article: ArticleRef)
fun Route.unfollowArticle(repo: FollowArticleRepository, voter: FollowVoter) {
delete<ArticleFollowRequest> {
val follow = FollowForUpdate(target = it.article, createdBy = this.citizen)
voter.assert { canDelete(follow, citizenOrNull) }
repo.unfollow(follow)
call.respond(HttpStatusCode.NoContent)
}
}
}

View File

@@ -0,0 +1,31 @@
package fr.dcproject.component.follow.routes.constitution
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.follow.FollowConstitutionRepository
import fr.dcproject.component.follow.FollowForUpdate
import fr.dcproject.component.follow.FollowVoter
import fr.dcproject.entity.ConstitutionRef
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.post
import io.ktor.response.respond
import io.ktor.routing.Route
@KtorExperimentalLocationsAPI
object FollowConstitution {
@Location("/constitutions/{constitution}/follows")
class ConstitutionFollowRequest(val constitution: ConstitutionRef)
fun Route.followConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) {
post<ConstitutionFollowRequest> {
val follow = FollowForUpdate(target = it.constitution, createdBy = this.citizen)
voter.assert { canCreate(follow, citizenOrNull) }
repo.follow(follow)
call.respond(HttpStatusCode.Created)
}
}
}

View File

@@ -0,0 +1,30 @@
package fr.dcproject.component.follow.routes.constitution
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.follow.FollowConstitutionRepository
import fr.dcproject.component.follow.FollowVoter
import fr.dcproject.entity.ConstitutionRef
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.response.respond
import io.ktor.routing.Route
@KtorExperimentalLocationsAPI
object GetFollowConstitution {
@Location("/constitutions/{constitution}/follows")
class ConstitutionFollowRequest(val constitution: ConstitutionRef)
fun Route.getFollowConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) {
get<ConstitutionFollowRequest> {
repo.findFollow(citizen, it.constitution)?.let { follow ->
voter.assert { canView(follow, citizenOrNull) }
call.respond(follow)
} ?: call.respond(HttpStatusCode.NotFound)
}
}
}

View File

@@ -0,0 +1,27 @@
package fr.dcproject.component.follow.routes.constitution
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.follow.FollowConstitutionRepository
import fr.dcproject.component.follow.FollowVoter
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 GetMyFollowsConstitution {
@Location("/citizens/{citizen}/follows/constitutions")
class CitizenFollowConstitutionRequest(val citizen: CitizenRef)
fun Route.getMyFollowsConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) {
get<CitizenFollowConstitutionRequest> {
val follows = repo.findByCitizen(it.citizen)
voter.assert { canView(follows.result, citizenOrNull) }
call.respond(follows)
}
}
}

View File

@@ -0,0 +1,31 @@
package fr.dcproject.component.follow.routes.constitution
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.follow.FollowConstitutionRepository
import fr.dcproject.component.follow.FollowForUpdate
import fr.dcproject.component.follow.FollowVoter
import fr.dcproject.entity.ConstitutionRef
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.delete
import io.ktor.response.respond
import io.ktor.routing.Route
@KtorExperimentalLocationsAPI
object UnfollowConstitution {
@Location("/constitutions/{constitution}/follows")
class ConstitutionUnfollowRequest(val constitution: ConstitutionRef)
fun Route.unfollowConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) {
delete<ConstitutionUnfollowRequest> {
val follow = FollowForUpdate(target = it.constitution, createdBy = this.citizen)
voter.assert { canDelete(follow, citizenOrNull) }
repo.unfollow(follow)
call.respond(HttpStatusCode.NoContent)
}
}
}

View File

@@ -9,11 +9,11 @@ import com.rabbitmq.client.Envelope
import fr.dcproject.application.Configuration import fr.dcproject.application.Configuration
import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleForView
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.entity.FollowSimple import fr.dcproject.component.follow.FollowRepository
import fr.dcproject.component.follow.FollowSimple
import fr.dcproject.entity.TargetRef import fr.dcproject.entity.TargetRef
import fr.dcproject.event.publisher.Publisher import fr.dcproject.event.publisher.Publisher
import fr.dcproject.messages.NotificationEmailSender import fr.dcproject.messages.NotificationEmailSender
import fr.dcproject.repository.Follow
import fr.postgresjson.serializer.deserialize import fr.postgresjson.serializer.deserialize
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
import io.ktor.application.EventDefinition import io.ktor.application.EventDefinition
@@ -27,7 +27,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import fr.dcproject.repository.FollowArticle as FollowArticleRepository import fr.dcproject.component.follow.FollowArticleRepository as FollowArticleRepository
class ArticleUpdate( class ArticleUpdate(
target: ArticleForView target: ArticleForView
@@ -120,7 +120,7 @@ class EventNotification(
val repo = when (event.type) { val repo = when (event.type) {
"article" -> followRepo "article" -> followRepo
else -> error("event '${event.type}' not implemented") else -> error("event '${event.type}' not implemented")
} as Follow<*, *> } as FollowRepository<*, *>
repo repo
.findFollowsByTarget(event.target) .findFollowsByTarget(event.target)

View File

@@ -8,7 +8,7 @@ import fr.dcproject.component.article.ArticleWithTitleI
import fr.dcproject.component.citizen.CitizenBasicI import fr.dcproject.component.citizen.CitizenBasicI
import fr.dcproject.component.citizen.CitizenRef import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.entity.FollowSimple import fr.dcproject.component.follow.FollowSimple
import fr.dcproject.entity.TargetRef import fr.dcproject.entity.TargetRef
import fr.postgresjson.entity.UuidEntityI import fr.postgresjson.entity.UuidEntityI
import java.util.UUID import java.util.UUID

View File

@@ -1,60 +0,0 @@
package fr.dcproject.routes
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.Citizen
import fr.dcproject.entity.FollowForUpdate
import fr.dcproject.security.voter.FollowVoter
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.delete
import io.ktor.locations.get
import io.ktor.locations.post
import io.ktor.response.respond
import io.ktor.routing.Route
import fr.dcproject.repository.FollowArticle as FollowArticleRepository
@KtorExperimentalLocationsAPI
object FollowArticlePaths {
@Location("/articles/{article}/follows")
class ArticleFollowRequest(val article: ArticleRef)
@Location("/citizens/{citizen}/follows/articles")
class CitizenFollowArticleRequest(val citizen: Citizen)
}
@KtorExperimentalLocationsAPI
fun Route.followArticle(repo: FollowArticleRepository, voter: FollowVoter) {
post<FollowArticlePaths.ArticleFollowRequest> {
val follow = FollowForUpdate(target = it.article, createdBy = this.citizen)
voter.assert { canCreate(follow, citizenOrNull) }
repo.follow(follow)
call.respond(HttpStatusCode.Created)
}
delete<FollowArticlePaths.ArticleFollowRequest> {
val follow = FollowForUpdate(target = it.article, createdBy = this.citizen)
voter.assert { canDelete(follow, citizenOrNull) }
repo.unfollow(follow)
call.respond(HttpStatusCode.NoContent)
}
get<FollowArticlePaths.ArticleFollowRequest> {
repo.findFollow(citizen, it.article)?.let { follow ->
voter.assert { canView(follow, citizenOrNull) }
call.respond(follow)
} ?: call.respond(HttpStatusCode.NoContent)
}
get<FollowArticlePaths.CitizenFollowArticleRequest> {
val follows = repo.findByCitizen(it.citizen)
if (follows.result.isNotEmpty()) {
voter.assert { canView(follows.result, citizenOrNull) }
}
call.respond(follows)
}
}

View File

@@ -1,58 +0,0 @@
package fr.dcproject.routes
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.CitizenRef
import fr.dcproject.entity.ConstitutionRef
import fr.dcproject.entity.FollowForUpdate
import fr.dcproject.security.voter.FollowVoter
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.delete
import io.ktor.locations.get
import io.ktor.locations.post
import io.ktor.response.respond
import io.ktor.routing.Route
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository
@KtorExperimentalLocationsAPI
object FollowConstitutionPaths {
@Location("/constitutions/{constitution}/follows")
class ConstitutionFollowRequest(val constitution: ConstitutionRef)
@Location("/citizens/{citizen}/follows/constitutions")
class CitizenFollowConstitutionRequest(val citizen: CitizenRef)
}
@KtorExperimentalLocationsAPI
fun Route.followConstitution(repo: FollowConstitutionRepository, voter: FollowVoter) {
post<FollowConstitutionPaths.ConstitutionFollowRequest> {
val follow = FollowForUpdate(target = it.constitution, createdBy = this.citizen)
voter.assert { canCreate(follow, citizenOrNull) }
repo.follow(follow)
call.respond(HttpStatusCode.Created)
}
delete<FollowConstitutionPaths.ConstitutionFollowRequest> {
val follow = FollowForUpdate(target = it.constitution, createdBy = this.citizen)
voter.assert { canDelete(follow, citizenOrNull) }
repo.unfollow(follow)
call.respond(HttpStatusCode.NoContent)
}
get<FollowConstitutionPaths.ConstitutionFollowRequest> {
repo.findFollow(citizen, it.constitution)?.let { follow ->
voter.assert { canView(follow, citizenOrNull) }
call.respond(follow)
} ?: call.respond(HttpStatusCode.NotFound)
}
get<FollowConstitutionPaths.CitizenFollowConstitutionRequest> {
val follows = repo.findByCitizen(it.citizen)
voter.assert { canView(follows.result, citizenOrNull) }
call.respond(follows)
}
}

View File

@@ -2,14 +2,14 @@ package steps
import fr.dcproject.component.article.ArticleRef import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.citizen.CitizenRepository import fr.dcproject.component.citizen.CitizenRepository
import fr.dcproject.component.follow.FollowForUpdate
import fr.dcproject.entity.ConstitutionRef import fr.dcproject.entity.ConstitutionRef
import fr.dcproject.entity.FollowForUpdate
import fr.dcproject.utils.toUUID import fr.dcproject.utils.toUUID
import io.cucumber.java8.En import io.cucumber.java8.En
import org.koin.test.KoinTest import org.koin.test.KoinTest
import org.koin.test.get import org.koin.test.get
import fr.dcproject.repository.FollowArticle as FollowArticleRepository import fr.dcproject.component.follow.FollowArticleRepository as FollowArticleRepository
import fr.dcproject.repository.FollowConstitution as FollowConstitutionRepository import fr.dcproject.component.follow.FollowConstitutionRepository as FollowConstitutionRepository
class FollowSteps : En, KoinTest { class FollowSteps : En, KoinTest {
init { init {

View File

@@ -12,9 +12,6 @@ import fr.dcproject.component.comment.generic.CommentForView
import fr.dcproject.component.comment.generic.CommentVoter import fr.dcproject.component.comment.generic.CommentVoter
import fr.dcproject.voter.Vote.DENIED import fr.dcproject.voter.Vote.DENIED
import fr.dcproject.voter.Vote.GRANTED import fr.dcproject.voter.Vote.GRANTED
import fr.postgresjson.connexion.Paginated
import io.mockk.every
import io.mockk.mockk
import org.amshove.kluent.`should be` import org.amshove.kluent.`should be`
import org.joda.time.DateTime import org.joda.time.DateTime
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
@@ -23,7 +20,6 @@ import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.parallel.Execution import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT import org.junit.jupiter.api.parallel.ExecutionMode.CONCURRENT
import java.util.UUID import java.util.UUID
import fr.dcproject.component.article.ArticleRepository as ArticleRepo
@TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Execution(CONCURRENT) @Execution(CONCURRENT)
@@ -101,10 +97,6 @@ internal class CommentVoterTest {
target = ArticleRef() target = ArticleRef()
) )
private val repoArticle1 = mockk<ArticleRepo> {
every { findVersionsByVersionId(1, 1, any()) } returns Paginated(listOf(article1), 0, 1, 1)
}
@Test @Test
fun `can be view the comment`() { fun `can be view the comment`() {
CommentVoter() CommentVoter()

View File

@@ -7,11 +7,10 @@ import fr.dcproject.component.citizen.Citizen
import fr.dcproject.component.citizen.CitizenBasic import fr.dcproject.component.citizen.CitizenBasic
import fr.dcproject.component.citizen.CitizenCart import fr.dcproject.component.citizen.CitizenCart
import fr.dcproject.component.citizen.CitizenI import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.entity.Follow import fr.dcproject.component.follow.Follow
import fr.dcproject.security.voter.FollowVoter import fr.dcproject.component.follow.FollowVoter
import fr.dcproject.voter.Vote.DENIED import fr.dcproject.voter.Vote.DENIED
import fr.dcproject.voter.Vote.GRANTED import fr.dcproject.voter.Vote.GRANTED
import io.mockk.mockkStatic
import org.amshove.kluent.`should be` import org.amshove.kluent.`should be`
import org.joda.time.DateTime import org.joda.time.DateTime
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
@@ -96,10 +95,6 @@ internal class FollowVoterTest {
target = article1 target = article1
) )
init {
mockkStatic("fr.dcproject.component.auth.CitizenContextKt")
}
@Test @Test
fun `can be view the follow`() { fun `can be view the follow`() {
FollowVoter() FollowVoter()

View File

@@ -9,7 +9,6 @@ import fr.dcproject.component.citizen.CitizenI
import fr.dcproject.entity.OpinionChoice import fr.dcproject.entity.OpinionChoice
import fr.dcproject.security.voter.OpinionChoiceVoter import fr.dcproject.security.voter.OpinionChoiceVoter
import fr.dcproject.voter.Vote.GRANTED import fr.dcproject.voter.Vote.GRANTED
import io.mockk.mockkStatic
import org.amshove.kluent.`should be` import org.amshove.kluent.`should be`
import org.joda.time.DateTime import org.joda.time.DateTime
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
@@ -56,10 +55,6 @@ internal class OpinionChoiceVoterTest {
target = listOf() target = listOf()
) )
init {
mockkStatic("fr.dcproject.component.auth.CitizenContextKt")
}
@Test @Test
fun `can be view the opinion choice`() { fun `can be view the opinion choice`() {
OpinionChoiceVoter() OpinionChoiceVoter()

View File

@@ -11,7 +11,6 @@ import fr.dcproject.entity.OpinionChoice
import fr.dcproject.security.voter.OpinionVoter import fr.dcproject.security.voter.OpinionVoter
import fr.dcproject.voter.Vote.DENIED import fr.dcproject.voter.Vote.DENIED
import fr.dcproject.voter.Vote.GRANTED import fr.dcproject.voter.Vote.GRANTED
import io.mockk.mockkStatic
import org.amshove.kluent.`should be` import org.amshove.kluent.`should be`
import org.joda.time.DateTime import org.joda.time.DateTime
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
@@ -73,10 +72,6 @@ internal class OpinionVoterTest {
) )
) )
init {
mockkStatic("fr.dcproject.component.auth.CitizenContextKt")
}
@Test @Test
fun `can be view the opinion`() { fun `can be view the opinion`() {
OpinionVoter() OpinionVoter()

View File

@@ -1,7 +1,6 @@
package unit.voter package unit.voter
import fr.dcproject.component.article.ArticleForView import fr.dcproject.component.article.ArticleForView
import fr.dcproject.component.article.ArticleRef
import fr.dcproject.component.auth.User import fr.dcproject.component.auth.User
import fr.dcproject.component.auth.UserI import fr.dcproject.component.auth.UserI
import fr.dcproject.component.citizen.Citizen import fr.dcproject.component.citizen.Citizen
@@ -12,7 +11,6 @@ import fr.dcproject.entity.VoteForUpdate
import fr.dcproject.security.voter.VoteVoter import fr.dcproject.security.voter.VoteVoter
import fr.dcproject.voter.Vote.DENIED import fr.dcproject.voter.Vote.DENIED
import fr.dcproject.voter.Vote.GRANTED import fr.dcproject.voter.Vote.GRANTED
import io.mockk.mockkStatic
import org.amshove.kluent.`should be` import org.amshove.kluent.`should be`
import org.joda.time.DateTime import org.joda.time.DateTime
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Tag
@@ -101,16 +99,6 @@ internal class VoteVoterTest {
note = 1 note = 1
) )
private val voteWithoutTargetUser = VoteForUpdate(
createdBy = tesla,
target = ArticleRef(),
note = 1
)
init {
mockkStatic("fr.dcproject.component.auth.CitizenContextKt")
}
@Test @Test
fun `can be view your the vote`() { fun `can be view your the vote`() {
VoteVoter() VoteVoter()