Big refactoring #77
@@ -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())
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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,
|
||||||
@@ -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 {
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user