From 7874f5cec41a9a34d361e258d6853c21935faea2 Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Mon, 1 Jun 2020 13:44:25 +0200 Subject: [PATCH] #55 Can be assign a role to members of my Workgroup Remove Owner on Workgroup (use role MASTER instead) "find_citizen_by_id" not return user anymore, use "find_citizen_by_id_with_user" instead --- src/main/kotlin/Application.kt | 2 +- src/main/kotlin/entity/Citizen.kt | 7 +- src/main/kotlin/entity/Workgroup.kt | 54 ++++++++++++---- src/main/kotlin/repository/Citizen.kt | 44 +++++-------- src/main/kotlin/repository/Workgroup.kt | 30 +++++---- src/main/kotlin/routes/Workgroup.kt | 23 ++++--- src/main/kotlin/voter/WorkgroupVoter.kt | 27 ++++---- src/main/resources/openapi.yaml | 27 ++++++-- .../resources/sql/fixtures/03-workgroup.sql | 23 +++++-- .../functions/article/find_article_by_id.sql | 2 +- .../sql/functions/article/find_articles.sql | 2 +- .../find_articles_versions_by_version_id.sql | 2 +- .../find_last_article_by_version_id.sql | 2 +- .../functions/citizen/find_citizen_by_id.sql | 4 +- .../citizen/find_citizen_by_id_with_user.sql | 3 +- ...citizen_by_id_with_user_and_workgroups.sql | 22 +++++++ .../sql/functions/citizen/upsert_citizen.sql | 2 +- .../functions/comment/find_comment_by_id.sql | 2 +- .../comment/find_comments_by_citizen.sql | 2 +- .../comment/find_comments_by_parent.sql | 2 +- .../comment/find_comments_by_target.sql | 2 +- .../constitution/find_constitution_by_id.sql | 2 +- .../constitution/find_constitutions.sql | 2 +- .../sql/functions/follow/find_follow.sql | 4 +- .../find_follows_article_by_citizen.sql | 2 +- .../follow/find_follows_by_citizen.sql | 2 +- .../find_follows_constitution_by_citizen.sql | 2 +- .../opinion/find_citizen_opinions.sql | 2 +- .../find_citizen_opinions_by_target_id.sql | 2 +- .../find_citizen_opinions_by_target_ids.sql | 2 +- .../functions/opinion/find_opinion_by_id.sql | 2 +- .../opinion/find_opinion_by_opinion.sql | 2 +- .../vote/find_citizen_votes_by_target_ids.sql | 2 +- .../functions/vote/find_votes_by_citizen.sql | 2 +- .../workgroup/add_workgroup_member.sql | 13 ++++ .../workgroup/add_workgroup_members.sql | 13 ++-- .../workgroup/find_workgroup_by_id.sql | 3 +- .../workgroup/find_workgroup_by_id_simple.sql | 3 +- .../workgroup/find_workgroup_members.sql | 5 +- .../functions/workgroup/find_workgroups.sql | 3 +- .../workgroup/remove_workgroup_members.sql | 8 +-- .../workgroup/update_workgroup_members.sql | 19 ++---- .../functions/workgroup/upsert_workgroup.sql | 19 +++--- .../sql/migrations/0000-init_schema.up.sql | 10 +-- src/test/kotlin/feature/WorkgroupSteps.kt | 11 ++-- .../security/voter/WorkgroupVoterTest.kt | 6 +- src/test/resources/feature/workgroup.feature | 58 +++++++++++------ src/test/sql/fixtures/3-fixture_workgroup.sql | 1 - src/test/sql/workgroup.sql | 64 ++++++++++++------- 49 files changed, 331 insertions(+), 217 deletions(-) create mode 100644 src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user_and_workgroups.sql create mode 100644 src/main/resources/sql/functions/workgroup/add_workgroup_member.sql diff --git a/src/main/kotlin/Application.kt b/src/main/kotlin/Application.kt index dd8b391..4b459ff 100644 --- a/src/main/kotlin/Application.kt +++ b/src/main/kotlin/Application.kt @@ -130,7 +130,7 @@ fun Application.module(env: Env = PROD) { decode { values, _ -> val id = values.singleOrNull()?.let { UUID.fromString(it) } ?: throw InternalError("Cannot convert $values to UUID") - get().findById(id, true) ?: throw NotFoundException("Citizen $values not found") + get().findById(id) ?: throw NotFoundException("Citizen $values not found") } } diff --git a/src/main/kotlin/entity/Citizen.kt b/src/main/kotlin/entity/Citizen.kt index 1329e08..af86096 100644 --- a/src/main/kotlin/entity/Citizen.kt +++ b/src/main/kotlin/entity/Citizen.kt @@ -21,7 +21,12 @@ class Citizen( ) : CitizenFull, CitizenBasic(id, name, email, birthday, voteAnonymous, followAnonymous, user), EntityCreatedAt by EntityCreatedAtImp() { - var workgroups: List> = emptyList() + var workgroups: List = emptyList() + + class WorkgroupAndRoles( + val roles: List, + val workgroup: WorkgroupSimple + ) } open class CitizenBasic( diff --git a/src/main/kotlin/entity/Workgroup.kt b/src/main/kotlin/entity/Workgroup.kt index 9d7c8ec..2b105bd 100644 --- a/src/main/kotlin/entity/Workgroup.kt +++ b/src/main/kotlin/entity/Workgroup.kt @@ -1,5 +1,8 @@ package fr.dcproject.entity +import fr.dcproject.entity.WorkgroupWithMembersI.Member +import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role +import fr.postgresjson.entity.EntityI import fr.postgresjson.entity.immutable.* import fr.postgresjson.entity.mutable.EntityDeletedAt import fr.postgresjson.entity.mutable.EntityDeletedAtImp @@ -11,9 +14,8 @@ class Workgroup( description: String, logo: String? = null, anonymous: Boolean = true, - owner: CitizenBasic, createdBy: CitizenBasic, - override var members: List = emptyList() + override var members: List> = emptyList() ) : WorkgroupWithAuthI, WorkgroupSimple( id, @@ -21,7 +23,6 @@ class Workgroup( description, logo, anonymous, - owner, createdBy ), EntityCreatedAt by EntityCreatedAtImp(), @@ -33,7 +34,6 @@ open class WorkgroupSimple( var description: String, var logo: String? = null, var anonymous: Boolean = true, - var owner: Z, createdBy: Z ) : WorkgroupRef(id), EntityCreatedBy by EntityCreatedByImp(createdBy), @@ -45,19 +45,51 @@ open class WorkgroupRef( interface WorkgroupWithAuthI : WorkgroupWithMembersI, EntityCreatedBy, EntityDeletedAt { val anonymous: Boolean - val owner: Z - fun isMember(user: UserI): Boolean = - members.map { it.user.id }.contains(user.id) || owner.user.id == user.id + fun isMember(user: UserI): Boolean = members.isMember(user) + fun isMember(citizen: CitizenWithUserI): Boolean = members.isMember(citizen) - fun isMember(citizen: CitizenWithUserI): Boolean = - isMember(citizen.user) + fun hasRole(expectedRole: Role, user: UserI): Boolean = members.hasRole(expectedRole, user) + fun hasRole(expectedRole: Role, citizen: CitizenI): Boolean = members.hasRole(expectedRole, citizen) + + fun getRoles(user: UserI): List = members.getRoles(user) + fun getRoles(citizen: CitizenI): List = members.getRoles(citizen) } interface WorkgroupWithMembersI : WorkgroupI { - var members: List + var members: List> + + class Member ( + val citizen: C, + val roles: List = emptyList() + ) : EntityI { + enum class Role { + MASTER, + MANAGER, + EDITOR, + REPORTER + } + } } -fun List.asCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id) +fun List.hasCitizen(citizen: CitizenI): Boolean = this.map { it.id }.contains(citizen.id) + +fun List>.isMember(user: UserI): Boolean = + map { it.citizen.user.id }.contains(user.id) + +fun List>.isMember(citizen: CitizenI): Boolean = + map { it.citizen.id }.contains(citizen.id) + +fun List>.hasRole(expectedRole: Role, citizen: CitizenI): Boolean = + any { member -> member.citizen.id == citizen.id && member.roles.any { it == expectedRole } } + +fun List>.hasRole(expectedRole: Role, user: UserI): Boolean = + any { member -> member.citizen.user.id == user.id && member.roles.any { it == expectedRole } } + +fun List>.getRoles(user: UserI): List = + firstOrNull { it.citizen.user.id == user.id }?.roles ?: emptyList() + +fun List>.getRoles(citizen: CitizenI): List = + firstOrNull { it.citizen.id == citizen.id }?.roles ?: emptyList() interface WorkgroupI : UuidEntityI \ No newline at end of file diff --git a/src/main/kotlin/repository/Citizen.kt b/src/main/kotlin/repository/Citizen.kt index 22d5485..1021e1b 100644 --- a/src/main/kotlin/repository/Citizen.kt +++ b/src/main/kotlin/repository/Citizen.kt @@ -12,29 +12,21 @@ import java.util.* import fr.dcproject.entity.Citizen as CitizenEntity class Citizen(override var requester: Requester) : RepositoryI { - fun findById(id: UUID, withUser: Boolean = false): CitizenEntity? { - return requester - .getFunction(if (withUser) "find_citizen_by_id_with_user" else "find_citizen_by_id") - .selectOne("id" to id) - } + fun findById(id: UUID): CitizenEntity? = requester + .getFunction("find_citizen_by_id_with_user_and_workgroups") + .selectOne("id" to id) - fun findByUser(user: UserI): CitizenEntity? { - return requester - .getFunction("find_citizen_by_user_id") - .selectOne("user_id" to user.id) - } + fun findByUser(user: UserI): CitizenEntity? = requester + .getFunction("find_citizen_by_user_id") + .selectOne("user_id" to user.id) - fun findByUsername(unsername: String): CitizenEntity? { - return requester - .getFunction("find_citizen_by_username") - .selectOne("username" to unsername) - } + fun findByUsername(unsername: String): CitizenEntity? = requester + .getFunction("find_citizen_by_username") + .selectOne("username" to unsername) - fun findByEmail(email: String): CitizenEntity? { - return requester - .getFunction("find_citizen_by_email") - .selectOne("email" to email) - } + fun findByEmail(email: String): CitizenEntity? = requester + .getFunction("find_citizen_by_email") + .selectOne("email" to email) fun find( page: Int = 1, @@ -42,8 +34,7 @@ class Citizen(override var requester: Requester) : RepositoryI { sort: String? = null, direction: Direction? = null, search: String? = null - ): Paginated { - return requester + ): Paginated = requester .getFunction("find_citizens") .select( page, limit, @@ -51,17 +42,12 @@ class Citizen(override var requester: Requester) : RepositoryI { "direction" to direction, "search" to search ) - } - fun upsert(citizen: CitizenFull): CitizenEntity? { - return requester + fun upsert(citizen: CitizenFull): CitizenEntity? = requester .getFunction("upsert_citizen") .selectOne("resource" to citizen) - } - fun insertWithUser(citizen: CitizenFull): CitizenEntity? { - return requester + fun insertWithUser(citizen: CitizenFull): CitizenEntity? = requester .getFunction("insert_citizen_with_user") .selectOne("resource" to citizen) - } } diff --git a/src/main/kotlin/repository/Workgroup.kt b/src/main/kotlin/repository/Workgroup.kt index 6d76668..0133e3c 100644 --- a/src/main/kotlin/repository/Workgroup.kt +++ b/src/main/kotlin/repository/Workgroup.kt @@ -1,6 +1,7 @@ package fr.dcproject.repository import fr.dcproject.entity.* +import fr.dcproject.entity.WorkgroupWithMembersI.Member import fr.postgresjson.connexion.Paginated import fr.postgresjson.connexion.Requester import fr.postgresjson.entity.Parameter @@ -44,36 +45,43 @@ class Workgroup(override var requester: Requester) : RepositoryI { .getFunction("delete_workgroup") .perform("id" to workgroup.id) - fun addMember(workgroup: WorkgroupI, member: CitizenI): List = - addMembers(workgroup, listOf(member)) + fun addMember(workgroup: WorkgroupI, member: Member): Member? = + addMember(workgroup, member.citizen, member.roles) - fun addMembers(workgroup: WorkgroupI, members: List): List = requester + fun addMember(workgroup: WorkgroupI, citizen: CitizenI, roles: List): Member? = requester + .getFunction("add_workgroup_member") + .selectOne( + "id" to workgroup.id, + "members" to Member(citizen, roles).serialize() + ) + + fun addMembers(workgroup: WorkgroupI, members: List>): List> = requester .getFunction("add_workgroup_members") .select( "id" to workgroup.id, - "resource" to members.serialize() + "members" to members.serialize() ) - fun removeMember(workgroup: WorkgroupI, memberToDelete: CitizenI): List = + fun removeMember(workgroup: WorkgroupI, memberToDelete: Member): List> = removeMembers(workgroup, listOf(memberToDelete)) - fun removeMembers(workgroup: WorkgroupI, membersToDelete: List): List = requester + fun removeMembers(workgroup: WorkgroupI, membersToDelete: List>): List> = requester .getFunction("remove_workgroup_members") .select( "id" to workgroup.id, - "resource" to membersToDelete + "members" to membersToDelete ) - fun updateMembers(workgroup: WorkgroupI, members: List): List = requester + fun updateMembers(workgroup: WorkgroupI, members: List>): List> = requester .getFunction("update_workgroup_members") .select( "id" to workgroup.id, - "resource" to members + "members" to members ) - fun > updateMembers(workgroup: W): W { + fun , Z : CitizenI> updateMembers(workgroup: W): W { updateMembers(workgroup, workgroup.members).let { - workgroup.members = it + workgroup.members = it as List> } return workgroup diff --git a/src/main/kotlin/routes/Workgroup.kt b/src/main/kotlin/routes/Workgroup.kt index b9f3305..06614ad 100644 --- a/src/main/kotlin/routes/Workgroup.kt +++ b/src/main/kotlin/routes/Workgroup.kt @@ -3,6 +3,8 @@ package fr.dcproject.routes import fr.dcproject.citizen import fr.dcproject.entity.CitizenRef import fr.dcproject.entity.WorkgroupSimple +import fr.dcproject.entity.WorkgroupWithMembersI.Member +import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role import fr.dcproject.repository.Workgroup.Filter import fr.dcproject.security.voter.WorkgroupVoter.Action.VIEW import fr.dcproject.security.voter.WorkgroupVoter.Action.CREATE @@ -54,8 +56,7 @@ object WorkgroupsPaths { val name: String, val description: String, val logo: String?, - val anonymous: Boolean?, - val owner: UUID? + val anonymous: Boolean? ) suspend fun getNewWorkgroup(call: ApplicationCall): WorkgroupSimple = call.receive().run { @@ -65,7 +66,6 @@ object WorkgroupsPaths { description, logo, anonymous ?: true, - owner?.let { CitizenRef(it) } ?: call.citizen, call.citizen ) } @@ -77,8 +77,7 @@ object WorkgroupsPaths { val name: String?, val description: String?, val logo: String?, - val anonymous: Boolean?, - val owner: UUID? + val anonymous: Boolean? ) suspend fun updateWorkgroup(call: ApplicationCall): Unit = call.receive().run { @@ -98,13 +97,19 @@ object WorkgroupsMembersPaths { @Location("/workgroups/{workgroup}/members") class WorkgroupsMembersRequest(val workgroup: WorkgroupEntity) { class Body : MutableList by mutableListOf() { - class Item(id: String) { - val id = id.toUUID() + class Item(id: String, roles: List) { + val citizen = CitizenRef(id.toUUID()) + val roles: List = roles.map { + Role.valueOf(it) + } } } - suspend fun getMembers(call: ApplicationCall): List = call.receive().map { - CitizenRef(it.id) + suspend fun getMembers(call: ApplicationCall): List> = call.receive().map { + Member( + citizen = it.citizen, + roles = it.roles + ) } } } diff --git a/src/main/kotlin/voter/WorkgroupVoter.kt b/src/main/kotlin/voter/WorkgroupVoter.kt index 12d8583..5192c77 100644 --- a/src/main/kotlin/voter/WorkgroupVoter.kt +++ b/src/main/kotlin/voter/WorkgroupVoter.kt @@ -1,7 +1,7 @@ package fr.dcproject.security.voter -import fr.dcproject.citizenOrNull import fr.dcproject.entity.* +import fr.dcproject.entity.WorkgroupWithMembersI.Member.Role import fr.dcproject.user import fr.ktorVoter.ActionI import fr.ktorVoter.Vote @@ -46,11 +46,11 @@ class WorkgroupVoter : Voter { } if (subject is WorkgroupWithAuthI<*>) { - if (action == Action.DELETE && user is UserI && subject.owner.user.id == user.id) { + if (action == Action.DELETE && user is UserI && subject.hasRole(Role.MASTER, user)) { return Vote.GRANTED } - if (action == Action.UPDATE && user is UserI && subject.owner.user.id == user.id) { + if (action == Action.UPDATE && user is UserI && subject.hasRole(Role.MASTER, user)) { return Vote.GRANTED } @@ -61,32 +61,29 @@ class WorkgroupVoter : Voter { } if (action == ActionMembers.ADD) { - val citizen = call.citizenOrNull // TODO create ROLES return Vote.isGranted { - citizen != null && - subject is WorkgroupWithMembersI<*> && - subject.members.asCitizen(citizen) + user is UserI && + subject is WorkgroupWithAuthI<*> && + subject.hasRole(Role.MASTER, user) } } if (action == ActionMembers.UPDATE) { - val citizen = call.citizenOrNull // TODO create ROLES return Vote.isGranted { - citizen != null && - subject is WorkgroupWithMembersI<*> && - subject.members.asCitizen(citizen) + user is UserI && + subject is WorkgroupWithAuthI<*> && + subject.hasRole(Role.MASTER, user) } } if (action == ActionMembers.REMOVE) { - val citizen = call.citizenOrNull // TODO create ROLES return Vote.isGranted { - citizen != null && - subject is WorkgroupWithMembersI<*> && - subject.members.asCitizen(citizen) + user is UserI && + subject is WorkgroupWithAuthI<*> && + subject.hasRole(Role.MASTER, user) } } diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index d0ab047..a7a6c21 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -1708,8 +1708,6 @@ components: anonymous: type: boolean example: false - owner: - $ref: '#/components/schemas/CitizenResponse' - $ref: '#/components/schemas/CreatedBy' - $ref: '#/components/schemas/DeletedAt' Workgroup: @@ -1719,11 +1717,30 @@ components: - type: object properties: members: - type: array - items: - $ref: '#/components/schemas/CitizenResponse' + $ref: '#/components/schemas/Members' - $ref: '#/components/schemas/CreatedAt' - $ref: '#/components/schemas/UpdatedAt' + Members: + description: members of workgroup + type: array + items: + $ref: '#/components/schemas/Member' + Member: + description: Member of workgroup + type: object + properties: + citizen: + $ref: '#/components/schemas/CitizenResponse' + roles: + type: array + items: + type: string + enum: + - MASTER + - MANAGER + - EDITOR + - REPORTER + example: MASTER diff --git a/src/main/resources/sql/fixtures/03-workgroup.sql b/src/main/resources/sql/fixtures/03-workgroup.sql index 743d71b..631e9de 100644 --- a/src/main/resources/sql/fixtures/03-workgroup.sql +++ b/src/main/resources/sql/fixtures/03-workgroup.sql @@ -2,27 +2,40 @@ do $$ declare citizen_count int = (select count(*) from citizen); + _roles text[] = $roles$ + { + "MANAGER", "EDITOR", "REPORTER" + } + $roles$; begin delete from citizen_in_workgroup; delete from workgroup; - insert into workgroup (id, created_by_id, name, description, anonymous, owner_id) + insert into workgroup (id, created_by_id, name, description, anonymous) select uuid_in(md5('workgroup'||rn::text)::cstring), z.id, 'name' || rn, 'description' || rn, - rn % 3 = 1, - z.id + rn % 3 = 1 from (select *, row_number() over () rn from citizen) z; - insert into citizen_in_workgroup (citizen_id, workgroup_id) + insert into citizen_in_workgroup (citizen_id, workgroup_id, roles) select z.id, - w.id + w.id, + '{MASTER}' from (select *, row_number() over ()+5 % citizen_count rn from citizen) z join (select *, row_number() over () rn from workgroup) w using (rn); + insert into citizen_in_workgroup (citizen_id, workgroup_id, roles) + select + z.id, + w.id, + _roles[(row_number() over () % 3)+1:(row_number() over () % 3)+1] + from (select *, row_number() over ()+10 % citizen_count rn from citizen) z + join (select *, row_number() over () rn from workgroup) w using (rn); + raise notice 'workgroup fixtures done'; end; $$; diff --git a/src/main/resources/sql/functions/article/find_article_by_id.sql b/src/main/resources/sql/functions/article/find_article_by_id.sql index 1092a35..29d9d6c 100644 --- a/src/main/resources/sql/functions/article/find_article_by_id.sql +++ b/src/main/resources/sql/functions/article/find_article_by_id.sql @@ -7,7 +7,7 @@ begin from ( select a.*, - find_citizen_by_id(a.created_by_id) as created_by, + find_citizen_by_id_with_user(a.created_by_id) as created_by, find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes, count_opinion(a.id) as opinions diff --git a/src/main/resources/sql/functions/article/find_articles.sql b/src/main/resources/sql/functions/article/find_articles.sql index 564298e..d19e970 100644 --- a/src/main/resources/sql/functions/article/find_articles.sql +++ b/src/main/resources/sql/functions/article/find_articles.sql @@ -21,7 +21,7 @@ begin from ( select a.*, - find_citizen_by_id(a.created_by_id) as created_by, + find_citizen_by_id_with_user(a.created_by_id) as created_by, find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes, count_opinion(a.id) as opinions, diff --git a/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql b/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql index 022d539..30bd7c4 100644 --- a/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql +++ b/src/main/resources/sql/functions/article/find_articles_versions_by_version_id.sql @@ -14,7 +14,7 @@ begin from ( select a.*, - find_citizen_by_id(a.created_by_id) as created_by, + find_citizen_by_id_with_user(a.created_by_id) as created_by, find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes from article as a diff --git a/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql b/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql index c891154..5a86334 100644 --- a/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql +++ b/src/main/resources/sql/functions/article/find_last_article_by_version_id.sql @@ -7,7 +7,7 @@ begin from ( select a.*, - find_citizen_by_id(a.created_by_id) as created_by, + find_citizen_by_id_with_user(a.created_by_id) as created_by, find_workgroup_by_id(a.workgroup_id) as workgroup, count_vote(a.id) as votes into resource diff --git a/src/main/resources/sql/functions/citizen/find_citizen_by_id.sql b/src/main/resources/sql/functions/citizen/find_citizen_by_id.sql index b9d32b2..001619a 100644 --- a/src/main/resources/sql/functions/citizen/find_citizen_by_id.sql +++ b/src/main/resources/sql/functions/citizen/find_citizen_by_id.sql @@ -6,9 +6,7 @@ begin select to_json(t) into resource from ( select - z.*, - find_user_by_id(z.user_id) as "user", - array_agg(find_workgroup_by_id_simple(ciw.workgroup_id)) as "workgroups" + z.* from citizen as z left join citizen_in_workgroup ciw on z.id = ciw.citizen_id where z.id = _id diff --git a/src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user.sql b/src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user.sql index bda4232..d6cfc55 100644 --- a/src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user.sql +++ b/src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user.sql @@ -7,8 +7,7 @@ begin from ( select z.*, - find_user_by_id(z.user_id) as "user", - array_agg(find_workgroup_by_id_simple(ciw.workgroup_id)) as "workgroups" + find_user_by_id(z.user_id) as "user" from citizen as z left join citizen_in_workgroup ciw on z.id = ciw.citizen_id where z.id = _id diff --git a/src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user_and_workgroups.sql b/src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user_and_workgroups.sql new file mode 100644 index 0000000..8c9a311 --- /dev/null +++ b/src/main/resources/sql/functions/citizen/find_citizen_by_id_with_user_and_workgroups.sql @@ -0,0 +1,22 @@ +create or replace function find_citizen_by_id_with_user_and_workgroups(in id uuid, out resource json) language plpgsql as +$$ +declare + _id alias for id; +begin + select to_json(t) into resource + from ( + select + z.*, + find_user_by_id(z.user_id) as "user", + case when ciw.workgroup_id is null then '{}' else array_agg(json_build_object( + 'roles', ciw.roles, + 'workgroup', find_workgroup_by_id_simple(ciw.workgroup_id) + )) end as "workgroups" + from citizen as z + left join citizen_in_workgroup ciw on z.id = ciw.citizen_id + where z.id = _id + group by z.id, ciw.workgroup_id + ) as t; +end; +$$; + diff --git a/src/main/resources/sql/functions/citizen/upsert_citizen.sql b/src/main/resources/sql/functions/citizen/upsert_citizen.sql index 9bf51b3..b4c6470 100644 --- a/src/main/resources/sql/functions/citizen/upsert_citizen.sql +++ b/src/main/resources/sql/functions/citizen/upsert_citizen.sql @@ -23,7 +23,7 @@ begin email = excluded.email returning id into new_id; - select find_citizen_by_id(new_id) into resource; + select find_citizen_by_id_with_user(new_id) into resource; end; $$; diff --git a/src/main/resources/sql/functions/comment/find_comment_by_id.sql b/src/main/resources/sql/functions/comment/find_comment_by_id.sql index 95ac3a6..6a30401 100644 --- a/src/main/resources/sql/functions/comment/find_comment_by_id.sql +++ b/src/main/resources/sql/functions/comment/find_comment_by_id.sql @@ -10,7 +10,7 @@ begin select com.*, find_reference_by_id(com.target_id, com.target_reference) as target, - find_citizen_by_id(com.created_by_id) as created_by, + find_citizen_by_id_with_user(com.created_by_id) as created_by, count_vote(com.id) as votes from "comment" as com where id = _id diff --git a/src/main/resources/sql/functions/comment/find_comments_by_citizen.sql b/src/main/resources/sql/functions/comment/find_comments_by_citizen.sql index fcbec84..ce3dd5b 100644 --- a/src/main/resources/sql/functions/comment/find_comments_by_citizen.sql +++ b/src/main/resources/sql/functions/comment/find_comments_by_citizen.sql @@ -21,7 +21,7 @@ begin select com.*, find_reference_by_id(com.target_id, _reference) as target, - find_citizen_by_id(com.created_by_id) as created_by, + find_citizen_by_id_with_user(com.created_by_id) as created_by, count_vote(com.id) as votes from "comment" as com diff --git a/src/main/resources/sql/functions/comment/find_comments_by_parent.sql b/src/main/resources/sql/functions/comment/find_comments_by_parent.sql index 830873f..1ae9058 100644 --- a/src/main/resources/sql/functions/comment/find_comments_by_parent.sql +++ b/src/main/resources/sql/functions/comment/find_comments_by_parent.sql @@ -14,7 +14,7 @@ begin com.*, (select count(*) from "comment" c2 where c2.parents_ids @> array[com.id]) as children_count, find_reference_by_id(com.target_id, com.target_reference) as target, - find_citizen_by_id(com.created_by_id) as created_by, + find_citizen_by_id_with_user(com.created_by_id) as created_by, count_vote(com.id) as votes from "comment" as com where parent_id = _parent_id diff --git a/src/main/resources/sql/functions/comment/find_comments_by_target.sql b/src/main/resources/sql/functions/comment/find_comments_by_target.sql index 8cdb562..b51eab5 100644 --- a/src/main/resources/sql/functions/comment/find_comments_by_target.sql +++ b/src/main/resources/sql/functions/comment/find_comments_by_target.sql @@ -15,7 +15,7 @@ begin com.*, (select count(c2) from "comment" c2 where c2.parent_comment_id = com.id) as children_count, find_reference_by_id(com.target_id, com.target_reference) as target, - find_citizen_by_id(com.created_by_id) as created_by, + find_citizen_by_id_with_user(com.created_by_id) as created_by, count_vote(com.id) as votes from "comment" as com where com.parent_id = _target_id diff --git a/src/main/resources/sql/functions/constitution/find_constitution_by_id.sql b/src/main/resources/sql/functions/constitution/find_constitution_by_id.sql index 0faaeba..455f803 100644 --- a/src/main/resources/sql/functions/constitution/find_constitution_by_id.sql +++ b/src/main/resources/sql/functions/constitution/find_constitution_by_id.sql @@ -7,7 +7,7 @@ begin from ( select c.*, - find_citizen_by_id(c.created_by_id) as created_by, + find_citizen_by_id_with_user(c.created_by_id) as created_by, find_constitution_titles_by_id(c.id) as titles into resource from constitution as c diff --git a/src/main/resources/sql/functions/constitution/find_constitutions.sql b/src/main/resources/sql/functions/constitution/find_constitutions.sql index 4f02ae0..b407d03 100644 --- a/src/main/resources/sql/functions/constitution/find_constitutions.sql +++ b/src/main/resources/sql/functions/constitution/find_constitutions.sql @@ -14,7 +14,7 @@ begin from ( select c.*, - find_citizen_by_id(c.created_by_id) as created_by, + find_citizen_by_id_with_user(c.created_by_id) as created_by, find_constitution_titles_by_id(c.id) as titles, zdb.score(c.ctid) _score from constitution as c diff --git a/src/main/resources/sql/functions/follow/find_follow.sql b/src/main/resources/sql/functions/follow/find_follow.sql index 17072e8..d68096d 100644 --- a/src/main/resources/sql/functions/follow/find_follow.sql +++ b/src/main/resources/sql/functions/follow/find_follow.sql @@ -19,7 +19,7 @@ begin select f.*, json_build_object('id', f.target_id, 'reference', f.target_reference) as target, - find_citizen_by_id(f.created_by_id) as created_by + find_citizen_by_id_with_user(f.created_by_id) as created_by from follow as f where f.created_by_id = _citizen_id and array[f.target_id] <@ _target_ids @@ -32,7 +32,7 @@ begin select f.*, json_build_object('id', f.target_id, 'reference', f.target_reference) as target, - find_citizen_by_id(f.created_by_id) as created_by + find_citizen_by_id_with_user(f.created_by_id) as created_by from follow as f where f.created_by_id = _citizen_id and f.target_id = _target_id diff --git a/src/main/resources/sql/functions/follow/find_follows_article_by_citizen.sql b/src/main/resources/sql/functions/follow/find_follows_article_by_citizen.sql index 1d6f0c3..58120a7 100644 --- a/src/main/resources/sql/functions/follow/find_follows_article_by_citizen.sql +++ b/src/main/resources/sql/functions/follow/find_follows_article_by_citizen.sql @@ -13,7 +13,7 @@ begin select f.*, find_article_by_id(f.target_id) as target, - find_citizen_by_id(f.created_by_id) as created_by + 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, diff --git a/src/main/resources/sql/functions/follow/find_follows_by_citizen.sql b/src/main/resources/sql/functions/follow/find_follows_by_citizen.sql index 8166627..9d5431a 100644 --- a/src/main/resources/sql/functions/follow/find_follows_by_citizen.sql +++ b/src/main/resources/sql/functions/follow/find_follows_by_citizen.sql @@ -13,7 +13,7 @@ begin select f.*, json_build_object('id', f.target_id) as target, - find_citizen_by_id(f.created_by_id) as created_by + 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, diff --git a/src/main/resources/sql/functions/follow/find_follows_constitution_by_citizen.sql b/src/main/resources/sql/functions/follow/find_follows_constitution_by_citizen.sql index 538f8ca..e561942 100644 --- a/src/main/resources/sql/functions/follow/find_follows_constitution_by_citizen.sql +++ b/src/main/resources/sql/functions/follow/find_follows_constitution_by_citizen.sql @@ -13,7 +13,7 @@ begin select f.*, find_constitution_by_id(f.target_id) as target, - find_citizen_by_id(f.created_by_id) as created_by + 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, diff --git a/src/main/resources/sql/functions/opinion/find_citizen_opinions.sql b/src/main/resources/sql/functions/opinion/find_citizen_opinions.sql index 467205b..4d849fb 100644 --- a/src/main/resources/sql/functions/opinion/find_citizen_opinions.sql +++ b/src/main/resources/sql/functions/opinion/find_citizen_opinions.sql @@ -19,7 +19,7 @@ begin select o.*, find_reference_by_id(o.target_id, o.target_reference) as target, - find_citizen_by_id(o.created_by_id) as created_by, + find_citizen_by_id_with_user(o.created_by_id) as created_by, to_json(ol) as choice from opinion as o join opinion_choice ol on o.choice_id = ol.id diff --git a/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_id.sql b/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_id.sql index ecf7ce0..43bc1bc 100644 --- a/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_id.sql +++ b/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_id.sql @@ -12,7 +12,7 @@ begin select o.*, find_reference_by_id(o.target_id, o.target_reference) as target, - find_citizen_by_id(o.created_by_id) as created_by, + find_citizen_by_id_with_user(o.created_by_id) as created_by, to_json(ol) as choice from opinion as o join opinion_choice ol on o.choice_id = ol.id diff --git a/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_ids.sql b/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_ids.sql index 03d0cb7..4eeb1de 100644 --- a/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_ids.sql +++ b/src/main/resources/sql/functions/opinion/find_citizen_opinions_by_target_ids.sql @@ -10,7 +10,7 @@ begin select o.*, find_reference_by_id(o.target_id, o.target_reference) as target, - find_citizen_by_id(o.created_by_id) as created_by, + find_citizen_by_id_with_user(o.created_by_id) as created_by, to_json(ol) as choice from opinion as o join opinion_choice ol on o.choice_id = ol.id diff --git a/src/main/resources/sql/functions/opinion/find_opinion_by_id.sql b/src/main/resources/sql/functions/opinion/find_opinion_by_id.sql index 48408d9..ea1844e 100644 --- a/src/main/resources/sql/functions/opinion/find_opinion_by_id.sql +++ b/src/main/resources/sql/functions/opinion/find_opinion_by_id.sql @@ -10,7 +10,7 @@ begin select o.*, find_reference_by_id(o.target_id, o.target_reference) as target, - find_citizen_by_id(o.created_by_id) as created_by, + find_citizen_by_id_with_user(o.created_by_id) as created_by, to_json(ol) as choice from "opinion" as o join opinion_choice ol on o.choice_id = ol.id diff --git a/src/main/resources/sql/functions/opinion/find_opinion_by_opinion.sql b/src/main/resources/sql/functions/opinion/find_opinion_by_opinion.sql index 4e5e4f3..fb91055 100644 --- a/src/main/resources/sql/functions/opinion/find_opinion_by_opinion.sql +++ b/src/main/resources/sql/functions/opinion/find_opinion_by_opinion.sql @@ -13,7 +13,7 @@ begin select o.*, find_reference_by_id(o.target_id, o.target_reference) as target, - find_citizen_by_id(o.created_by_id) as created_by, + find_citizen_by_id_with_user(o.created_by_id) as created_by, to_json(ol) as choice from "opinion" as o join opinion_choice ol on o.choice_id = ol.id diff --git a/src/main/resources/sql/functions/vote/find_citizen_votes_by_target_ids.sql b/src/main/resources/sql/functions/vote/find_citizen_votes_by_target_ids.sql index 421321f..18b0a09 100644 --- a/src/main/resources/sql/functions/vote/find_citizen_votes_by_target_ids.sql +++ b/src/main/resources/sql/functions/vote/find_citizen_votes_by_target_ids.sql @@ -13,7 +13,7 @@ begin select v.*, find_reference_by_id(v.target_id, v.target_reference) as target, - find_citizen_by_id(v.created_by_id) as created_by + find_citizen_by_id_with_user(v.created_by_id) as created_by from vote as v diff --git a/src/main/resources/sql/functions/vote/find_votes_by_citizen.sql b/src/main/resources/sql/functions/vote/find_votes_by_citizen.sql index 69816e4..16f258d 100644 --- a/src/main/resources/sql/functions/vote/find_votes_by_citizen.sql +++ b/src/main/resources/sql/functions/vote/find_votes_by_citizen.sql @@ -21,7 +21,7 @@ begin select v.*, find_reference_by_id(v.target_id, _reference) as target, - find_citizen_by_id(v.created_by_id) as created_by + find_citizen_by_id_with_user(v.created_by_id) as created_by from vote as v diff --git a/src/main/resources/sql/functions/workgroup/add_workgroup_member.sql b/src/main/resources/sql/functions/workgroup/add_workgroup_member.sql new file mode 100644 index 0000000..36bb559 --- /dev/null +++ b/src/main/resources/sql/functions/workgroup/add_workgroup_member.sql @@ -0,0 +1,13 @@ +create or replace function add_workgroup_member(in _id uuid, inout member json) + language plpgsql as +$$ +begin + insert into citizen_in_workgroup (workgroup_id, citizen_id, roles) + values ( + _id, + (member#>>'{citizen, id}')::uuid, + (select array_agg(t) from json_array_elements_text(member#>'{roles}') t) + ) + on conflict do nothing; +end; +$$; diff --git a/src/main/resources/sql/functions/workgroup/add_workgroup_members.sql b/src/main/resources/sql/functions/workgroup/add_workgroup_members.sql index 8425fd4..252992e 100644 --- a/src/main/resources/sql/functions/workgroup/add_workgroup_members.sql +++ b/src/main/resources/sql/functions/workgroup/add_workgroup_members.sql @@ -1,16 +1,11 @@ -create or replace function add_workgroup_members(in _id uuid, inout resource json) +create or replace function add_workgroup_members(in _id uuid, inout members json) language plpgsql as $$ begin - insert into citizen_in_workgroup (citizen_id, workgroup_id) - select - (z->>'id')::uuid, - _id::uuid - from json_array_elements(resource) z - where (z->>'id') is not null - on conflict do nothing; + perform add_workgroup_member(_id, b) + from json_array_elements(members) b; - select find_workgroup_members(_id) into resource; + select find_workgroup_members(_id) into members; end; $$; diff --git a/src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql b/src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql index 83db460..8ee55e8 100644 --- a/src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql +++ b/src/main/resources/sql/functions/workgroup/find_workgroup_by_id.sql @@ -7,8 +7,7 @@ begin from ( select w.*, - find_citizen_by_id(w.created_by_id) as created_by, - find_citizen_by_id(w.owner_id) as owner, + find_citizen_by_id_with_user(w.created_by_id) as created_by, find_workgroup_members(w.id) as members into resource from workgroup as w diff --git a/src/main/resources/sql/functions/workgroup/find_workgroup_by_id_simple.sql b/src/main/resources/sql/functions/workgroup/find_workgroup_by_id_simple.sql index 4187a4c..271a0b8 100644 --- a/src/main/resources/sql/functions/workgroup/find_workgroup_by_id_simple.sql +++ b/src/main/resources/sql/functions/workgroup/find_workgroup_by_id_simple.sql @@ -7,8 +7,7 @@ begin from ( select w.*, - json_build_object('id', w.created_by_id) as created_by, - json_build_object('id', w.owner_id) as owner + json_build_object('id', w.created_by_id) as created_by into resource from workgroup as w join citizen_in_workgroup ciw on w.id = ciw.workgroup_id diff --git a/src/main/resources/sql/functions/workgroup/find_workgroup_members.sql b/src/main/resources/sql/functions/workgroup/find_workgroup_members.sql index 0a012db..bde203a 100644 --- a/src/main/resources/sql/functions/workgroup/find_workgroup_members.sql +++ b/src/main/resources/sql/functions/workgroup/find_workgroup_members.sql @@ -4,8 +4,9 @@ begin select json_agg(t) into resource from ( select - z.*, - find_user_by_id(z.user_id) as "user" + w.id as id, + find_citizen_by_id_with_user(z.id) as citizen, + ciw.roles as roles from citizen_in_workgroup as ciw join workgroup as w on ciw.workgroup_id = w.id join citizen z on z.id = ciw.citizen_id diff --git a/src/main/resources/sql/functions/workgroup/find_workgroups.sql b/src/main/resources/sql/functions/workgroup/find_workgroups.sql index 29f985d..e696af2 100644 --- a/src/main/resources/sql/functions/workgroup/find_workgroups.sql +++ b/src/main/resources/sql/functions/workgroup/find_workgroups.sql @@ -21,8 +21,7 @@ begin from ( select w.*, - find_citizen_by_id(w.created_by_id) as created_by, - find_citizen_by_id(w.owner_id) as owner, + find_citizen_by_id_with_user(w.created_by_id) as created_by, zdb.score(w.ctid) _score from workgroup as w where deleted_at is null diff --git a/src/main/resources/sql/functions/workgroup/remove_workgroup_members.sql b/src/main/resources/sql/functions/workgroup/remove_workgroup_members.sql index bd41c3b..07dfb83 100644 --- a/src/main/resources/sql/functions/workgroup/remove_workgroup_members.sql +++ b/src/main/resources/sql/functions/workgroup/remove_workgroup_members.sql @@ -1,4 +1,4 @@ -create or replace function remove_workgroup_members(in _id uuid, inout resource json) +create or replace function remove_workgroup_members(in _id uuid, inout members json) language plpgsql as $$ begin @@ -6,11 +6,11 @@ begin where workgroup_id = _id and citizen_id in ( select - (z->>'id')::uuid - from json_array_elements(resource) z + (b#>>'{citizen, id}')::uuid + from json_array_elements(members) b ); - select find_workgroup_members(_id) into resource; + select find_workgroup_members(_id) into members; end $$; diff --git a/src/main/resources/sql/functions/workgroup/update_workgroup_members.sql b/src/main/resources/sql/functions/workgroup/update_workgroup_members.sql index 6b1e36b..43d5e3d 100644 --- a/src/main/resources/sql/functions/workgroup/update_workgroup_members.sql +++ b/src/main/resources/sql/functions/workgroup/update_workgroup_members.sql @@ -1,25 +1,20 @@ -create or replace function update_workgroup_members(in _id uuid, inout resource json) +create or replace function update_workgroup_members(in _id uuid, inout members json) language plpgsql as $$ begin - insert into citizen_in_workgroup (citizen_id, workgroup_id) - select - (z->>'id')::uuid, - _id::uuid - from json_array_elements(resource) z - where (z->>'id') is not null - on conflict do nothing; + perform add_workgroup_member(_id, b) + from json_array_elements(members) b; delete from citizen_in_workgroup where workgroup_id = _id and citizen_id not in( select - (z->>'id')::uuid - from json_array_elements(resource) z - where (z->>'id') is not null + (b#>>'{citizen, id}')::uuid + from json_array_elements(members) b + where (b#>>'{citizen, id}')::uuid is not null ); - select find_workgroup_members(_id) into resource; + select find_workgroup_members(_id) into members; end; $$; diff --git a/src/main/resources/sql/functions/workgroup/upsert_workgroup.sql b/src/main/resources/sql/functions/workgroup/upsert_workgroup.sql index 6e8789c..7338a3f 100644 --- a/src/main/resources/sql/functions/workgroup/upsert_workgroup.sql +++ b/src/main/resources/sql/functions/workgroup/upsert_workgroup.sql @@ -4,28 +4,27 @@ $$ declare new_id uuid = coalesce((resource->>'id')::uuid, uuid_generate_v4()); begin - insert into workgroup (id, created_by_id, name, description, anonymous, logo, owner_id) + insert into workgroup (id, created_by_id, name, description, anonymous, logo) select new_id, (resource#>>'{created_by, id}')::uuid, name, description, anonymous, - logo, - (resource#>>'{owner, id}')::uuid + logo from json_populate_record(null::workgroup, resource) on conflict (id) do update set name = excluded.name, description = excluded.description, anonymous = excluded.anonymous, - logo = excluded.logo, - owner_id = excluded.owner_id; + logo = excluded.logo; --- insert into citizen_in_workgroup (citizen_id, workgroup_id) --- select --- (resource->>'id')::uuid, --- new_id::uuid --- from json_populate_recordset(null::workgroup, resource->'members'); + insert into citizen_in_workgroup (workgroup_id, citizen_id, roles) + select + new_id::uuid, + (resource#>>'{created_by, id}')::uuid, + '{MASTER}' + from json_populate_recordset(null::workgroup, resource->'members'); select find_workgroup_by_id(new_id) into resource; end; diff --git a/src/main/resources/sql/migrations/0000-init_schema.up.sql b/src/main/resources/sql/migrations/0000-init_schema.up.sql index 1e87249..d170490 100644 --- a/src/main/resources/sql/migrations/0000-init_schema.up.sql +++ b/src/main/resources/sql/migrations/0000-init_schema.up.sql @@ -32,15 +32,15 @@ create table workgroup name varchar(128) not null, description text null, anonymous boolean default false not null, - logo text null, - owner_id uuid not null references citizen (id) + logo text null ); create table citizen_in_workgroup ( - citizen_id uuid not null references citizen (id), - workgroup_id uuid not null references workgroup (id), - created_at timestamptz default now() not null, + citizen_id uuid not null references citizen (id), + workgroup_id uuid not null references workgroup (id), + roles text[] not null, + created_at timestamptz default now() not null, primary key (citizen_id, workgroup_id) ); diff --git a/src/test/kotlin/feature/WorkgroupSteps.kt b/src/test/kotlin/feature/WorkgroupSteps.kt index d734d44..6c361a9 100644 --- a/src/test/kotlin/feature/WorkgroupSteps.kt +++ b/src/test/kotlin/feature/WorkgroupSteps.kt @@ -1,6 +1,7 @@ package feature import fr.dcproject.entity.* +import fr.dcproject.entity.WorkgroupWithMembersI.Member import fr.dcproject.utils.toUUID import io.cucumber.datatable.DataTable import io.cucumber.java8.En @@ -16,7 +17,10 @@ class WorkgroupSteps : En, KoinTest { init { When("I have members in workgroup {string}:") { workgroupId: String, members: DataTable -> val membersRefs = members.asList() - .map { CitizenRef(it.toUUID()) } + .map { Member( + citizen = CitizenRef(it.toUUID()), + roles = listOf(Member.Role.MASTER) + ) } get().addMembers(WorkgroupRef(workgroupId.toUUID()), membersRefs) } @@ -42,16 +46,11 @@ class WorkgroupSteps : En, KoinTest { } } - val owner = data["owner"]?.let { - get().findByUsername(it.toLowerCase().replace(' ', '-')) - } ?: 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 ) diff --git a/src/test/kotlin/security/voter/WorkgroupVoterTest.kt b/src/test/kotlin/security/voter/WorkgroupVoterTest.kt index bfc8b6c..7ea3edf 100644 --- a/src/test/kotlin/security/voter/WorkgroupVoterTest.kt +++ b/src/test/kotlin/security/voter/WorkgroupVoterTest.kt @@ -55,15 +55,15 @@ internal class WorkgroupVoterTest { createdBy = tesla, description = "Super desc", name = "super name", - owner = tesla, - anonymous = false + anonymous = false, + members = listOf(WorkgroupWithMembersI.Member(tesla, listOf(WorkgroupWithMembersI.Member.Role.MASTER))) ) private val workgroupAnon = WorkgroupEntity( createdBy = tesla, description = "Super desc", name = "super name", - owner = tesla, + members = listOf(WorkgroupWithMembersI.Member(tesla, listOf(WorkgroupWithMembersI.Member.Role.MASTER))), anonymous = true ) diff --git a/src/test/resources/feature/workgroup.feature b/src/test/resources/feature/workgroup.feature index 9eeaf70..be5d939 100644 --- a/src/test/resources/feature/workgroup.feature +++ b/src/test/resources/feature/workgroup.feature @@ -3,15 +3,21 @@ Feature: Workgroup Scenario: Can get one workgroup Given I have citizen Stephen Hawking + And I have citizen Sadi Carnot with ID "be3b0926-8628-4426-804a-75188a6eb315" + And I have citizen Joseph Fourier with ID "d9671eca-abaf-4b67-9230-3ece700c1ddb" And I am authenticated as Stephen Hawking And I have workgroup: | id | ab469134-bf14-4856-b093-ae1aa990f977 | | name | Les Mousquets | + And I have members in workgroup "ab469134-bf14-4856-b093-ae1aa990f977": + | be3b0926-8628-4426-804a-75188a6eb315 | + | d9671eca-abaf-4b67-9230-3ece700c1ddb | 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 | + And the response should contain object: + | $.id | ab469134-bf14-4856-b093-ae1aa990f977 | + | $.name | Les Mousquets | + | $.members[0].first_name | Sadi | Scenario: Can create a workgroup Given I have citizen Werner Heisenberg @@ -58,14 +64,19 @@ Feature: Workgroup And I have citizen Alessandro Volta with ID "b5bac515-45d4-4aeb-9b6d-2627a0bbc419" And I am authenticated as Blaise Pascal And I have workgroup: - | id | b0ea1922-3bc6-44e2-aa7c-40158998cfbb | - | name | Les bonobos | - | owner | Blaise Pascal | + | id | b0ea1922-3bc6-44e2-aa7c-40158998cfbb | + | name | Les bonobos | When I send a POST request to "/workgroups/b0ea1922-3bc6-44e2-aa7c-40158998cfbb/members" with body: """ [ - {"id":"6d883fe7-5fc0-4a50-8858-72230673eba4"}, - {"id":"b5bac515-45d4-4aeb-9b6d-2627a0bbc419"} + { + "id":"6d883fe7-5fc0-4a50-8858-72230673eba4", + "roles": ["MASTER"] + }, + { + "id":"b5bac515-45d4-4aeb-9b6d-2627a0bbc419", + "roles": ["MASTER"] + } ] """ Then the response status code should be 201 @@ -76,21 +87,23 @@ Feature: Workgroup And I have citizen Paul Dirac with ID "1baf48bb-02bc-4d8f-ac86-33335354f5e7" And I am authenticated as Heinrich Hertz And I have workgroup: - | id | b6c975df-dd44-4e99-adc1-f605746b0e11 | - | name | Les Tacos | - | owner | Heinrich Hertz | + | id | b6c975df-dd44-4e99-adc1-f605746b0e11 | + | name | Les Tacos | And I have members in workgroup "b6c975df-dd44-4e99-adc1-f605746b0e11": | 87909ba3-2069-431c-9924-219fd8411cf2 | | 1baf48bb-02bc-4d8f-ac86-33335354f5e7 | When I send a DELETE request to "/workgroups/b6c975df-dd44-4e99-adc1-f605746b0e11/members" with body: """ [ - {"id":"87909ba3-2069-431c-9924-219fd8411cf2"} + { + "id":"87909ba3-2069-431c-9924-219fd8411cf2", + "roles": ["MASTER"] + } ] """ Then the response status code should be 200 And the response should contain object: - | $.[0]id | 1baf48bb-02bc-4d8f-ac86-33335354f5e7 | + | $.[0]citizen.id | 1baf48bb-02bc-4d8f-ac86-33335354f5e7 | And the JSON should have 1 items Scenario: Can update members on workgroup @@ -100,21 +113,26 @@ Feature: Workgroup And I have citizen Georg Ohm with ID "b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1" And I am authenticated as Leon Foucault And I have workgroup: - | id | 784fe6bc-7635-4ae2-b080-3a4743b998bf | - | name | Les Tacos | - | owner | Leon Foucault | + | id | 784fe6bc-7635-4ae2-b080-3a4743b998bf | + | name | Les Tacos | And I have members in workgroup "784fe6bc-7635-4ae2-b080-3a4743b998bf": | be3b0926-8628-4426-804a-75188a6eb315 | | d9671eca-abaf-4b67-9230-3ece700c1ddb | When I send a PUT request to "/workgroups/784fe6bc-7635-4ae2-b080-3a4743b998bf/members" with body: """ [ - {"id":"be3b0926-8628-4426-804a-75188a6eb315"}, - {"id":"b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1"} + { + "id":"be3b0926-8628-4426-804a-75188a6eb315", + "roles": ["MASTER"] + }, + { + "id":"b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1", + "roles": ["MASTER"] + } ] """ Then the response status code should be 200 And the response should contain object: - | $.[0]id | be3b0926-8628-4426-804a-75188a6eb315 | - | $.[1]id | b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1 | + | $.[0]citizen.id | be3b0926-8628-4426-804a-75188a6eb315 | + | $.[1]citizen.id | b49e20c1-8393-45d6-a6a0-3fa5c71cbdc1 | And the JSON should have 2 items \ No newline at end of file diff --git a/src/test/sql/fixtures/3-fixture_workgroup.sql b/src/test/sql/fixtures/3-fixture_workgroup.sql index a2178e3..0390263 100644 --- a/src/test/sql/fixtures/3-fixture_workgroup.sql +++ b/src/test/sql/fixtures/3-fixture_workgroup.sql @@ -19,7 +19,6 @@ begin end if; created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; - created_workgroup := jsonb_set(created_workgroup::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text); -- upsert workgroup diff --git a/src/test/sql/workgroup.sql b/src/test/sql/workgroup.sql index 1c4e17b..be31877 100644 --- a/src/test/sql/workgroup.sql +++ b/src/test/sql/workgroup.sql @@ -16,9 +16,9 @@ declare }'; selected_workgroup json; members json; + selected_citizen json; begin created_workgroup := jsonb_set(created_workgroup::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; - created_workgroup := jsonb_set(created_workgroup::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; assert created_workgroup#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup#>>'{created_by, id}', _citizen_id::text); -- upsert workgroup @@ -28,7 +28,6 @@ begin -- insert another workgroup created_workgroup_2 := jsonb_set(created_workgroup_2::jsonb, '{created_by}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; - created_workgroup_2 := jsonb_set(created_workgroup_2::jsonb, '{owner}'::text[], jsonb_build_object('id', _citizen_id::text), true)::json; assert created_workgroup_2#>>'{created_by, id}' = _citizen_id::text, format('citizenId in workgroup must be the same as citizen, %s != %s', created_workgroup_2#>>'{created_by, id}', _citizen_id::text); select upsert_workgroup(created_workgroup_2) into created_workgroup_2; @@ -47,44 +46,61 @@ begin -- add select m into members from add_workgroup_members((created_workgroup->>'id')::uuid, json_build_array( - json_build_object('id', _citizen_id2), - json_build_object('id', _citizen_id3) + json_build_object('citizen', json_build_object('id', _citizen_id2), 'roles', '{MASTER}'::text[]), + json_build_object('citizen', json_build_object('id', _citizen_id3), 'roles', '{MASTER}'::text[]) )) m; assert json_array_length(members) = 2, 'The members count must be equal to 2'; - assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id3)), + assert (members::jsonb) @> jsonb_build_array(jsonb_build_object( + 'id', (created_workgroup->>'id'), + 'citizen', jsonb_build_object('id', _citizen_id3), + 'roles', jsonb_build_array('MASTER') + )), 'Members must contain citizen3'; - -- Check if "find_citizen_by_id" retrun workgroups of citizen - assert (select find_citizen_by_id(_citizen_id2)#>>'{workgroups, 0, id}') = (created_workgroup->>'id'), 'find_citizen_by_id must return workgroups'; + -- Check if "find_citizen_by_id" retrun citizen + assert (select find_citizen_by_id(_citizen_id2)#>>'{id}')::uuid = _citizen_id2, 'find_citizen_by_id must return citizen'; + + -- Check if "find_citizen_by_id_with_user_and_workgroups" retrun workgroups of citizen + select find_citizen_by_id_with_user_and_workgroups(_citizen_id3) into selected_citizen; + assert selected_citizen#>>'{workgroups, 0, roles, 0}' = 'MASTER', format('workgroup must have MASTER role, %s', selected_citizen#>>'{workgroups, 0, roles, 0}'); -- update select m into members from update_workgroup_members((created_workgroup->>'id')::uuid, json_build_array( - json_build_object('id', _citizen_id2), - json_build_object('id', _citizen_id) + json_build_object('citizen', json_build_object('id', _citizen_id2), 'roles', '{MASTER}'::text[]), + json_build_object('citizen', json_build_object('id', _citizen_id), 'roles', '{MASTER}'::text[]) )) m; assert json_array_length(members) = 2, 'The members count must be equal to 2'; - assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id)), - 'Members must contain citizen2'; - assert not members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id3)), - 'Members must NOT contain citizen3'; + assert (members::jsonb) @> jsonb_build_array(jsonb_build_object( + 'id', (created_workgroup->>'id'), + 'citizen', jsonb_build_object('id', _citizen_id), + 'roles', jsonb_build_array('MASTER') + )), 'Members must contain citizen1'; + assert not (members::jsonb) @> jsonb_build_array(jsonb_build_object( + 'citizen', jsonb_build_object('id', _citizen_id3) + )), 'Members must NOT contain citizen3'; -- remove - select m into members from remove_workgroup_members((created_workgroup->>'id')::uuid, json_build_array( - json_build_object('id', _citizen_id2) - )) m; + select m into members from remove_workgroup_members((created_workgroup->>'id')::uuid, json_build_array(jsonb_build_object( + 'citizen', json_build_object('id', _citizen_id2) + ))) m; assert json_array_length(members) = 1, 'The members count must be equal to 1'; - assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id)), - 'Members must contain citizen1'; - assert not members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id2)), - 'Members must NOT contain citizen2'; + assert (members::jsonb) @> jsonb_build_array(jsonb_build_object( + 'citizen', jsonb_build_object('id', _citizen_id) + )), 'Members must contain citizen1'; + assert not (members::jsonb) @> jsonb_build_array(jsonb_build_object( + 'citizen', jsonb_build_object('id', _citizen_id2) + )), 'Members must NOT contain citizen2'; select m into members from find_workgroup_members((created_workgroup->>'id')::uuid) m; assert json_array_length(members) = 1, 'The members count must be equal to 1'; - assert members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id)), - 'Members must contain citizen1'; - assert not members::jsonb @> jsonb_build_array(jsonb_build_object('id', _citizen_id2)), - 'Members must NOT contain citizen2'; + assert (members::jsonb) @> jsonb_build_array(jsonb_build_object( + 'citizen', jsonb_build_object('id', _citizen_id) + )), 'Members must contain citizen1'; + assert not (members::jsonb) @> jsonb_build_array(jsonb_build_object( + 'citizen', jsonb_build_object('id', _citizen_id2) + )), 'Members must NOT contain citizen2'; + -- Check if find_workgroup_by_id return members select find_workgroup_by_id((created_workgroup->>'id')::uuid) into selected_workgroup; assert json_array_length(selected_workgroup->'members') = 1, 'Workgroup must have members';