#60 Can follow citizen

This commit is contained in:
2021-04-17 01:37:32 +02:00
parent 4871e7d780
commit 1c33c026f0
17 changed files with 463 additions and 8 deletions

View File

@@ -25,6 +25,7 @@ import fr.dcproject.component.constitution.routes.installConstitutionRoutes
import fr.dcproject.component.doc.routes.installDocRoutes import fr.dcproject.component.doc.routes.installDocRoutes
import fr.dcproject.component.follow.followKoinModule import fr.dcproject.component.follow.followKoinModule
import fr.dcproject.component.follow.routes.article.installFollowArticleRoutes import fr.dcproject.component.follow.routes.article.installFollowArticleRoutes
import fr.dcproject.component.follow.routes.citizen.installFollowCitizenRoutes
import fr.dcproject.component.follow.routes.constitution.installFollowConstitutionRoutes import fr.dcproject.component.follow.routes.constitution.installFollowConstitutionRoutes
import fr.dcproject.component.notification.NotificationConsumer import fr.dcproject.component.notification.NotificationConsumer
import fr.dcproject.component.notification.routes.installNotificationsRoutes import fr.dcproject.component.notification.routes.installNotificationsRoutes
@@ -154,6 +155,7 @@ fun Application.module(env: Env = PROD) {
installCommentRoutes() installCommentRoutes()
installFollowArticleRoutes() installFollowArticleRoutes()
installFollowConstitutionRoutes() installFollowConstitutionRoutes()
installFollowCitizenRoutes()
installWorkgroupRoutes() installWorkgroupRoutes()
installOpinionRoutes() installOpinionRoutes()
installVoteRoutes() installVoteRoutes()

View File

@@ -69,7 +69,7 @@ val KoinModule = module {
single { single {
val config: Configuration = get() val config: Configuration = get()
NotificationConsumer(get(), get(), get(), get(), get(), config.exchangeNotificationName) NotificationConsumer(get(), get(), get(), get(), get(), get(), config.exchangeNotificationName)
} }
// RabbitMQ // RabbitMQ

View File

@@ -2,6 +2,7 @@ package fr.dcproject.common.entity
import fr.dcproject.component.article.database.ArticleRef import fr.dcproject.component.article.database.ArticleRef
import fr.dcproject.component.citizen.database.CitizenI import fr.dcproject.component.citizen.database.CitizenI
import fr.dcproject.component.citizen.database.CitizenRef
import fr.dcproject.component.comment.generic.database.CommentRef import fr.dcproject.component.comment.generic.database.CommentRef
import fr.dcproject.component.constitution.database.ConstitutionRef import fr.dcproject.component.constitution.database.ConstitutionRef
import fr.dcproject.component.opinion.database.OpinionRef import fr.dcproject.component.opinion.database.OpinionRef
@@ -34,7 +35,8 @@ interface TargetI : EntityI {
Article("article"), Article("article"),
Constitution("constitution"), Constitution("constitution"),
Comment("comment"), Comment("comment"),
Opinion("opinion") Opinion("opinion"),
Citizen("citizen"),
} }
companion object { companion object {
@@ -44,6 +46,7 @@ interface TargetI : EntityI {
t.isSubclassOf(ConstitutionRef::class) -> TargetName.Constitution.targetReference t.isSubclassOf(ConstitutionRef::class) -> TargetName.Constitution.targetReference
t.isSubclassOf(CommentRef::class) -> TargetName.Comment.targetReference t.isSubclassOf(CommentRef::class) -> TargetName.Comment.targetReference
t.isSubclassOf(OpinionRef::class) -> TargetName.Opinion.targetReference t.isSubclassOf(OpinionRef::class) -> TargetName.Opinion.targetReference
t.isSubclassOf(CitizenRef::class) -> TargetName.Citizen.targetReference
else -> throw error("target not implemented: ${t.qualifiedName} \nImplement it or return 'reference' from SQL") else -> throw error("target not implemented: ${t.qualifiedName} \nImplement it or return 'reference' from SQL")
} }
} }

View File

