mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2026-02-06 09:56:03 +00:00
refactor(backend): properly model group-membership (#9124)
This commit is contained in:
parent
bea7c275e8
commit
d96cb32f11
@ -3,10 +3,14 @@ import gql from 'graphql-tag'
|
||||
export const ChangeGroupMemberRole = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
|
||||
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -3,10 +3,14 @@ import gql from 'graphql-tag'
|
||||
export const GroupMembers = gql`
|
||||
query GroupMembers($id: ID!) {
|
||||
GroupMembers(id: $id) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -3,10 +3,14 @@ import gql from 'graphql-tag'
|
||||
export const JoinGroup = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
JoinGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -3,10 +3,14 @@ import gql from 'graphql-tag'
|
||||
export const LeaveGroup = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
LeaveGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -3,10 +3,14 @@ import gql from 'graphql-tag'
|
||||
export const RemoveUserFromGroup = gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
RemoveUserFromGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -891,8 +891,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
JoinGroup: {
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: {
|
||||
id: 'owner-of-closed-group',
|
||||
},
|
||||
membership: {
|
||||
role: 'usual',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -914,8 +918,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
JoinGroup: {
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'owner',
|
||||
user: {
|
||||
id: 'current-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -939,8 +947,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
JoinGroup: {
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'pending',
|
||||
user: {
|
||||
id: 'current-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'pending',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -962,8 +974,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
JoinGroup: {
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'owner',
|
||||
user: {
|
||||
id: 'owner-of-closed-group',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -1001,8 +1017,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
JoinGroup: {
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'owner',
|
||||
user: {
|
||||
id: 'owner-of-hidden-group',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -1208,16 +1228,28 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1241,16 +1273,28 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1274,16 +1318,28 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1317,16 +1373,28 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'pending',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'pending',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1350,16 +1418,28 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'pending',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'pending',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1415,20 +1495,36 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'pending-user',
|
||||
myRoleInGroup: 'pending',
|
||||
user: expect.objectContaining({
|
||||
id: 'pending-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'pending',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'admin',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'admin',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1452,20 +1548,36 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'pending-user',
|
||||
myRoleInGroup: 'pending',
|
||||
user: expect.objectContaining({
|
||||
id: 'pending-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'pending',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'admin',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'admin',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1489,20 +1601,36 @@ describe('in mode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 'pending-user',
|
||||
myRoleInGroup: 'pending',
|
||||
user: expect.objectContaining({
|
||||
id: 'pending-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'pending',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'current-user',
|
||||
myRoleInGroup: 'usual',
|
||||
user: expect.objectContaining({
|
||||
id: 'current-user',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'usual',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
myRoleInGroup: 'admin',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-closed-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'admin',
|
||||
}),
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
myRoleInGroup: 'owner',
|
||||
user: expect.objectContaining({
|
||||
id: 'owner-of-hidden-group',
|
||||
}),
|
||||
membership: expect.objectContaining({
|
||||
role: 'owner',
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
},
|
||||
@ -1600,8 +1728,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: 'usual',
|
||||
user: {
|
||||
id: 'usual-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'usual',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -1638,8 +1770,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'admin-member-user',
|
||||
myRoleInGroup: 'admin',
|
||||
user: {
|
||||
id: 'admin-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'admin',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -1673,8 +1809,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'second-owner-member-user',
|
||||
myRoleInGroup: 'owner',
|
||||
user: {
|
||||
id: 'second-owner-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -1759,8 +1899,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'owner-member-user',
|
||||
myRoleInGroup: 'owner',
|
||||
user: {
|
||||
id: 'owner-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -1869,8 +2013,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'admin-member-user',
|
||||
myRoleInGroup: 'owner',
|
||||
user: {
|
||||
id: 'admin-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -2047,8 +2195,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: 'admin',
|
||||
user: {
|
||||
id: 'usual-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'admin',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -2073,8 +2225,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: 'usual',
|
||||
user: {
|
||||
id: 'usual-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'usual',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -2234,8 +2390,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'pending-member-user',
|
||||
myRoleInGroup: 'usual',
|
||||
user: {
|
||||
id: 'pending-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'usual',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -2260,8 +2420,12 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
id: 'pending-member-user',
|
||||
myRoleInGroup: 'pending',
|
||||
user: {
|
||||
id: 'pending-member-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'pending',
|
||||
},
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -2413,7 +2577,7 @@ describe('in mode', () => {
|
||||
},
|
||||
})
|
||||
return result.data?.GroupMembers
|
||||
? !!result.data.GroupMembers.find((member) => member.id === userId)
|
||||
? !!result.data.GroupMembers.find((member) => member.user.id === userId)
|
||||
: null
|
||||
}
|
||||
|
||||
@ -2440,8 +2604,10 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
LeaveGroup: {
|
||||
id: 'pending-member-user',
|
||||
myRoleInGroup: null,
|
||||
user: {
|
||||
id: 'pending-member-user',
|
||||
},
|
||||
membership: null,
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -2467,8 +2633,10 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
LeaveGroup: {
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: null,
|
||||
user: {
|
||||
id: 'usual-member-user',
|
||||
},
|
||||
membership: null,
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -2494,8 +2662,10 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
LeaveGroup: {
|
||||
id: 'admin-member-user',
|
||||
myRoleInGroup: null,
|
||||
user: {
|
||||
id: 'admin-member-user',
|
||||
},
|
||||
membership: null,
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
@ -3021,8 +3191,10 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
RemoveUserFromGroup: expect.objectContaining({
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: null,
|
||||
user: expect.objectContaining({
|
||||
id: 'usual-member-user',
|
||||
}),
|
||||
membership: null,
|
||||
}),
|
||||
},
|
||||
errors: undefined,
|
||||
@ -3093,8 +3265,10 @@ describe('in mode', () => {
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
RemoveUserFromGroup: expect.objectContaining({
|
||||
id: 'usual-member-user',
|
||||
myRoleInGroup: null,
|
||||
user: {
|
||||
id: 'usual-member-user',
|
||||
},
|
||||
membership: null,
|
||||
}),
|
||||
},
|
||||
errors: undefined,
|
||||
|
||||
@ -63,7 +63,7 @@ export default {
|
||||
const readTxResultPromise = session.readTransaction(async (txc) => {
|
||||
const groupMemberCypher = `
|
||||
MATCH (user:User)-[membership:MEMBER_OF]->(:Group {id: $groupId})
|
||||
RETURN user {.*, myRoleInGroup: membership.role}
|
||||
RETURN user {.*}, membership {.*}
|
||||
SKIP toInteger($offset) LIMIT toInteger($first)
|
||||
`
|
||||
const transactionResponse = await txc.run(groupMemberCypher, {
|
||||
@ -71,7 +71,9 @@ export default {
|
||||
first,
|
||||
offset,
|
||||
})
|
||||
return transactionResponse.records.map((record) => record.get('user'))
|
||||
return transactionResponse.records.map((record) => {
|
||||
return { user: record.get('user'), membership: record.get('membership') }
|
||||
})
|
||||
})
|
||||
try {
|
||||
return await readTxResultPromise
|
||||
@ -273,8 +275,8 @@ export default {
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
|
||||
const joinGroupCypher = `
|
||||
MATCH (member:User {id: $userId}), (group:Group {id: $groupId})
|
||||
MERGE (member)-[membership:MEMBER_OF]->(group)
|
||||
MATCH (user:User {id: $userId}), (group:Group {id: $groupId})
|
||||
MERGE (user)-[membership:MEMBER_OF]->(group)
|
||||
ON CREATE SET
|
||||
membership.createdAt = toString(datetime()),
|
||||
membership.updatedAt = null,
|
||||
@ -283,14 +285,15 @@ export default {
|
||||
THEN 'usual'
|
||||
ELSE 'pending'
|
||||
END
|
||||
RETURN member {.*, myRoleInGroup: membership.role}
|
||||
RETURN user {.*}, membership {.*}
|
||||
`
|
||||
const transactionResponse = await transaction.run(joinGroupCypher, { groupId, userId })
|
||||
const [member] = transactionResponse.records.map((record) => record.get('member'))
|
||||
return member
|
||||
return transactionResponse.records.map((record) => {
|
||||
return { user: record.get('user'), membership: record.get('membership') }
|
||||
})
|
||||
})
|
||||
try {
|
||||
return await writeTxResultPromise
|
||||
return (await writeTxResultPromise)[0]
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
@ -337,7 +340,7 @@ export default {
|
||||
membership.updatedAt = toString(datetime()),
|
||||
membership.role = $roleInGroup
|
||||
${postRestrictionCypher}
|
||||
RETURN member {.*, myRoleInGroup: membership.role}
|
||||
RETURN member {.*} as user, membership {.*}
|
||||
`
|
||||
|
||||
const transactionResponse = await transaction.run(joinGroupCypher, {
|
||||
@ -345,7 +348,9 @@ export default {
|
||||
userId,
|
||||
roleInGroup,
|
||||
})
|
||||
const [member] = transactionResponse.records.map((record) => record.get('member'))
|
||||
const [member] = transactionResponse.records.map((record) => {
|
||||
return { user: record.get('user'), membership: record.get('membership') }
|
||||
})
|
||||
return member
|
||||
})
|
||||
try {
|
||||
@ -528,14 +533,16 @@ const removeUserFromGroupWriteTxResultPromise = async (session, groupId, userId)
|
||||
WITH user, collect(p) AS posts
|
||||
FOREACH (post IN posts |
|
||||
MERGE (user)-[:CANNOT_SEE]->(post))
|
||||
RETURN user {.*, myRoleInGroup: NULL}
|
||||
RETURN user {.*}, NULL as membership
|
||||
`
|
||||
|
||||
const transactionResponse = await transaction.run(removeUserFromGroupCypher, {
|
||||
groupId,
|
||||
userId,
|
||||
})
|
||||
const [user] = await transactionResponse.records.map((record) => record.get('user'))
|
||||
const [user] = await transactionResponse.records.map((record) => {
|
||||
return { user: record.get('user'), membership: record.get('membership') }
|
||||
})
|
||||
return user
|
||||
})
|
||||
}
|
||||
|
||||
@ -1089,16 +1089,24 @@ describe('redeemInviteCode', () => {
|
||||
data: {
|
||||
GroupMembers: expect.arrayContaining([
|
||||
{
|
||||
id: 'inviting-user',
|
||||
myRoleInGroup: 'owner',
|
||||
name: 'Inviting User',
|
||||
slug: 'inviting-user',
|
||||
user: {
|
||||
id: 'inviting-user',
|
||||
name: 'Inviting User',
|
||||
slug: 'inviting-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'other-user',
|
||||
myRoleInGroup: 'pending',
|
||||
name: 'Other User',
|
||||
slug: 'other-user',
|
||||
user: {
|
||||
id: 'other-user',
|
||||
name: 'Other User',
|
||||
slug: 'other-user',
|
||||
},
|
||||
membership: {
|
||||
role: 'pending',
|
||||
},
|
||||
},
|
||||
]),
|
||||
},
|
||||
|
||||
@ -55,6 +55,11 @@ type Group {
|
||||
currentlyPinnedPostsCount: Int! @neo4j_ignore
|
||||
}
|
||||
|
||||
type GroupMember {
|
||||
user: User
|
||||
membership: MEMBER_OF
|
||||
}
|
||||
|
||||
input _GroupFilter {
|
||||
AND: [_GroupFilter!]
|
||||
OR: [_GroupFilter!]
|
||||
@ -82,7 +87,7 @@ type Query {
|
||||
# orderBy: [_GroupOrdering] # not implemented yet
|
||||
# filter: _GroupFilter # not implemented yet
|
||||
|
||||
GroupMembers(id: ID!, first: Int, offset: Int): [User]
|
||||
GroupMembers(id: ID!, first: Int, offset: Int): [GroupMember]
|
||||
# orderBy: [_UserOrdering] # not implemented yet
|
||||
# filter: _UserFilter # not implemented yet
|
||||
|
||||
@ -128,13 +133,13 @@ type Mutation {
|
||||
|
||||
# DeleteGroup(id: ID!): Group
|
||||
|
||||
JoinGroup(groupId: ID!, userId: ID!): User
|
||||
JoinGroup(groupId: ID!, userId: ID!): GroupMember
|
||||
|
||||
LeaveGroup(groupId: ID!, userId: ID!): User
|
||||
LeaveGroup(groupId: ID!, userId: ID!): GroupMember
|
||||
|
||||
ChangeGroupMemberRole(groupId: ID!, userId: ID!, roleInGroup: GroupMemberRole!): User
|
||||
ChangeGroupMemberRole(groupId: ID!, userId: ID!, roleInGroup: GroupMemberRole!): GroupMember
|
||||
|
||||
RemoveUserFromGroup(groupId: ID!, userId: ID!): User
|
||||
RemoveUserFromGroup(groupId: ID!, userId: ID!): GroupMember
|
||||
|
||||
muteGroup(groupId: ID!): Group
|
||||
unmuteGroup(groupId: ID!): Group
|
||||
|
||||
@ -153,8 +153,6 @@ type User {
|
||||
emotions: [EMOTED]
|
||||
|
||||
activeCategories: [String] @neo4j_ignore
|
||||
|
||||
myRoleInGroup: GroupMemberRole
|
||||
}
|
||||
|
||||
input _UserFilter {
|
||||
|
||||
@ -52,10 +52,14 @@ describe('CtaJoinLeaveGroup.vue', () => {
|
||||
mocks.$apollo.mutate = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
JoinGroup: {
|
||||
id: 'g-123',
|
||||
slug: 'group-123',
|
||||
name: 'Group 123',
|
||||
myRoleInGroup: 'usual',
|
||||
user: {
|
||||
id: 'g-123',
|
||||
slug: 'group-123',
|
||||
name: 'Group 123',
|
||||
},
|
||||
membership: {
|
||||
role: 'usual',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -66,10 +70,14 @@ describe('CtaJoinLeaveGroup.vue', () => {
|
||||
expect(wrapper.emitted().update).toEqual([
|
||||
[
|
||||
{
|
||||
id: 'g-123',
|
||||
slug: 'group-123',
|
||||
name: 'Group 123',
|
||||
myRoleInGroup: 'usual',
|
||||
user: {
|
||||
id: 'g-123',
|
||||
slug: 'group-123',
|
||||
name: 'Group 123',
|
||||
},
|
||||
membership: {
|
||||
role: 'usual',
|
||||
},
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
@ -8,14 +8,22 @@ const propsData = {
|
||||
groupId: 'group-id',
|
||||
groupMembers: [
|
||||
{
|
||||
slug: 'owner',
|
||||
id: 'owner',
|
||||
myRoleInGroup: 'owner',
|
||||
user: {
|
||||
slug: 'owner',
|
||||
id: 'owner',
|
||||
},
|
||||
membership: {
|
||||
role: 'owner',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
myRoleInGroup: 'usual',
|
||||
user: {
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
},
|
||||
membership: {
|
||||
role: 'usual',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -30,9 +38,13 @@ const apolloMock = jest
|
||||
.mockResolvedValue({
|
||||
data: {
|
||||
ChangeGroupMemberRole: {
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
myRoleInGroup: 'admin',
|
||||
user: {
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
},
|
||||
membership: {
|
||||
role: 'admin',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@ -117,9 +129,11 @@ describe('GroupMember', () => {
|
||||
apolloMock.mockRejectedValueOnce({ message: 'Oh no!!' }).mockResolvedValue({
|
||||
data: {
|
||||
RemoveUserFromGroup: {
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
myRoleInGroup: null,
|
||||
user: {
|
||||
slug: 'user',
|
||||
id: 'user',
|
||||
},
|
||||
membership: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@ -7,21 +7,21 @@
|
||||
<nuxt-link
|
||||
:to="{
|
||||
name: 'profile-id-slug',
|
||||
params: { id: scope.row.id, slug: scope.row.slug },
|
||||
params: { id: scope.row.user.id, slug: scope.row.user.slug },
|
||||
}"
|
||||
>
|
||||
<profile-avatar :profile="scope.row" size="small" />
|
||||
<profile-avatar :profile="scope.row.user" size="small" />
|
||||
</nuxt-link>
|
||||
</template>
|
||||
<template #name="scope">
|
||||
<nuxt-link
|
||||
:to="{
|
||||
name: 'profile-id-slug',
|
||||
params: { id: scope.row.id, slug: scope.row.slug },
|
||||
params: { id: scope.row.user.id, slug: scope.row.user.slug },
|
||||
}"
|
||||
>
|
||||
<ds-text>
|
||||
<b>{{ scope.row.name | truncate(20) }}</b>
|
||||
<b>{{ scope.row.user.name | truncate(20) }}</b>
|
||||
</ds-text>
|
||||
</nuxt-link>
|
||||
</template>
|
||||
@ -29,37 +29,37 @@
|
||||
<nuxt-link
|
||||
:to="{
|
||||
name: 'profile-id-slug',
|
||||
params: { id: scope.row.id, slug: scope.row.slug },
|
||||
params: { id: scope.row.user.id, slug: scope.row.user.slug },
|
||||
}"
|
||||
>
|
||||
<ds-text>
|
||||
<b>{{ `@${scope.row.slug}` | truncate(20) }}</b>
|
||||
<b>{{ `@${scope.row.user.slug}` | truncate(20) }}</b>
|
||||
</ds-text>
|
||||
</nuxt-link>
|
||||
</template>
|
||||
<template #roleInGroup="scope">
|
||||
<select
|
||||
v-if="scope.row.myRoleInGroup !== 'owner'"
|
||||
v-if="scope.row.membership.role !== 'owner'"
|
||||
:options="['pending', 'usual', 'admin', 'owner']"
|
||||
:value="`${scope.row.myRoleInGroup}`"
|
||||
@change="changeMemberRole(scope.row.id, $event)"
|
||||
:value="`${scope.row.membership.role}`"
|
||||
@change="changeMemberRole(scope.row.user.id, $event)"
|
||||
>
|
||||
<option v-for="role in ['pending', 'usual', 'admin', 'owner']" :key="role" :value="role">
|
||||
{{ $t(`group.roles.${role}`) }}
|
||||
</option>
|
||||
</select>
|
||||
<ds-chip v-else color="primary">
|
||||
{{ $t(`group.roles.${scope.row.myRoleInGroup}`) }}
|
||||
{{ $t(`group.roles.${scope.row.membership.role}`) }}
|
||||
</ds-chip>
|
||||
</template>
|
||||
<template #edit="scope">
|
||||
<base-button
|
||||
v-if="scope.row.myRoleInGroup !== 'owner'"
|
||||
v-if="scope.row.membership.role !== 'owner'"
|
||||
size="small"
|
||||
primary
|
||||
@click="
|
||||
isOpen = true
|
||||
userId = scope.row.id
|
||||
userId = scope.row.user.id
|
||||
"
|
||||
>
|
||||
{{ $t('group.removeMemberButton') }}
|
||||
|
||||
@ -111,10 +111,14 @@ export const joinGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
JoinGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -124,10 +128,14 @@ export const leaveGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
LeaveGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -137,10 +145,14 @@ export const changeGroupMemberRoleMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
|
||||
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -150,10 +162,14 @@ export const removeUserFromGroupMutation = () => {
|
||||
return gql`
|
||||
mutation ($groupId: ID!, $userId: ID!) {
|
||||
RemoveUserFromGroup(groupId: $groupId, userId: $userId) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -215,12 +231,16 @@ export const groupMembersQuery = () => {
|
||||
|
||||
query ($id: ID!, $first: Int, $offset: Int) {
|
||||
GroupMembers(id: $id, first: $first, offset: $offset) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
myRoleInGroup
|
||||
avatar {
|
||||
...imageUrls
|
||||
user {
|
||||
id
|
||||
name
|
||||
slug
|
||||
avatar {
|
||||
...imageUrls
|
||||
}
|
||||
}
|
||||
membership {
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +244,12 @@ describe('GroupProfileSlug', () => {
|
||||
...yogaPractice,
|
||||
myRole: 'owner',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -282,7 +287,12 @@ describe('GroupProfileSlug', () => {
|
||||
...yogaPractice,
|
||||
myRole: 'usual',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -301,7 +311,12 @@ describe('GroupProfileSlug', () => {
|
||||
...yogaPractice,
|
||||
myRole: 'pending',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -320,7 +335,12 @@ describe('GroupProfileSlug', () => {
|
||||
...yogaPractice,
|
||||
myRole: null,
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -342,7 +362,12 @@ describe('GroupProfileSlug', () => {
|
||||
...schoolForCitizens,
|
||||
myRole: 'owner',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -361,7 +386,12 @@ describe('GroupProfileSlug', () => {
|
||||
...schoolForCitizens,
|
||||
myRole: 'usual',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -403,7 +433,12 @@ describe('GroupProfileSlug', () => {
|
||||
...schoolForCitizens,
|
||||
myRole: 'pending',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -422,7 +457,12 @@ describe('GroupProfileSlug', () => {
|
||||
...schoolForCitizens,
|
||||
myRole: null,
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -445,7 +485,12 @@ describe('GroupProfileSlug', () => {
|
||||
...investigativeJournalism,
|
||||
myRole: 'owner',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -464,7 +509,12 @@ describe('GroupProfileSlug', () => {
|
||||
...investigativeJournalism,
|
||||
myRole: 'usual',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -483,7 +533,12 @@ describe('GroupProfileSlug', () => {
|
||||
...investigativeJournalism,
|
||||
myRole: 'pending',
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -502,7 +557,12 @@ describe('GroupProfileSlug', () => {
|
||||
...investigativeJournalism,
|
||||
myRole: null,
|
||||
},
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
GroupMembers: [
|
||||
{ user: peterLustig, membership: { role: 'owner' } },
|
||||
{ user: jennyRostock, membership: { role: 'usual' } },
|
||||
{ user: bobDerBaumeister, membership: { role: 'usual' } },
|
||||
{ user: huey, membership: { role: 'usual' } },
|
||||
],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -181,7 +181,7 @@
|
||||
:allProfilesCount="
|
||||
isAllowedSeeingGroupMembers && group.membersCount ? group.membersCount : 0
|
||||
"
|
||||
:profiles="isAllowedSeeingGroupMembers ? groupMembers : []"
|
||||
:profiles="isAllowedSeeingGroupMembers ? groupMembers.map((d) => d.user) : []"
|
||||
:loading="$apollo.loading"
|
||||
@fetchAllProfiles="fetchAllMembers"
|
||||
/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user