feat: Restrict Comments on Posts in Groups

This commit is contained in:
Moriz Wahl 2022-10-27 14:06:42 +02:00
parent d4b921a25c
commit 5f4bf58dc6
2 changed files with 200 additions and 1 deletions

View File

@ -249,6 +249,40 @@ const isMemberOfGroup = rule({
}
})
const canCommentPost = rule({
cache: 'no_cache',
})(async (_parent, args, { user, driver }) => {
if (!(user && user.id)) return false
const { postId } = args
const userId = user.id
const session = driver.session()
const readTxPromise = session.readTransaction(async (transaction) => {
const transactionResponse = await transaction.run(
`
MATCH (post:Post { id: $postId })
OPTIONAL MATCH (post)-[:IN]->(group:Group)
OPTIONAL MATCH (user:User { id: $userId })-[membership:MEMBER_OF]->(group)
RETURN group AS group, membership AS membership
`,
{ postId, userId },
)
return {
group: transactionResponse.records.map((record) => record.get('group'))[0],
membership: transactionResponse.records.map((record) => record.get('membership'))[0],
}
})
try {
const { group, membership } = await readTxPromise
return (
!group || (membership && ['usual', 'admin', 'owner'].includes(membership.properties.role))
)
} catch (error) {
throw new Error(error)
} finally {
session.close()
}
})
const isAuthor = rule({
cache: 'no_cache',
})(async (_parent, args, { user, driver }) => {
@ -361,7 +395,7 @@ export default shield(
unshout: isAuthenticated,
changePassword: isAuthenticated,
review: isModerator,
CreateComment: isAuthenticated,
CreateComment: and(isAuthenticated, canCommentPost),
UpdateComment: isAuthor,
DeleteComment: isAuthor,
DeleteUser: or(isDeletingOwnAccount, isAdmin),

View File

@ -14,6 +14,7 @@ import {
profilePagePosts,
searchPosts,
} from '../../db/graphql/posts'
import { createCommentMutation } from '../../db/graphql/comments'
// eslint-disable-next-line no-unused-vars
import { DESCRIPTION_WITHOUT_HTML_LENGTH_MIN } from '../../constants/groups'
import CONFIG from '../../config'
@ -378,6 +379,170 @@ describe('Posts in Groups', () => {
})
})
describe('commenting posts in groups', () => {
describe('without membership of group', () => {
beforeAll(async () => {
authenticatedUser = await anyUser.toJson()
})
it('throws an error for public groups', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-public-group',
content:
'I am commenting a post in a public group without being a member of the group',
},
}),
).resolves.toMatchObject({
errors: expect.arrayContaining([expect.objectContaining({ message: 'Not Authorized!' })]),
})
})
it('throws an error for closed groups', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-closed-group',
content:
'I am commenting a post in a closed group without being a member of the group',
},
}),
).resolves.toMatchObject({
errors: expect.arrayContaining([expect.objectContaining({ message: 'Not Authorized!' })]),
})
})
it('throws an error for hidden groups', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-hidden-group',
content:
'I am commenting a post in a hidden group without being a member of the group',
},
}),
).resolves.toMatchObject({
errors: expect.arrayContaining([expect.objectContaining({ message: 'Not Authorized!' })]),
})
})
})
describe('as a pending member of group', () => {
beforeAll(async () => {
authenticatedUser = await pendingUser.toJson()
})
it('throws an error for public groups', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-public-group',
content: 'I am commenting a post in a public group as a pending member of the group',
},
}),
).resolves.toMatchObject({
errors: expect.arrayContaining([expect.objectContaining({ message: 'Not Authorized!' })]),
})
})
it('throws an error for closed groups', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-closed-group',
content: 'I am commenting a post in a closed group as a pending member of the group',
},
}),
).resolves.toMatchObject({
errors: expect.arrayContaining([expect.objectContaining({ message: 'Not Authorized!' })]),
})
})
it('throws an error for hidden groups', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-hidden-group',
content: 'I am commenting a post in a hidden group as a pending member of the group',
},
}),
).resolves.toMatchObject({
errors: expect.arrayContaining([expect.objectContaining({ message: 'Not Authorized!' })]),
})
})
})
describe('as a member of group', () => {
beforeAll(async () => {
authenticatedUser = await allGroupsUser.toJson()
})
it('comments a post in a public group', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-public-group',
content: 'I am commenting a post in a public group as a member of the group',
},
}),
).resolves.toMatchObject({
data: {
CreateComment: {
id: expect.any(String),
},
},
errors: undefined,
})
})
it('comments a post in a closed group', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-closed-group',
content: 'I am commenting a post in a closed group as a member of the group',
},
}),
).resolves.toMatchObject({
data: {
CreateComment: {
id: expect.any(String),
},
},
errors: undefined,
})
})
it('comments a post in a hidden group', async () => {
await expect(
mutate({
mutation: createCommentMutation,
variables: {
postId: 'post-to-hidden-group',
content: 'I am commenting a post in a hidden group as a member of the group',
},
}),
).resolves.toMatchObject({
data: {
CreateComment: {
id: expect.any(String),
},
},
errors: undefined,
})
})
})
})
describe('visibility of posts', () => {
describe('query post by ID', () => {
describe('without authentication', () => {