@@ -2,8 +2,9 @@ package fr.dcproject.component.citizen.database
import fr.dcproject.common.entity.CreatedAt import fr.dcproject.common.entity.CreatedAt
import fr.dcproject.common.entity.DeletedAt import fr.dcproject.common.entity.DeletedAt
import fr.dcproject.common.entity.Entity
import fr.dcproject.common.entity.EntityI import fr.dcproject.common.entity.EntityI
import fr.dcproject.common.entity.TargetI
import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.auth.database.User import fr.dcproject.component.auth.database.User
import fr.dcproject.component.auth.database.UserCreator import fr.dcproject.component.auth.database.UserCreator
import fr.dcproject.component.auth.database.UserForCreate import fr.dcproject.component.auth.database.UserForCreate
@@ -95,10 +96,10 @@ open class CitizenRefWithUser(
open class CitizenRef( open class CitizenRef(
id: UUID = UUID.randomUUID() id: UUID = UUID.randomUUID()
) : Entity(id), ) : TargetRef(id),
CitizenI CitizenI
interface CitizenI : EntityI { interface CitizenI : EntityI, TargetI {
data class Name( data class Name(
override val firstName: String, override val firstName: String,
override val lastName: String, override val lastName: String,

View File

@@ -1,11 +1,13 @@
package fr.dcproject.component.follow package fr.dcproject.component.follow
import fr.dcproject.component.follow.database.FollowArticleRepository import fr.dcproject.component.follow.database.FollowArticleRepository
import fr.dcproject.component.follow.database.FollowCitizenRepository
import fr.dcproject.component.follow.database.FollowConstitutionRepository import fr.dcproject.component.follow.database.FollowConstitutionRepository
import org.koin.dsl.module import org.koin.dsl.module
val followKoinModule = module { val followKoinModule = module {
single { FollowArticleRepository(get()) } single { FollowArticleRepository(get()) }
single { FollowConstitutionRepository(get()) } single { FollowConstitutionRepository(get()) }
single { FollowCitizenRepository(get()) }
single { FollowAccessControl() } single { FollowAccessControl() }
} }

View File

@@ -4,7 +4,9 @@ import fr.dcproject.common.entity.Entity
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.article.database.ArticleForView import fr.dcproject.component.article.database.ArticleForView
import fr.dcproject.component.article.database.ArticleRef import fr.dcproject.component.article.database.ArticleRef
import fr.dcproject.component.citizen.database.Citizen
import fr.dcproject.component.citizen.database.CitizenI import fr.dcproject.component.citizen.database.CitizenI
import fr.dcproject.component.citizen.database.CitizenRef
import fr.dcproject.component.constitution.database.ConstitutionForView import fr.dcproject.component.constitution.database.ConstitutionForView
import fr.dcproject.component.constitution.database.ConstitutionRef import fr.dcproject.component.constitution.database.ConstitutionRef
import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Paginated
@@ -144,3 +146,28 @@ class FollowConstitutionRepository(requester: Requester) : FollowRepository<Cons
TODO("Not yet implemented") TODO("Not yet implemented")
} }
} }
class FollowCitizenRepository(requester: Requester) : FollowRepository<CitizenRef, Citizen>(requester) {
override fun findByCitizen(
citizenId: UUID,
page: Int,
limit: Int
): Paginated<FollowForView<Citizen>> {
return requester.run {
getFunction("find_follows_citizen_by_citizen")
.select(
page,
limit,
"created_by_id" to citizenId
)
}
}
override fun findFollowsByTarget(
target: Entity,
page: Int,
limit: Int
): Paginated<FollowForView<CitizenRef>> {
TODO("Not yet implemented")
}
}

View File

@@ -0,0 +1,36 @@
package fr.dcproject.component.follow.routes.citizen
import fr.dcproject.common.security.assert
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.auth.mustBeAuth
import fr.dcproject.component.citizen.database.CitizenRef
import fr.dcproject.component.follow.FollowAccessControl
import fr.dcproject.component.follow.database.FollowCitizenRepository
import fr.dcproject.component.follow.database.FollowForUpdate
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
import java.util.UUID
@KtorExperimentalLocationsAPI
object FollowCitizen {
@Location("/citizens/{citizen}/follows")
class CitizenFollowRequest(citizen: UUID) {
val citizen = CitizenRef(citizen)
}
fun Route.followCitizen(repo: FollowCitizenRepository, ac: FollowAccessControl) {
post<CitizenFollowRequest> {
mustBeAuth()
val follow = FollowForUpdate(target = it.citizen, createdBy = this.citizen)
ac.assert { canCreate(follow, citizenOrNull) }
repo.follow(follow)
call.respond(HttpStatusCode.Created)
}
}
}

View File

@@ -0,0 +1,50 @@
package fr.dcproject.component.follow.routes.citizen
import fr.dcproject.common.response.toOutput
import fr.dcproject.common.security.assert
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.citizen.database.CitizenRef
import fr.dcproject.component.follow.FollowAccessControl
import fr.dcproject.component.follow.database.FollowCitizenRepository
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
import org.joda.time.DateTime
import java.util.UUID
@KtorExperimentalLocationsAPI
object GetFollowCitizen {
@Location("/citizens/{citizen}/follows")
class CitizenFollowRequest(citizen: UUID) {
val citizen = CitizenRef(citizen)
}
fun Route.getFollowCitizen(repo: FollowCitizenRepository, ac: FollowAccessControl) {
get<CitizenFollowRequest> {
repo.findFollow(citizen, it.citizen)?.let { follow ->
ac.assert { canView(follow, citizenOrNull) }
call.respond(
HttpStatusCode.OK,
follow.let { f ->
object {
val id: UUID = f.id
val createdBy: Any = f.createdBy.toOutput()
val target: Any = f.target.let { t ->
object {
val id: UUID = t.id
val reference: String = f.target.reference
}
}
val createdAt: DateTime = f.createdAt
}
}
)
} ?: call.respond(HttpStatusCode.NoContent)
}
}
}

View File

@@ -0,0 +1,50 @@
package fr.dcproject.component.follow.routes.citizen
import fr.dcproject.common.response.toOutput
import fr.dcproject.common.security.assert
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.auth.mustBeAuth
import fr.dcproject.component.citizen.database.CitizenRef
import fr.dcproject.component.follow.FollowAccessControl
import fr.dcproject.component.follow.database.FollowCitizenRepository
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
import org.joda.time.DateTime
import java.util.UUID
@KtorExperimentalLocationsAPI
object GetMyFollowsCitizen {
@Location("/citizens/{citizen}/follows/citizens")
class CitizenFollowCitizenRequest(citizen: UUID) {
val citizen = CitizenRef(citizen)
}
fun Route.getMyFollowsCitizen(repo: FollowCitizenRepository, ac: FollowAccessControl) {
get<CitizenFollowCitizenRequest> {
mustBeAuth()
val follows = repo.findByCitizen(it.citizen)
ac.assert { canView(follows.result, citizenOrNull) }
call.respond(
HttpStatusCode.OK,
follows.toOutput { f ->
object {
val id: UUID = f.id
val createdBy: Any = f.createdBy.toOutput()
val target: Any = f.target.let { t ->
object {
val id: UUID = t.id
val reference: String = f.target.reference
}
}
val createdAt: DateTime = f.createdAt
}
}
)
}
}
}

View File

@@ -0,0 +1,36 @@
package fr.dcproject.component.follow.routes.citizen
import fr.dcproject.common.security.assert
import fr.dcproject.component.auth.citizen
import fr.dcproject.component.auth.citizenOrNull
import fr.dcproject.component.auth.mustBeAuth
import fr.dcproject.component.citizen.database.CitizenRef
import fr.dcproject.component.follow.FollowAccessControl
import fr.dcproject.component.follow.database.FollowCitizenRepository
import fr.dcproject.component.follow.database.FollowForUpdate
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
import java.util.UUID
@KtorExperimentalLocationsAPI
object UnfollowCitizen {
@Location("/citizens/{citizen}/follows")
class CitizenFollowRequest(citizen: UUID) {
val citizen = CitizenRef(citizen)
}
fun Route.unfollowCitizen(repo: FollowCitizenRepository, ac: FollowAccessControl) {
delete<CitizenFollowRequest> {
mustBeAuth()
val follow = FollowForUpdate(target = it.citizen, createdBy = this.citizen)
ac.assert { canDelete(follow, citizenOrNull) }
repo.unfollow(follow)
call.respond(HttpStatusCode.NoContent)
}
}
}

View File

@@ -0,0 +1,20 @@
package fr.dcproject.component.follow.routes.citizen
import fr.dcproject.component.follow.routes.citizen.FollowCitizen.followCitizen
import fr.dcproject.component.follow.routes.citizen.GetFollowCitizen.getFollowCitizen
import fr.dcproject.component.follow.routes.citizen.GetMyFollowsCitizen.getMyFollowsCitizen
import fr.dcproject.component.follow.routes.citizen.UnfollowCitizen.unfollowCitizen
import io.ktor.auth.authenticate
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.routing.Routing
import org.koin.ktor.ext.get
@KtorExperimentalLocationsAPI
fun Routing.installFollowCitizenRoutes() {
authenticate(optional = true) {
followCitizen(get(), get())
unfollowCitizen(get(), get())
getFollowCitizen(get(), get())
getMyFollowsCitizen(get(), get())
}
}

View File

@@ -8,6 +8,7 @@ import com.rabbitmq.client.DefaultConsumer
import com.rabbitmq.client.Envelope import com.rabbitmq.client.Envelope
import fr.dcproject.common.entity.TargetRef import fr.dcproject.common.entity.TargetRef
import fr.dcproject.component.follow.database.FollowArticleRepository import fr.dcproject.component.follow.database.FollowArticleRepository
import fr.dcproject.component.follow.database.FollowCitizenRepository
import fr.dcproject.component.follow.database.FollowConstitutionRepository import fr.dcproject.component.follow.database.FollowConstitutionRepository
import fr.dcproject.component.follow.database.FollowForView import fr.dcproject.component.follow.database.FollowForView
import io.ktor.utils.io.errors.IOException import io.ktor.utils.io.errors.IOException
@@ -23,6 +24,7 @@ class NotificationConsumer(
private val redisClient: RedisClient, private val redisClient: RedisClient,
private val followConstitutionRepo: FollowConstitutionRepository, private val followConstitutionRepo: FollowConstitutionRepository,
private val followArticleRepo: FollowArticleRepository, private val followArticleRepo: FollowArticleRepository,
private val followCitizenRepo: FollowCitizenRepository,
private val notificationEmailSender: NotificationEmailSender, private val notificationEmailSender: NotificationEmailSender,
private val exchangeName: String, private val exchangeName: String,
) { ) {
@@ -98,6 +100,7 @@ class NotificationConsumer(
val follows = when (notification.type) { val follows = when (notification.type) {
"article" -> followArticleRepo.findFollowsByTarget(notification.target) "article" -> followArticleRepo.findFollowsByTarget(notification.target)
"constitution" -> followConstitutionRepo.findFollowsByTarget(notification.target) "constitution" -> followConstitutionRepo.findFollowsByTarget(notification.target)
"citizen" -> followCitizenRepo.findFollowsByTarget(notification.target)
else -> error("event '${notification.type}' not implemented") else -> error("event '${notification.type}' not implemented")
} }

View File

@@ -955,13 +955,105 @@ paths:
description: Return only http status 204 on success description: Return only http status 204 on success
401: 401:
$ref: '#/components/responses/401' $ref: '#/components/responses/401'
/citizens/{citizen}/follows:
parameters:
- $ref: '#/components/parameters/citizen'
get:
security:
- JWTAuth: [ ]
summary: Return Follows of citizen
tags:
- follow
- citizen
responses:
200:
description: Return follows
content:
application/json:
schema:
$ref: '#/components/schemas/FollowResponse'
404:
description: Citizen not exist
content:
application/json:
schema:
$ref: '#/components/schemas/404'
post:
security:
- JWTAuth: []
summary: Follow citizen
description: Follow a citizen to receive notifications of his activity
tags:
- follow
- citizen
responses:
201:
description: Return only http status 201 on success
401:
$ref: '#/components/responses/401'
404:
description: Citizen not exist
content:
application/json:
schema:
$ref: '#/components/schemas/404'
delete:
security:
- JWTAuth: [ ]
summary: Unfollow one citizen
tags:
- follow
- citizen
responses:
204:
description: Return only http status 204 on success
401:
$ref: '#/components/responses/401'
404:
description: Citizen not exist
content:
application/json:
schema:
$ref: '#/components/schemas/404'
/citizens/{citizen}/follows/citizens:
parameters:
- $ref: '#/components/parameters/citizen'
get:
security:
- JWTAuth: [ ]
summary: Return citizen Follow of citizen
tags:
- follow
- citizen
responses:
200:
description: Return citizen Follow of citizen
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
properties:
result:
type: array
items:
$ref: '#/components/schemas/FollowResponse'
404:
description: Citizen not exist
content:
application/json:
schema:
$ref: '#/components/schemas/404'
/citizens/{citizen}/follows/articles: /citizens/{citizen}/follows/articles:
parameters: parameters:
- $ref: '#/components/parameters/citizen' - $ref: '#/components/parameters/citizen'
get: get:
security: security:
- JWTAuth: [ ] - JWTAuth: [ ]
summary: Return Follow or nothing if you not follow summary: Return article Follow of citizen
tags: tags:
- follow - follow
- article - article
@@ -1036,7 +1128,7 @@ paths:
- citizen - citizen
responses: responses:
200: 200:
description: Return your follows description: Return constitution Follow of citizen
content: content:
application/json: application/json:
schema: schema:

View File

@@ -0,0 +1,24 @@
create or replace function find_follows_citizen_by_citizen(
_created_by_id uuid,
"limit" int default 50,
"offset" int default 0,
out resource json,
out total int
) language plpgsql as
$$
begin
select json_agg(t), (select count(id) from follow)
into resource, total
from (
select
f.*,
find_citizen_by_id_with_user(f.target_id) as target,
find_citizen_by_id_with_user(f.created_by_id) as created_by
from follow as f
where created_by_id = _created_by_id
order by created_at desc,
f.created_at desc
limit "limit" offset "offset"
) as t;
end;
$$;

View File

@@ -92,7 +92,8 @@ class NotificationConsumerTest {
rabbitFactory = rabbitFactory, rabbitFactory = rabbitFactory,
redisClient = redisClient, redisClient = redisClient,
followArticleRepo = followArticleRepo, followArticleRepo = followArticleRepo,
followConstitutionRepo = mockk(), followConstitutionRepo = mockk(), // TODO test followConstitution
followCitizenRepo = mockk(), // TODO test followCitizen
notificationEmailSender = emailSender, notificationEmailSender = emailSender,
exchangeName = "notification", exchangeName = "notification",
).apply { start() } ).apply { start() }

View File

@@ -0,0 +1,96 @@
package integration
import integration.steps.`when`.`When I send a DELETE request`
import integration.steps.`when`.`When I send a GET request`
import integration.steps.`when`.`When I send a POST request`
import integration.steps.given.`And follow citizen`
import integration.steps.given.`Given I have citizen`
import integration.steps.given.`authenticated as`
import integration.steps.given.`with no content`
import integration.steps.then.`And the response should be null`
import integration.steps.then.`And the response should contain`
import integration.steps.then.`And the response should not be null`
import integration.steps.then.`Then the response should be`
import integration.steps.then.and
import io.ktor.http.HttpStatusCode.Companion.Created
import io.ktor.http.HttpStatusCode.Companion.NoContent
import io.ktor.http.HttpStatusCode.Companion.OK
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Tags
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@Tags(Tag("integration"), Tag("article"), Tag("follow"))
class `Follow citizen routes` : BaseTest() {
@Test
fun `I can follow citizen`() {
withIntegrationApplication {
/* Followed user */
`Given I have citizen`("John", "Glenn", id = "7e1580c5-05b7-4557-84f4-faac9f0a9441")
/* Current user */
`Given I have citizen`("Valentina", "Terechkova")
`When I send a POST request`("/citizens/7e1580c5-05b7-4557-84f4-faac9f0a9441/follows") {
`authenticated as`("Valentina", "Terechkova")
`with no content`()
} `Then the response should be` Created
}
}
@Test
fun `I can get my follow citizen`() {
withIntegrationApplication {
/* Followed user */
`Given I have citizen`("Jean-Loup", "Chrétien", id = "c2432b94-a509-4116-a8b6-9774bc963372")
/* Current user */
`Given I have citizen`("John", "Young", id = "6d41ce65-9df7-47e0-af46-8da4a909490b") {
`And follow citizen`("c2432b94-a509-4116-a8b6-9774bc963372")
}
/* Get my all follows */
`When I send a GET request`("/citizens/6d41ce65-9df7-47e0-af46-8da4a909490b/follows/citizens") {
`authenticated as`("John", "Young")
} `Then the response should be` OK and {
`And the response should not be null`()
`And the response should contain`("$.currentPage", 1)
`And the response should contain`("$.limit", 50)
}
}
}
@Test
fun `I can unfollow citizen`() {
withIntegrationApplication {
/* Followed user */
`Given I have citizen`("Bruce", "McCandless", id = "680c7af7-d2de-4249-bfcb-47007ef546fe")
/* Current user */
`Given I have citizen`("Jean-François", "Clervoy", id = "a12455ae-1047-43ff-826d-0d826dbe90f7") {
`And follow citizen`("680c7af7-d2de-4249-bfcb-47007ef546fe")
}
`When I send a DELETE request`("/citizens/680c7af7-d2de-4249-bfcb-47007ef546fe/follows") {
`authenticated as`("Jean-François", "Clervoy")
`with no content`()
} `Then the response should be` NoContent and {
`And the response should be null`()
}
}
}
@Test
fun `I can know if I follow an citizen`() {
withIntegrationApplication {
/* Followed user */
`Given I have citizen`("Eugene", "Cernan", id = "c755788f-7f48-4cde-8ff0-e75bcffdafc2")
/* Current user */
`Given I have citizen`("Buzz", "Aldrin", id = "39e2915a-e96f-43ea-babd-bd339d8bf197") {
`And follow citizen`("c755788f-7f48-4cde-8ff0-e75bcffdafc2")
}
`When I send a GET request`("/citizens/c755788f-7f48-4cde-8ff0-e75bcffdafc2/follows") {
`authenticated as`("Buzz", "Aldrin")
`with no content`()
} `Then the response should be` OK and {
`And the response should not be null`()
`And the response should contain`("$.target.id", "c755788f-7f48-4cde-8ff0-e75bcffdafc2")
}
}
}
}

View File

@@ -8,6 +8,7 @@ import fr.dcproject.component.citizen.database.CitizenRef
import fr.dcproject.component.citizen.database.CitizenRepository import fr.dcproject.component.citizen.database.CitizenRepository
import fr.dcproject.component.constitution.database.ConstitutionRef import fr.dcproject.component.constitution.database.ConstitutionRef
import fr.dcproject.component.follow.database.FollowArticleRepository import fr.dcproject.component.follow.database.FollowArticleRepository
import fr.dcproject.component.follow.database.FollowCitizenRepository
import fr.dcproject.component.follow.database.FollowConstitutionRepository import fr.dcproject.component.follow.database.FollowConstitutionRepository
import fr.dcproject.component.follow.database.FollowForUpdate import fr.dcproject.component.follow.database.FollowForUpdate
import io.ktor.server.testing.TestApplicationEngine import io.ktor.server.testing.TestApplicationEngine
@@ -24,6 +25,11 @@ fun Citizen.`And follow constitution`(
) { ) {
createFollow(this, ConstitutionRef(constitution.toUUID())) createFollow(this, ConstitutionRef(constitution.toUUID()))
} }
fun Citizen.`And follow citizen`(
citizen: String,
) {
createFollow(this, CitizenRef(citizen.toUUID()))
}
fun TestApplicationEngine.`Given I have follow on article`( fun TestApplicationEngine.`Given I have follow on article`(
firstName: String, firstName: String,
@@ -56,3 +62,9 @@ fun createFollow(citizen: CitizenRef, constitution: ConstitutionRef) {
val follow = FollowForUpdate(createdBy = citizen, target = constitution) val follow = FollowForUpdate(createdBy = citizen, target = constitution)
followConstitutionRepository.follow(follow) followConstitutionRepository.follow(follow)
} }
fun createFollow(createdBy: CitizenRef, target: CitizenRef) {
val followCitizenRepository: FollowCitizenRepository by lazy { GlobalContext.get().get() }
val follow = FollowForUpdate(createdBy = createdBy, target = target)
followCitizenRepository.follow(follow)
}