diff --git a/backend/src/db/graphql/groups.js b/backend/src/db/graphql/groups.js
index b169e10fb..8486288ec 100644
--- a/backend/src/db/graphql/groups.js
+++ b/backend/src/db/graphql/groups.js
@@ -39,9 +39,9 @@ export const createGroupMutation = gql`
}
`
-export const enterGroupMutation = gql`
+export const joinGroupMutation = gql`
mutation ($id: ID!, $userId: ID!) {
- EnterGroup(id: $id, userId: $userId) {
+ JoinGroup(id: $id, userId: $userId) {
id
name
slug
diff --git a/backend/src/db/seed.js b/backend/src/db/seed.js
index ebe8a6020..f9b2d05da 100644
--- a/backend/src/db/seed.js
+++ b/backend/src/db/seed.js
@@ -5,7 +5,7 @@ import createServer from '../server'
import faker from '@faker-js/faker'
import Factory from '../db/factories'
import { getNeode, getDriver } from '../db/neo4j'
-import { createGroupMutation, enterGroupMutation } from './graphql/groups'
+import { createGroupMutation, joinGroupMutation } from './graphql/groups'
import { createPostMutation } from './graphql/posts'
import { createCommentMutation } from './graphql/comments'
@@ -402,14 +402,14 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
])
await Promise.all([
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g0',
userId: 'u2',
},
}),
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g0',
userId: 'u3',
@@ -434,28 +434,28 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
])
await Promise.all([
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g1',
userId: 'u1',
},
}),
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g1',
userId: 'u5',
},
}),
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g1',
userId: 'u6',
},
}),
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g1',
userId: 'u7',
@@ -480,28 +480,28 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
])
await Promise.all([
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g2',
userId: 'u4',
},
}),
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g2',
userId: 'u5',
},
}),
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g2',
userId: 'u6',
},
}),
mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'g2',
userId: 'u7',
diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js
index dc54d5a29..afdc5501e 100644
--- a/backend/src/middleware/permissionsMiddleware.js
+++ b/backend/src/middleware/permissionsMiddleware.js
@@ -64,22 +64,26 @@ const isAllowedSeeingMembersOfGroup = rule({
const transactionResponse = await transaction.run(
`
MATCH (group:Group {id: $groupId})
- OPTIONAL MATCH (admin:User {id: $userId})-[membership:MEMBER_OF]->(group)
- WHERE membership.role IN ['admin', 'owner']
- RETURN group {.*}, admin {.*, myRoleInGroup: membership.role}
+ OPTIONAL MATCH (member:User {id: $userId})-[membership:MEMBER_OF]->(group)
+ RETURN group {.*}, member {.*, myRoleInGroup: membership.role}
`,
{ groupId, userId: user.id },
)
return {
- admin: transactionResponse.records.map((record) => record.get('admin'))[0],
+ member: transactionResponse.records.map((record) => record.get('member'))[0],
group: transactionResponse.records.map((record) => record.get('group'))[0],
}
})
try {
- const { admin, group } = await readTxPromise
- // Wolle: console.log('admin: ', admin)
+ const { member, group } = await readTxPromise
+ // Wolle: console.log('member: ', member)
// console.log('group: ', group)
- return group.groupType === 'public' || !!admin
+ return (
+ group.groupType === 'public' ||
+ (['closed', 'hidden'].includes(group.groupType) &&
+ !!member &&
+ ['usual', 'admin', 'owner'].includes(member.myRoleInGroup))
+ )
} catch (error) {
// Wolle: console.log('error: ', error)
throw new Error(error)
@@ -179,7 +183,7 @@ export default shield(
SignupVerification: allow,
UpdateUser: onlyYourself,
CreateGroup: isAuthenticated,
- EnterGroup: isAuthenticated,
+ JoinGroup: isAuthenticated,
CreatePost: isAuthenticated,
UpdatePost: isAuthor,
DeletePost: isAuthor,
diff --git a/backend/src/schema/resolvers/groups.js b/backend/src/schema/resolvers/groups.js
index 91135a1db..c9a31fdc3 100644
--- a/backend/src/schema/resolvers/groups.js
+++ b/backend/src/schema/resolvers/groups.js
@@ -131,11 +131,11 @@ export default {
session.close()
}
},
- EnterGroup: async (_parent, params, context, _resolveInfo) => {
+ JoinGroup: async (_parent, params, context, _resolveInfo) => {
const { id: groupId, userId } = params
const session = context.driver.session()
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
- const enterGroupCypher = `
+ const joinGroupCypher = `
MATCH (member:User {id: $userId}), (group:Group {id: $groupId})
MERGE (member)-[membership:MEMBER_OF]->(group)
ON CREATE SET
@@ -148,7 +148,7 @@ export default {
END
RETURN member {.*, myRoleInGroup: membership.role}
`
- const result = await transaction.run(enterGroupCypher, { groupId, userId })
+ const result = await transaction.run(joinGroupCypher, { groupId, userId })
const [member] = await result.records.map((record) => record.get('member'))
return member
})
diff --git a/backend/src/schema/resolvers/groups.spec.js b/backend/src/schema/resolvers/groups.spec.js
index 33aeaf2bd..87eb02dc0 100644
--- a/backend/src/schema/resolvers/groups.spec.js
+++ b/backend/src/schema/resolvers/groups.spec.js
@@ -2,7 +2,7 @@ import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import {
createGroupMutation,
- enterGroupMutation,
+ joinGroupMutation,
groupMemberQuery,
groupQuery,
} from '../../db/graphql/groups'
@@ -90,6 +90,118 @@ afterEach(async () => {
await cleanDatabase()
})
+describe('CreateGroup', () => {
+ beforeEach(() => {
+ variables = {
+ ...variables,
+ id: 'g589',
+ name: 'The Best Group',
+ slug: 'the-group',
+ about: 'We will change the world!',
+ description: 'Some description' + descriptionAdditional100,
+ groupType: 'public',
+ actionRadius: 'regional',
+ categoryIds,
+ }
+ })
+
+ describe('unauthenticated', () => {
+ it('throws authorization error', async () => {
+ const { errors } = await mutate({ mutation: createGroupMutation, variables })
+ expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
+ })
+ })
+
+ describe('authenticated', () => {
+ beforeEach(async () => {
+ authenticatedUser = await user.toJson()
+ })
+
+ it('creates a group', async () => {
+ const expected = {
+ data: {
+ CreateGroup: {
+ name: 'The Best Group',
+ slug: 'the-group',
+ about: 'We will change the world!',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject(
+ expected,
+ )
+ })
+
+ it('assigns the authenticated user as owner', async () => {
+ const expected = {
+ data: {
+ CreateGroup: {
+ name: 'The Best Group',
+ myRole: 'owner',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject(
+ expected,
+ )
+ })
+
+ it('has "disabled" and "deleted" default to "false"', async () => {
+ const expected = { data: { CreateGroup: { disabled: false, deleted: false } } }
+ await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject(
+ expected,
+ )
+ })
+
+ describe('description', () => {
+ describe('length without HTML', () => {
+ describe('less then 100 chars', () => {
+ it('throws error: "Too view categories!"', async () => {
+ const { errors } = await mutate({
+ mutation: createGroupMutation,
+ variables: {
+ ...variables,
+ description:
+ '0123456789' +
+ '0123456789',
+ },
+ })
+ expect(errors[0]).toHaveProperty('message', 'Description too short!')
+ })
+ })
+ })
+ })
+
+ describe('categories', () => {
+ beforeEach(() => {
+ CONFIG.CATEGORIES_ACTIVE = true
+ })
+
+ describe('not even one', () => {
+ it('throws error: "Too view categories!"', async () => {
+ const { errors } = await mutate({
+ mutation: createGroupMutation,
+ variables: { ...variables, categoryIds: null },
+ })
+ expect(errors[0]).toHaveProperty('message', 'Too view categories!')
+ })
+ })
+
+ describe('four', () => {
+ it('throws error: "Too many categories!"', async () => {
+ const { errors } = await mutate({
+ mutation: createGroupMutation,
+ variables: { ...variables, categoryIds: ['cat9', 'cat4', 'cat15', 'cat27'] },
+ })
+ expect(errors[0]).toHaveProperty('message', 'Too many categories!')
+ })
+ })
+ })
+ })
+})
+
describe('Group', () => {
describe('unauthenticated', () => {
it('throws authorization error', async () => {
@@ -208,6 +320,244 @@ describe('Group', () => {
})
})
+describe('JoinGroup', () => {
+ describe('unauthenticated', () => {
+ it('throws authorization error', async () => {
+ variables = {
+ id: 'not-existing-group',
+ userId: 'current-user',
+ }
+ const { errors } = await mutate({ mutation: joinGroupMutation, variables })
+ expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
+ })
+ })
+
+ describe('authenticated', () => {
+ let ownerOfClosedGroupUser
+ let ownerOfHiddenGroupUser
+
+ beforeEach(async () => {
+ ownerOfClosedGroupUser = await Factory.build(
+ 'user',
+ {
+ id: 'owner-of-closed-group',
+ name: 'Owner Of Closed Group',
+ },
+ {
+ email: 'owner-of-closed-group@example.org',
+ password: '1234',
+ },
+ )
+ ownerOfHiddenGroupUser = await Factory.build(
+ 'user',
+ {
+ id: 'owner-of-hidden-group',
+ name: 'Owner Of Hidden Group',
+ },
+ {
+ email: 'owner-of-hidden-group@example.org',
+ password: '1234',
+ },
+ )
+ authenticatedUser = await ownerOfClosedGroupUser.toJson()
+ await mutate({
+ mutation: createGroupMutation,
+ variables: {
+ id: 'closed-group',
+ name: 'Uninteresting Group',
+ about: 'We will change nothing!',
+ description: 'We love it like it is!?' + descriptionAdditional100,
+ groupType: 'closed',
+ actionRadius: 'national',
+ categoryIds,
+ },
+ })
+ authenticatedUser = await ownerOfHiddenGroupUser.toJson()
+ await mutate({
+ mutation: createGroupMutation,
+ variables: {
+ id: 'hidden-group',
+ name: 'Investigative Journalism Group',
+ about: 'We will change all.',
+ description: 'We research …' + descriptionAdditional100,
+ groupType: 'hidden',
+ actionRadius: 'global',
+ categoryIds,
+ },
+ })
+ authenticatedUser = await user.toJson()
+ await mutate({
+ mutation: createGroupMutation,
+ variables: {
+ id: 'public-group',
+ name: 'The Best Group',
+ about: 'We will change the world!',
+ description: 'Some description' + descriptionAdditional100,
+ groupType: 'public',
+ actionRadius: 'regional',
+ categoryIds,
+ },
+ })
+ })
+
+ describe('public group', () => {
+ describe('entered by "owner-of-closed-group"', () => {
+ it('has "usual" as membership role', async () => {
+ variables = {
+ id: 'public-group',
+ userId: 'owner-of-closed-group',
+ }
+ const expected = {
+ data: {
+ JoinGroup: {
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'usual',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(
+ mutate({
+ mutation: joinGroupMutation,
+ variables,
+ }),
+ ).resolves.toMatchObject(expected)
+ })
+ })
+
+ describe('entered by its owner', () => {
+ describe('does not create additional "MEMBER_OF" relation and therefore', () => {
+ it('has still "owner" as membership role', async () => {
+ variables = {
+ id: 'public-group',
+ userId: 'current-user',
+ }
+ const expected = {
+ data: {
+ JoinGroup: {
+ id: 'current-user',
+ myRoleInGroup: 'owner',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(
+ mutate({
+ mutation: joinGroupMutation,
+ variables,
+ }),
+ ).resolves.toMatchObject(expected)
+ })
+ })
+ })
+ })
+
+ describe('closed group', () => {
+ describe('entered by "current-user"', () => {
+ it('has "pending" as membership role', async () => {
+ variables = {
+ id: 'closed-group',
+ userId: 'current-user',
+ }
+ const expected = {
+ data: {
+ JoinGroup: {
+ id: 'current-user',
+ myRoleInGroup: 'pending',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(
+ mutate({
+ mutation: joinGroupMutation,
+ variables,
+ }),
+ ).resolves.toMatchObject(expected)
+ })
+ })
+
+ describe('entered by its owner', () => {
+ describe('does not create additional "MEMBER_OF" relation and therefore', () => {
+ it('has still "owner" as membership role', async () => {
+ variables = {
+ id: 'closed-group',
+ userId: 'owner-of-closed-group',
+ }
+ const expected = {
+ data: {
+ JoinGroup: {
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'owner',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(
+ mutate({
+ mutation: joinGroupMutation,
+ variables,
+ }),
+ ).resolves.toMatchObject(expected)
+ })
+ })
+ })
+ })
+
+ describe('hidden group', () => {
+ describe('entered by "owner-of-closed-group"', () => {
+ it('has "pending" as membership role', async () => {
+ variables = {
+ id: 'hidden-group',
+ userId: 'owner-of-closed-group',
+ }
+ const expected = {
+ data: {
+ JoinGroup: {
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'pending',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(
+ mutate({
+ mutation: joinGroupMutation,
+ variables,
+ }),
+ ).resolves.toMatchObject(expected)
+ })
+ })
+
+ describe('entered by its owner', () => {
+ describe('does not create additional "MEMBER_OF" relation and therefore', () => {
+ it('has still "owner" as membership role', async () => {
+ variables = {
+ id: 'hidden-group',
+ userId: 'owner-of-hidden-group',
+ }
+ const expected = {
+ data: {
+ JoinGroup: {
+ id: 'owner-of-hidden-group',
+ myRoleInGroup: 'owner',
+ },
+ },
+ errors: undefined,
+ }
+ await expect(
+ mutate({
+ mutation: joinGroupMutation,
+ variables,
+ }),
+ ).resolves.toMatchObject(expected)
+ })
+ })
+ })
+ })
+ })
+})
+
describe('GroupMember', () => {
describe('unauthenticated', () => {
it('throws authorization error', async () => {
@@ -301,28 +651,28 @@ describe('GroupMember', () => {
})
// create additional memberships
await mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'public-group',
userId: 'owner-of-closed-group',
},
})
await mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'public-group',
userId: 'owner-of-hidden-group',
},
})
await mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'closed-group',
userId: 'current-user',
},
})
await mutate({
- mutation: enterGroupMutation,
+ mutation: joinGroupMutation,
variables: {
id: 'hidden-group',
userId: 'owner-of-closed-group',
@@ -338,7 +688,11 @@ describe('GroupMember', () => {
})
describe('query group members', () => {
- describe('by owner', () => {
+ describe('by owner "current-user"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await user.toJson()
+ })
+
it('finds all members', async () => {
const expected = {
data: {
@@ -368,493 +722,265 @@ describe('GroupMember', () => {
})
})
- describe('by "other-user"', () => {
- it.only('throws authorization error', async () => {
- authenticatedUser = await otherUser.toJson()
- const result = await query({ query: groupMemberQuery, variables })
- console.log('result: ', result)
- // Wolle: const { errors } = await query({ query: groupMemberQuery, variables })
- // expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
+ describe('by usual member "owner-of-closed-group"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await ownerOfClosedGroupUser.toJson()
})
- })
- })
- describe('entered by its owner', () => {
- describe('does not create additional "MEMBER_OF" relation and therefore', () => {
- it('has still "owner" as membership role', async () => {
- variables = {
- id: 'public-group',
- userId: 'current-user',
- }
+ it('finds all members', async () => {
const expected = {
data: {
- EnterGroup: {
- id: 'current-user',
- myRoleInGroup: 'owner',
- },
+ GroupMember: expect.arrayContaining([
+ expect.objectContaining({
+ id: 'current-user',
+ myRoleInGroup: 'owner',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'usual',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-hidden-group',
+ myRoleInGroup: 'usual',
+ }),
+ ]),
},
errors: undefined,
}
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
- })
- })
- })
- })
-
- describe('closed group', () => {
- describe('entered by "current-user"', () => {
- it('has "pending" as membership role', async () => {
- variables = {
- id: 'closed-group',
- userId: 'current-user',
- }
- const expected = {
- data: {
- EnterGroup: {
- id: 'current-user',
- myRoleInGroup: 'pending',
- },
- },
- errors: undefined,
- }
- await expect(
- mutate({
- mutation: enterGroupMutation,
+ const result = await mutate({
+ mutation: groupMemberQuery,
variables,
- }),
- ).resolves.toMatchObject(expected)
- })
- })
-
- describe('entered by its owner', () => {
- describe('does not create additional "MEMBER_OF" relation and therefore', () => {
- it('has still "owner" as membership role', async () => {
- variables = {
- id: 'closed-group',
- userId: 'owner-of-closed-group',
- }
- const expected = {
- data: {
- EnterGroup: {
- id: 'owner-of-closed-group',
- myRoleInGroup: 'owner',
- },
- },
- errors: undefined,
- }
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
- })
- })
- })
- })
-
- describe('hidden group', () => {
- describe('entered by "owner-of-closed-group"', () => {
- it('has "pending" as membership role', async () => {
- variables = {
- id: 'hidden-group',
- userId: 'owner-of-closed-group',
- }
- const expected = {
- data: {
- EnterGroup: {
- id: 'owner-of-closed-group',
- myRoleInGroup: 'pending',
- },
- },
- errors: undefined,
- }
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
- })
- })
-
- describe('entered by its owner', () => {
- describe('does not create additional "MEMBER_OF" relation and therefore', () => {
- it('has still "owner" as membership role', async () => {
- variables = {
- id: 'hidden-group',
- userId: 'owner-of-hidden-group',
- }
- const expected = {
- data: {
- EnterGroup: {
- id: 'owner-of-hidden-group',
- myRoleInGroup: 'owner',
- },
- },
- errors: undefined,
- }
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
- })
- })
- })
- })
- })
-})
-
-describe('CreateGroup', () => {
- beforeEach(() => {
- variables = {
- ...variables,
- id: 'g589',
- name: 'The Best Group',
- slug: 'the-group',
- about: 'We will change the world!',
- description: 'Some description' + descriptionAdditional100,
- groupType: 'public',
- actionRadius: 'regional',
- categoryIds,
- }
- })
-
- describe('unauthenticated', () => {
- it('throws authorization error', async () => {
- const { errors } = await mutate({ mutation: createGroupMutation, variables })
- expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
- })
- })
-
- describe('authenticated', () => {
- beforeEach(async () => {
- authenticatedUser = await user.toJson()
- })
-
- it('creates a group', async () => {
- const expected = {
- data: {
- CreateGroup: {
- name: 'The Best Group',
- slug: 'the-group',
- about: 'We will change the world!',
- },
- },
- errors: undefined,
- }
- await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject(
- expected,
- )
- })
-
- it('assigns the authenticated user as owner', async () => {
- const expected = {
- data: {
- CreateGroup: {
- name: 'The Best Group',
- myRole: 'owner',
- },
- },
- errors: undefined,
- }
- await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject(
- expected,
- )
- })
-
- it('has "disabled" and "deleted" default to "false"', async () => {
- const expected = { data: { CreateGroup: { disabled: false, deleted: false } } }
- await expect(mutate({ mutation: createGroupMutation, variables })).resolves.toMatchObject(
- expected,
- )
- })
-
- describe('description', () => {
- describe('length without HTML', () => {
- describe('less then 100 chars', () => {
- it('throws error: "Too view categories!"', async () => {
- const { errors } = await mutate({
- mutation: createGroupMutation,
- variables: {
- ...variables,
- description:
- '0123456789' +
- '0123456789',
- },
})
- expect(errors[0]).toHaveProperty('message', 'Description too short!')
+ expect(result).toMatchObject(expected)
+ expect(result.data.GroupMember.length).toBe(3)
})
})
- })
- })
- describe('categories', () => {
- beforeEach(() => {
- CONFIG.CATEGORIES_ACTIVE = true
- })
-
- describe('not even one', () => {
- it('throws error: "Too view categories!"', async () => {
- const { errors } = await mutate({
- mutation: createGroupMutation,
- variables: { ...variables, categoryIds: null },
+ describe('by none member "other-user"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await otherUser.toJson()
})
- expect(errors[0]).toHaveProperty('message', 'Too view categories!')
- })
- })
- describe('four', () => {
- it('throws error: "Too many categories!"', async () => {
- const { errors } = await mutate({
- mutation: createGroupMutation,
- variables: { ...variables, categoryIds: ['cat9', 'cat4', 'cat15', 'cat27'] },
- })
- expect(errors[0]).toHaveProperty('message', 'Too many categories!')
- })
- })
- })
- })
-})
-
-describe('EnterGroup', () => {
- describe('unauthenticated', () => {
- it('throws authorization error', async () => {
- variables = {
- id: 'not-existing-group',
- userId: 'current-user',
- }
- const { errors } = await mutate({ mutation: enterGroupMutation, variables })
- expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
- })
- })
-
- describe('authenticated', () => {
- let ownerOfClosedGroupUser
- let ownerOfHiddenGroupUser
-
- beforeEach(async () => {
- ownerOfClosedGroupUser = await Factory.build(
- 'user',
- {
- id: 'owner-of-closed-group',
- name: 'Owner Of Closed Group',
- },
- {
- email: 'owner-of-closed-group@example.org',
- password: '1234',
- },
- )
- ownerOfHiddenGroupUser = await Factory.build(
- 'user',
- {
- id: 'owner-of-hidden-group',
- name: 'Owner Of Hidden Group',
- },
- {
- email: 'owner-of-hidden-group@example.org',
- password: '1234',
- },
- )
- authenticatedUser = await ownerOfClosedGroupUser.toJson()
- await mutate({
- mutation: createGroupMutation,
- variables: {
- id: 'closed-group',
- name: 'Uninteresting Group',
- about: 'We will change nothing!',
- description: 'We love it like it is!?' + descriptionAdditional100,
- groupType: 'closed',
- actionRadius: 'national',
- categoryIds,
- },
- })
- authenticatedUser = await ownerOfHiddenGroupUser.toJson()
- await mutate({
- mutation: createGroupMutation,
- variables: {
- id: 'hidden-group',
- name: 'Investigative Journalism Group',
- about: 'We will change all.',
- description: 'We research …' + descriptionAdditional100,
- groupType: 'hidden',
- actionRadius: 'global',
- categoryIds,
- },
- })
- authenticatedUser = await user.toJson()
- await mutate({
- mutation: createGroupMutation,
- variables: {
- id: 'public-group',
- name: 'The Best Group',
- about: 'We will change the world!',
- description: 'Some description' + descriptionAdditional100,
- groupType: 'public',
- actionRadius: 'regional',
- categoryIds,
- },
- })
- })
-
- describe('public group', () => {
- describe('entered by "owner-of-closed-group"', () => {
- it('has "usual" as membership role', async () => {
- variables = {
- id: 'public-group',
- userId: 'owner-of-closed-group',
- }
- const expected = {
- data: {
- EnterGroup: {
- id: 'owner-of-closed-group',
- myRoleInGroup: 'usual',
- },
- },
- errors: undefined,
- }
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
- })
- })
-
- describe('entered by its owner', () => {
- describe('does not create additional "MEMBER_OF" relation and therefore', () => {
- it('has still "owner" as membership role', async () => {
- variables = {
- id: 'public-group',
- userId: 'current-user',
- }
+ it('finds all members', async () => {
const expected = {
data: {
- EnterGroup: {
- id: 'current-user',
- myRoleInGroup: 'owner',
- },
+ GroupMember: expect.arrayContaining([
+ expect.objectContaining({
+ id: 'current-user',
+ myRoleInGroup: 'owner',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'usual',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-hidden-group',
+ myRoleInGroup: 'usual',
+ }),
+ ]),
},
errors: undefined,
}
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
+ const result = await mutate({
+ mutation: groupMemberQuery,
+ variables,
+ })
+ expect(result).toMatchObject(expected)
+ expect(result.data.GroupMember.length).toBe(3)
})
})
})
})
describe('closed group', () => {
- describe('entered by "current-user"', () => {
- it('has "pending" as membership role', async () => {
- variables = {
- id: 'closed-group',
- userId: 'current-user',
- }
- const expected = {
- data: {
- EnterGroup: {
- id: 'current-user',
- myRoleInGroup: 'pending',
- },
- },
- errors: undefined,
- }
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
- })
+ beforeEach(async () => {
+ variables = {
+ id: 'closed-group',
+ }
})
- describe('entered by its owner', () => {
- describe('does not create additional "MEMBER_OF" relation and therefore', () => {
- it('has still "owner" as membership role', async () => {
- variables = {
- id: 'closed-group',
- userId: 'owner-of-closed-group',
- }
+ describe('query group members', () => {
+ describe('by owner "owner-of-closed-group"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await ownerOfClosedGroupUser.toJson()
+ })
+
+ it('finds all members', async () => {
const expected = {
data: {
- EnterGroup: {
- id: 'owner-of-closed-group',
- myRoleInGroup: 'owner',
- },
+ GroupMember: expect.arrayContaining([
+ expect.objectContaining({
+ id: 'current-user',
+ myRoleInGroup: 'pending',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'owner',
+ }),
+ ]),
},
errors: undefined,
}
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
+ const result = await mutate({
+ mutation: groupMemberQuery,
+ variables,
+ })
+ expect(result).toMatchObject(expected)
+ expect(result.data.GroupMember.length).toBe(2)
+ })
+ })
+
+ // needs 'SwitchGroupMemberRole'
+ describe.skip('by usual member "owner-of-hidden-group"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await ownerOfHiddenGroupUser.toJson()
+ })
+
+ it('finds all members', async () => {
+ const expected = {
+ data: {
+ GroupMember: expect.arrayContaining([
+ expect.objectContaining({
+ id: 'current-user',
+ myRoleInGroup: 'pending',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'owner',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-hidden-group',
+ myRoleInGroup: 'usual',
+ }),
+ ]),
+ },
+ errors: undefined,
+ }
+ const result = await mutate({
+ mutation: groupMemberQuery,
+ variables,
+ })
+ expect(result).toMatchObject(expected)
+ expect(result.data.GroupMember.length).toBe(3)
+ })
+ })
+
+ describe('by pending member "current-user"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await user.toJson()
+ })
+
+ it('throws authorization error', async () => {
+ const { errors } = await query({ query: groupMemberQuery, variables })
+ expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
+ })
+ })
+
+ describe('by none member "other-user"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await otherUser.toJson()
+ })
+
+ it('throws authorization error', async () => {
+ const { errors } = await query({ query: groupMemberQuery, variables })
+ expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
})
})
})
})
describe('hidden group', () => {
- describe('entered by "owner-of-closed-group"', () => {
- it('has "pending" as membership role', async () => {
- variables = {
- id: 'hidden-group',
- userId: 'owner-of-closed-group',
- }
- const expected = {
- data: {
- EnterGroup: {
- id: 'owner-of-closed-group',
- myRoleInGroup: 'pending',
- },
- },
- errors: undefined,
- }
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
- })
+ beforeEach(async () => {
+ variables = {
+ id: 'hidden-group',
+ }
})
- describe('entered by its owner', () => {
- describe('does not create additional "MEMBER_OF" relation and therefore', () => {
- it('has still "owner" as membership role', async () => {
- variables = {
- id: 'hidden-group',
- userId: 'owner-of-hidden-group',
- }
+ describe('query group members', () => {
+ describe('by owner "owner-of-hidden-group"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await ownerOfHiddenGroupUser.toJson()
+ })
+
+ it('finds all members', async () => {
const expected = {
data: {
- EnterGroup: {
- id: 'owner-of-hidden-group',
- myRoleInGroup: 'owner',
- },
+ GroupMember: expect.arrayContaining([
+ expect.objectContaining({
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'pending',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-hidden-group',
+ myRoleInGroup: 'owner',
+ }),
+ ]),
},
errors: undefined,
}
- await expect(
- mutate({
- mutation: enterGroupMutation,
- variables,
- }),
- ).resolves.toMatchObject(expected)
+ const result = await mutate({
+ mutation: groupMemberQuery,
+ variables,
+ })
+ expect(result).toMatchObject(expected)
+ expect(result.data.GroupMember.length).toBe(2)
+ })
+ })
+
+ // needs 'SwitchGroupMemberRole'
+ describe.skip('by usual member "owner-of-closed-group"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await ownerOfClosedGroupUser.toJson()
+ })
+
+ it('finds all members', async () => {
+ const expected = {
+ data: {
+ GroupMember: expect.arrayContaining([
+ expect.objectContaining({
+ id: 'current-user',
+ myRoleInGroup: 'pending',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-closed-group',
+ myRoleInGroup: 'usual',
+ }),
+ expect.objectContaining({
+ id: 'owner-of-hidden-group',
+ myRoleInGroup: 'owner',
+ }),
+ ]),
+ },
+ errors: undefined,
+ }
+ const result = await mutate({
+ mutation: groupMemberQuery,
+ variables,
+ })
+ expect(result).toMatchObject(expected)
+ expect(result.data.GroupMember.length).toBe(3)
+ })
+ })
+
+ describe('by pending member "current-user"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await user.toJson()
+ })
+
+ it('throws authorization error', async () => {
+ const { errors } = await query({ query: groupMemberQuery, variables })
+ expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
+ })
+ })
+
+ describe('by none member "other-user"', () => {
+ beforeEach(async () => {
+ authenticatedUser = await otherUser.toJson()
+ })
+
+ it('throws authorization error', async () => {
+ const { errors } = await query({ query: groupMemberQuery, variables })
+ expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
})
})
})
diff --git a/backend/src/schema/types/type/Group.gql b/backend/src/schema/types/type/Group.gql
index cf44894db..fad1b7e58 100644
--- a/backend/src/schema/types/type/Group.gql
+++ b/backend/src/schema/types/type/Group.gql
@@ -114,7 +114,7 @@ type Mutation {
DeleteGroup(id: ID!): Group
- EnterGroup(
+ JoinGroup(
id: ID!
userId: ID!
): User