#29 Implement Workgroup (route, voter, repo, entity)
Create tests for workgroup routes add CitizenWithUserI
This commit is contained in:
@@ -45,11 +45,13 @@ import org.slf4j.event.Level
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CompletionException
|
import java.util.concurrent.CompletionException
|
||||||
|
import fr.dcproject.entity.Workgroup as WorkgroupEntity
|
||||||
import fr.dcproject.repository.Article as RepositoryArticle
|
import fr.dcproject.repository.Article as RepositoryArticle
|
||||||
import fr.dcproject.repository.Citizen as RepositoryCitizen
|
import fr.dcproject.repository.Citizen as RepositoryCitizen
|
||||||
import fr.dcproject.repository.Constitution as RepositoryConstitution
|
import fr.dcproject.repository.Constitution as RepositoryConstitution
|
||||||
import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository
|
import fr.dcproject.repository.OpinionChoice as OpinionChoiceRepository
|
||||||
import fr.dcproject.repository.User as UserRepository
|
import fr.dcproject.repository.User as UserRepository
|
||||||
|
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
||||||
|
|
||||||
fun main(args: Array<String>): Unit = io.ktor.server.jetty.EngineMain.main(args)
|
fun main(args: Array<String>): Unit = io.ktor.server.jetty.EngineMain.main(args)
|
||||||
|
|
||||||
@@ -97,7 +99,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
decode { values, _ ->
|
decode { values, _ ->
|
||||||
values.singleOrNull()?.let {
|
values.singleOrNull()?.let {
|
||||||
ArticleRef(UUID.fromString(it))
|
ArticleRef(UUID.fromString(it))
|
||||||
} ?: throw NotFoundException("Article $values not found")
|
} ?: throw NotFoundException("""UUID "$values" is not valid for Article""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,14 +107,14 @@ fun Application.module(env: Env = PROD) {
|
|||||||
decode { values, _ ->
|
decode { values, _ ->
|
||||||
values.singleOrNull()?.let {
|
values.singleOrNull()?.let {
|
||||||
CommentRef(UUID.fromString(it))
|
CommentRef(UUID.fromString(it))
|
||||||
} ?: throw NotFoundException("Comment $values not found")
|
} ?: throw NotFoundException("""UUID "$values" is not valid for Comment""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
convert<ConstitutionRef> {
|
convert<ConstitutionRef> {
|
||||||
decode { values, _ ->
|
decode { values, _ ->
|
||||||
values.singleOrNull()?.let {
|
values.singleOrNull()?.let {
|
||||||
ConstitutionRef(UUID.fromString(it))
|
ConstitutionRef(UUID.fromString(it))
|
||||||
} ?: throw NotFoundException("Constitution $values not found")
|
} ?: throw NotFoundException("""UUID "$values" is not valid for Constitution""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +138,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
decode { values, _ ->
|
decode { values, _ ->
|
||||||
values.singleOrNull()?.let {
|
values.singleOrNull()?.let {
|
||||||
CitizenRef(UUID.fromString(it))
|
CitizenRef(UUID.fromString(it))
|
||||||
} ?: throw NotFoundException("Citizen $values not found")
|
} ?: throw NotFoundException("""UUID "$values" is not valid for Citizen""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +150,23 @@ fun Application.module(env: Env = PROD) {
|
|||||||
?: throw NotFoundException("OpinionChoice $values not found")
|
?: throw NotFoundException("OpinionChoice $values not found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
convert<CitizenRef> {
|
||||||
|
decode { values, _ ->
|
||||||
|
values.singleOrNull()?.let {
|
||||||
|
CitizenRef(UUID.fromString(it))
|
||||||
|
} ?: throw NotFoundException("""UUID "$values" is not valid for Workgroup""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
convert<WorkgroupEntity> {
|
||||||
|
decode { values, _ ->
|
||||||
|
val id = values.singleOrNull()?.let { UUID.fromString(it) }
|
||||||
|
?: throw InternalError("Cannot convert $values to UUID")
|
||||||
|
get<WorkgroupRepository>().findById(id)
|
||||||
|
?: throw NotFoundException("Workgroup $values not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
install(Locations) {
|
install(Locations) {
|
||||||
@@ -162,7 +181,8 @@ fun Application.module(env: Env = PROD) {
|
|||||||
VoteVoter(),
|
VoteVoter(),
|
||||||
FollowVoter(),
|
FollowVoter(),
|
||||||
OpinionVoter(),
|
OpinionVoter(),
|
||||||
OpinionChoiceVoter()
|
OpinionChoiceVoter(),
|
||||||
|
WorkgroupVoter()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,6 +319,7 @@ fun Application.module(env: Env = PROD) {
|
|||||||
voteConstitution(get())
|
voteConstitution(get())
|
||||||
opinionArticle(get())
|
opinionArticle(get())
|
||||||
opinionChoice(get())
|
opinionChoice(get())
|
||||||
|
workgroup(get())
|
||||||
definition()
|
definition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import fr.dcproject.repository.User as UserRepository
|
|||||||
import fr.dcproject.repository.VoteArticle as VoteArticleRepository
|
import fr.dcproject.repository.VoteArticle as VoteArticleRepository
|
||||||
import fr.dcproject.repository.VoteComment as VoteCommentRepository
|
import fr.dcproject.repository.VoteComment as VoteCommentRepository
|
||||||
import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository
|
import fr.dcproject.repository.VoteConstitution as VoteConstitutionRepository
|
||||||
|
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
||||||
|
|
||||||
val config = Config()
|
val config = Config()
|
||||||
|
|
||||||
@@ -111,6 +112,7 @@ val Module = module {
|
|||||||
single { VoteCommentRepository(get()) }
|
single { VoteCommentRepository(get()) }
|
||||||
single { OpinionChoiceRepository(get()) }
|
single { OpinionChoiceRepository(get()) }
|
||||||
single { OpinionArticleRepository(get()) }
|
single { OpinionArticleRepository(get()) }
|
||||||
|
single { WorkgroupRepository(get()) }
|
||||||
|
|
||||||
// Elasticsearch Client
|
// Elasticsearch Client
|
||||||
single<RestClient> {
|
single<RestClient> {
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ open class CitizenSimple(
|
|||||||
|
|
||||||
open class CitizenRefWithUser(
|
open class CitizenRefWithUser(
|
||||||
id: UUID = UUID.randomUUID(),
|
id: UUID = UUID.randomUUID(),
|
||||||
open val user: UserRef
|
override val user: UserRef
|
||||||
) : CitizenRef(id),
|
) : CitizenWithUserI,
|
||||||
|
CitizenRef(id),
|
||||||
EntityDeletedAt by EntityDeletedAtImp()
|
EntityDeletedAt by EntityDeletedAtImp()
|
||||||
|
|
||||||
open class CitizenRef(
|
open class CitizenRef(
|
||||||
@@ -58,15 +59,18 @@ interface CitizenI : UuidEntityI {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CitizenBasicI : CitizenI, EntityDeletedAt {
|
interface CitizenBasicI : CitizenWithUserI, EntityDeletedAt {
|
||||||
var name: Name
|
var name: Name
|
||||||
var email: String
|
var email: String
|
||||||
var birthday: DateTime
|
var birthday: DateTime
|
||||||
var voteAnonymous: Boolean
|
var voteAnonymous: Boolean
|
||||||
var followAnonymous: Boolean
|
var followAnonymous: Boolean
|
||||||
val user: UserI
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CitizenFull : CitizenBasicI {
|
interface CitizenFull : CitizenBasicI {
|
||||||
override val user: User
|
override val user: User
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CitizenWithUserI : CitizenI {
|
||||||
|
val user: UserI
|
||||||
|
}
|
||||||
|
|||||||
58
src/main/kotlin/fr/dcproject/entity/Workgroup.kt
Normal file
58
src/main/kotlin/fr/dcproject/entity/Workgroup.kt
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package fr.dcproject.entity
|
||||||
|
|
||||||
|
import fr.postgresjson.entity.immutable.*
|
||||||
|
import fr.postgresjson.entity.mutable.EntityDeletedAt
|
||||||
|
import fr.postgresjson.entity.mutable.EntityDeletedAtImp
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class Workgroup(
|
||||||
|
id: UUID?,
|
||||||
|
name: String,
|
||||||
|
description: String,
|
||||||
|
logo: String? = null,
|
||||||
|
anonymous: Boolean = true,
|
||||||
|
owner: CitizenBasic,
|
||||||
|
createdBy: CitizenBasic,
|
||||||
|
override var members: List<CitizenBasic> = emptyList()
|
||||||
|
) : WorkgroupWithAuthI<CitizenBasic>,
|
||||||
|
WorkgroupSimple<CitizenBasic>(
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
logo,
|
||||||
|
anonymous,
|
||||||
|
owner,
|
||||||
|
createdBy
|
||||||
|
),
|
||||||
|
EntityCreatedAt by EntityCreatedAtImp(),
|
||||||
|
EntityUpdatedAt by EntityUpdatedAtImp()
|
||||||
|
|
||||||
|
open class WorkgroupSimple<Z : CitizenRef>(
|
||||||
|
id: UUID?,
|
||||||
|
var name: String,
|
||||||
|
var description: String,
|
||||||
|
var logo: String? = null,
|
||||||
|
var anonymous: Boolean = true,
|
||||||
|
var owner: Z,
|
||||||
|
createdBy: Z
|
||||||
|
) : WorkgroupRef(id),
|
||||||
|
EntityCreatedBy<Z> by EntityCreatedByImp(createdBy),
|
||||||
|
EntityDeletedAt by EntityDeletedAtImp()
|
||||||
|
|
||||||
|
open class WorkgroupRef(
|
||||||
|
id: UUID?
|
||||||
|
) : UuidEntity(id ?: UUID.randomUUID()), WorkgroupI
|
||||||
|
|
||||||
|
interface WorkgroupWithAuthI<Z : CitizenWithUserI> : WorkgroupI, EntityCreatedBy<Z>, EntityDeletedAt {
|
||||||
|
val anonymous: Boolean
|
||||||
|
val owner: Z
|
||||||
|
var members: List<Z>
|
||||||
|
|
||||||
|
fun isMember(user: UserI): Boolean =
|
||||||
|
members.map { it.user.id }.contains(user.id) || owner.user.id == user.id
|
||||||
|
|
||||||
|
fun isMember(citizen: CitizenWithUserI): Boolean =
|
||||||
|
isMember(citizen.user)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WorkgroupI : UuidEntityI
|
||||||
46
src/main/kotlin/fr/dcproject/repository/Workgroup.kt
Normal file
46
src/main/kotlin/fr/dcproject/repository/Workgroup.kt
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package fr.dcproject.repository
|
||||||
|
|
||||||
|
import fr.dcproject.entity.CitizenRef
|
||||||
|
import fr.dcproject.entity.WorkgroupSimple
|
||||||
|
import fr.postgresjson.connexion.Paginated
|
||||||
|
import fr.postgresjson.connexion.Requester
|
||||||
|
import fr.postgresjson.entity.Parameter
|
||||||
|
import fr.postgresjson.repository.RepositoryI
|
||||||
|
import fr.postgresjson.repository.RepositoryI.Direction
|
||||||
|
import net.pearx.kasechange.toSnakeCase
|
||||||
|
import java.util.*
|
||||||
|
import fr.dcproject.entity.Workgroup as WorkgroupEntity
|
||||||
|
|
||||||
|
class Workgroup(override var requester: Requester) : RepositoryI {
|
||||||
|
fun findById(id: UUID): WorkgroupEntity? {
|
||||||
|
val function = requester.getFunction("find_workgroup_by_id")
|
||||||
|
return function.selectOne("id" to id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun find(
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50,
|
||||||
|
sort: String? = null,
|
||||||
|
direction: Direction? = null,
|
||||||
|
search: String? = null,
|
||||||
|
filter: Filter = Filter()
|
||||||
|
): Paginated<WorkgroupEntity> {
|
||||||
|
return requester
|
||||||
|
.getFunction("find_workgroups")
|
||||||
|
.select(
|
||||||
|
page, limit,
|
||||||
|
"sort" to sort?.toSnakeCase(),
|
||||||
|
"direction" to direction,
|
||||||
|
"search" to search,
|
||||||
|
"filter" to filter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun upsert(workgroup: WorkgroupSimple<CitizenRef>): WorkgroupEntity = requester
|
||||||
|
.getFunction("upsert_workgroup")
|
||||||
|
.selectOne("resource" to workgroup) ?: error("query 'upsert_workgroup' return null")
|
||||||
|
|
||||||
|
class Filter(
|
||||||
|
val createdById: String? = null
|
||||||
|
) : Parameter
|
||||||
|
}
|
||||||
99
src/main/kotlin/fr/dcproject/routes/Workgroup.kt
Normal file
99
src/main/kotlin/fr/dcproject/routes/Workgroup.kt
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package fr.dcproject.routes
|
||||||
|
|
||||||
|
import fr.dcproject.citizen
|
||||||
|
import fr.dcproject.entity.CitizenRef
|
||||||
|
import fr.dcproject.entity.WorkgroupSimple
|
||||||
|
import fr.dcproject.entity.request.RequestBuilder
|
||||||
|
import fr.dcproject.entity.request.getContent
|
||||||
|
import fr.dcproject.repository.Workgroup.Filter
|
||||||
|
import fr.dcproject.security.voter.WorkgroupVoter.Action.VIEW
|
||||||
|
import fr.dcproject.security.voter.WorkgroupVoter.Action.CREATE
|
||||||
|
import fr.dcproject.security.voter.assertCan
|
||||||
|
import fr.postgresjson.repository.RepositoryI
|
||||||
|
import io.ktor.application.ApplicationCall
|
||||||
|
import io.ktor.application.call
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.locations.KtorExperimentalLocationsAPI
|
||||||
|
import io.ktor.locations.Location
|
||||||
|
import io.ktor.locations.get
|
||||||
|
import io.ktor.locations.post
|
||||||
|
import io.ktor.request.receive
|
||||||
|
import io.ktor.response.respond
|
||||||
|
import io.ktor.routing.Route
|
||||||
|
import org.koin.core.KoinComponent
|
||||||
|
import java.util.*
|
||||||
|
import fr.dcproject.entity.Workgroup as WorkgroupEntity
|
||||||
|
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
object WorkgroupsPaths {
|
||||||
|
@Location("/workgroups")
|
||||||
|
class WorkgroupsRequest(
|
||||||
|
page: Int = 1,
|
||||||
|
limit: Int = 50,
|
||||||
|
val sort: String? = null,
|
||||||
|
val direction: RepositoryI.Direction? = null,
|
||||||
|
val search: String? = null,
|
||||||
|
val createdBy: String? = null
|
||||||
|
) {
|
||||||
|
val page: Int = if (page < 1) 1 else page
|
||||||
|
val limit: Int = if (limit > 50) 50 else if (limit < 1) 1 else limit
|
||||||
|
}
|
||||||
|
|
||||||
|
@Location("/workgroups/{workgroup}")
|
||||||
|
class WorkgroupRequest(val workgroup: WorkgroupEntity)
|
||||||
|
|
||||||
|
@Location("/workgroups")
|
||||||
|
class PostWorkgroupRequest : RequestBuilder<WorkgroupSimple<CitizenRef>> {
|
||||||
|
class Content(
|
||||||
|
val id: UUID?,
|
||||||
|
val name: String,
|
||||||
|
val description: String,
|
||||||
|
val logo: String?,
|
||||||
|
val anonymous: Boolean?,
|
||||||
|
val owner: CitizenRef?
|
||||||
|
) : KoinComponent {
|
||||||
|
fun create(creator: CitizenRef): WorkgroupSimple<CitizenRef> {
|
||||||
|
return WorkgroupSimple(
|
||||||
|
id ?: UUID.randomUUID(),
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
logo,
|
||||||
|
anonymous ?: true,
|
||||||
|
owner ?: creator,
|
||||||
|
creator
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getContent(call: ApplicationCall): WorkgroupSimple<CitizenRef> {
|
||||||
|
return call.receive<Content>().create(call.citizen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@KtorExperimentalLocationsAPI
|
||||||
|
fun Route.workgroup(repo: WorkgroupRepository) {
|
||||||
|
get<WorkgroupsPaths.WorkgroupsRequest> {
|
||||||
|
val workgroups =
|
||||||
|
repo.find(it.page, it.limit, it.sort, it.direction, it.search, Filter(createdById = it.createdBy))
|
||||||
|
assertCan(VIEW, workgroups.result)
|
||||||
|
call.respond(workgroups)
|
||||||
|
}
|
||||||
|
|
||||||
|
get<WorkgroupsPaths.WorkgroupRequest> {
|
||||||
|
assertCan(VIEW, it.workgroup)
|
||||||
|
|
||||||
|
call.respond(it.workgroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
post<WorkgroupsPaths.PostWorkgroupRequest> {
|
||||||
|
call.getContent(it)
|
||||||
|
.let { workgroup ->
|
||||||
|
assertCan(CREATE, workgroup)
|
||||||
|
repo.upsert(workgroup)
|
||||||
|
}.let {
|
||||||
|
call.respond(HttpStatusCode.Created, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package fr.dcproject.security.voter
|
||||||
|
|
||||||
|
import fr.dcproject.entity.UserI
|
||||||
|
import fr.dcproject.entity.WorkgroupI
|
||||||
|
import fr.dcproject.entity.WorkgroupWithAuthI
|
||||||
|
import io.ktor.application.ApplicationCall
|
||||||
|
|
||||||
|
class WorkgroupVoter : Voter {
|
||||||
|
enum class Action : ActionI {
|
||||||
|
CREATE,
|
||||||
|
UPDATE,
|
||||||
|
VIEW,
|
||||||
|
DELETE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean {
|
||||||
|
return (action is Action)
|
||||||
|
.and(subject is List<*> || subject is WorkgroupI?)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote {
|
||||||
|
val user = call.user
|
||||||
|
if (subject is WorkgroupI && action == Action.CREATE && user is UserI) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == Action.VIEW) {
|
||||||
|
if (subject is WorkgroupWithAuthI<*>) {
|
||||||
|
return if (subject.isDeleted()) Vote.DENIED
|
||||||
|
else if (!subject.anonymous) Vote.GRANTED
|
||||||
|
else if (subject.anonymous && user != null && subject.isMember(user)) Vote.GRANTED
|
||||||
|
else Vote.DENIED
|
||||||
|
}
|
||||||
|
if (subject is List<*>) {
|
||||||
|
subject.forEach {
|
||||||
|
if (it !is WorkgroupWithAuthI<*> || it.isDeleted()) {
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subject is WorkgroupWithAuthI<*>) {
|
||||||
|
if (action == Action.DELETE && user is UserI && subject.owner.user.id == user.id) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == Action.UPDATE && user is UserI && subject.owner.user.id == user.id) {
|
||||||
|
return Vote.GRANTED
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action is Action) {
|
||||||
|
return Vote.DENIED
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vote.ABSTAIN
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/test/kotlin/feature/WorkgroupSteps.kt
Normal file
53
src/test/kotlin/feature/WorkgroupSteps.kt
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package feature
|
||||||
|
|
||||||
|
import fr.dcproject.entity.*
|
||||||
|
import io.cucumber.datatable.DataTable
|
||||||
|
import io.cucumber.java8.En
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
import org.koin.test.KoinTest
|
||||||
|
import org.koin.test.get
|
||||||
|
import java.util.*
|
||||||
|
import fr.dcproject.repository.Citizen as CitizenRepository
|
||||||
|
import fr.dcproject.repository.Workgroup as WorkgroupRepository
|
||||||
|
|
||||||
|
class WorkgroupSteps : En, KoinTest {
|
||||||
|
init {
|
||||||
|
When("I have workgroup:") { body: DataTable ->
|
||||||
|
val data = body.asMap<String, String>(String::class.java, String::class.java)
|
||||||
|
|
||||||
|
val creator = if (data["created_by"] != null) {
|
||||||
|
CitizenRef(UUID.fromString(data["created_by"]))
|
||||||
|
} else {
|
||||||
|
val username = "paul-langevin".toLowerCase() + UUID.randomUUID()
|
||||||
|
val user = User(
|
||||||
|
username = username,
|
||||||
|
plainPassword = "azerty"
|
||||||
|
)
|
||||||
|
Citizen(
|
||||||
|
name = CitizenI.Name("Paul", "Langevin"),
|
||||||
|
email = "$username@dc-project.fr",
|
||||||
|
birthday = DateTime.now(),
|
||||||
|
user = user
|
||||||
|
).also {
|
||||||
|
get<CitizenRepository>().insertWithUser(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val owner = if (data["owner"] != null) {
|
||||||
|
CitizenRef(UUID.fromString(data["owner"]))
|
||||||
|
} else {
|
||||||
|
creator
|
||||||
|
}
|
||||||
|
|
||||||
|
val workgroup = WorkgroupSimple(
|
||||||
|
id = UUID.fromString(data["id"] ?: UUID.randomUUID().toString()),
|
||||||
|
name = data["name"] ?: "Les Incoruptible",
|
||||||
|
description = data["description"] ?: "La vie est notre jeux",
|
||||||
|
createdBy = creator,
|
||||||
|
owner = owner,
|
||||||
|
anonymous = (data["anonymous"] ?: false) == true
|
||||||
|
)
|
||||||
|
|
||||||
|
get<WorkgroupRepository>().upsert(workgroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/test/resources/feature/workgroup.feature
Normal file
44
src/test/resources/feature/workgroup.feature
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
@workgroup
|
||||||
|
Feature: Workgroup
|
||||||
|
|
||||||
|
Scenario: Can get one workgroup
|
||||||
|
Given I have citizen Stephen Hawking
|
||||||
|
And I am authenticated as Stephen Hawking
|
||||||
|
And I have workgroup:
|
||||||
|
| id | ab469134-bf14-4856-b093-ae1aa990f977 |
|
||||||
|
| name | Les Mousquets |
|
||||||
|
When I send a GET request to "/workgroups/ab469134-bf14-4856-b093-ae1aa990f977"
|
||||||
|
Then the response status code should be 200
|
||||||
|
And the JSON should contain:
|
||||||
|
| id | ab469134-bf14-4856-b093-ae1aa990f977 |
|
||||||
|
| name | Les Mousquets |
|
||||||
|
|
||||||
|
Scenario: Can create a workgroup
|
||||||
|
Given I have citizen Werner Heisenberg
|
||||||
|
And I am authenticated as Werner Heisenberg
|
||||||
|
When I send a POST request to "/workgroups" with body:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"id":"f496d86d-6654-4068-91ff-90e1dbcc5f38",
|
||||||
|
"name":"Les Bouffons",
|
||||||
|
"description":"La vie est belle",
|
||||||
|
"anonymous":false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then the response status code should be 201
|
||||||
|
And the JSON should contain:
|
||||||
|
| id | f496d86d-6654-4068-91ff-90e1dbcc5f38 |
|
||||||
|
| name | Les Bouffons |
|
||||||
|
| description | La vie est belle |
|
||||||
|
| anonymous | false |
|
||||||
|
|
||||||
|
Scenario: Can get workgroups list
|
||||||
|
Given I have citizen Max Planck
|
||||||
|
And I am authenticated as Max Planck
|
||||||
|
And I have workgroup:
|
||||||
|
| id | 3fd8edb6-c4b4-4c94-bc75-ddd9b290d32c |
|
||||||
|
| name | Les Pissenlits |
|
||||||
|
When I send a GET request to "/workgroups"
|
||||||
|
Then the response status code should be 200
|
||||||
|
And the response should contain object:
|
||||||
|
| $.result[0]id | 3fd8edb6-c4b4-4c94-bc75-ddd9b290d32c |
|
||||||
Reference in New Issue
Block a user