717 lines
23 KiB
JavaScript

import { createTestClient } from 'apollo-server-testing'
import Factory, { cleanDatabase } from '../../db/factories'
import { gql } from '../../helpers/jest'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer from '../../server'
const neode = getNeode()
const driver = getDriver()
let mutate,
authenticatedUser,
disableVariables,
enableVariables,
moderator,
nonModerator,
closeReportVariables
const reviewMutation = gql`
mutation ($resourceId: ID!, $disable: Boolean, $closed: Boolean) {
review(resourceId: $resourceId, disable: $disable, closed: $closed) {
createdAt
updatedAt
resource {
__typename
... on User {
id
disabled
}
... on Post {
id
disabled
}
... on Comment {
id
disabled
}
}
report {
id
createdAt
updatedAt
closed
reviewed {
createdAt
moderator {
id
}
}
}
}
}
`
describe('moderate resources', () => {
beforeAll(async () => {
await cleanDatabase()
authenticatedUser = undefined
const { server } = createServer({
context: () => {
return {
driver,
neode,
user: authenticatedUser,
}
},
})
mutate = createTestClient(server).mutate
})
afterAll(async () => {
await cleanDatabase()
driver.close()
})
beforeEach(async () => {
disableVariables = {
resourceId: 'undefined-resource',
disable: true,
closed: false,
}
enableVariables = {
resourceId: 'undefined-resource',
disable: false,
closed: false,
}
authenticatedUser = null
moderator = await Factory.build(
'user',
{
id: 'moderator-id',
name: 'Moderator',
role: 'moderator',
},
{
email: 'moderator@example.org',
password: '1234',
},
)
nonModerator = await Factory.build(
'user',
{
id: 'non-moderator',
name: 'Non Moderator',
},
{
email: 'non.moderator@example.org',
password: '1234',
},
)
})
// TODO: avoid database clean after each test in the future if possible for performance and flakyness reasons by filling the database step by step, see issue https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/4543
afterEach(async () => {
await cleanDatabase()
})
describe('review to close report, leaving resource enabled', () => {
describe('unauthenticated', () => {
it('throws authorization error', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
errors: [{ message: 'Not Authorized!' }],
})
})
})
describe('authenticated', () => {
beforeEach(async () => {
authenticatedUser = await nonModerator.toJson()
})
it('non-moderator receives an authorization error', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
errors: [{ message: 'Not Authorized!' }],
})
})
})
describe('moderator', () => {
beforeEach(async () => {
authenticatedUser = await moderator.toJson()
const questionablePost = await Factory.build('post', {
id: 'should-i-be-disabled',
})
const reportAgainstQuestionablePost = await Factory.build('report')
await Promise.all([
reportAgainstQuestionablePost.relateTo(nonModerator, 'filed', {
resourceId: 'should-i-be-disabled',
reasonCategory: 'doxing',
reasonDescription: "This shouldn't be shown to anybody else! It's my private thing!",
}),
reportAgainstQuestionablePost.relateTo(questionablePost, 'belongsTo'),
])
closeReportVariables = {
resourceId: 'should-i-be-disabled',
disable: false,
closed: true,
}
})
it('report can be closed without disabling resource', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: closeReportVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Post', id: 'should-i-be-disabled', disabled: false },
report: { id: expect.any(String), closed: true },
},
},
errors: undefined,
})
})
it('creates only one review for multiple reviews by the same moderator on same resource', async () => {
await Promise.all([
mutate({
mutation: reviewMutation,
variables: { ...disableVariables, resourceId: 'should-i-be-disabled' },
}),
mutate({
mutation: reviewMutation,
variables: { ...enableVariables, resourceId: 'should-i-be-disabled' },
}),
])
const cypher =
'MATCH (:Report)<-[review:REVIEWED]-(moderator:User {id: "moderator-id"}) RETURN review'
const reviews = await neode.cypher(cypher)
expect(reviews.records).toHaveLength(1)
})
it('updates the updatedAt attribute', async () => {
const [firstReview, secondReview] = await Promise.all([
mutate({
mutation: reviewMutation,
variables: { ...disableVariables, resourceId: 'should-i-be-disabled' },
}),
mutate({
mutation: reviewMutation,
variables: { ...enableVariables, resourceId: 'should-i-be-disabled' },
}),
])
expect(firstReview.data.review.updatedAt).toBeTruthy()
expect(Date.parse(firstReview.data.review.updatedAt)).toEqual(expect.any(Number))
expect(secondReview.data.review.updatedAt).toBeTruthy()
expect(Date.parse(secondReview.data.review.updatedAt)).toEqual(expect.any(Number))
expect(firstReview.data.review.updatedAt).not.toEqual(secondReview.data.review.updatedAt)
})
})
})
describe('review to disable', () => {
describe('unauthenticated', () => {
it('throws authorization error', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
errors: [{ message: 'Not Authorized!' }],
})
})
})
describe('authenticated', () => {
beforeEach(async () => {
authenticatedUser = await nonModerator.toJson()
})
it('non-moderator receives an authorization error', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
errors: [{ message: 'Not Authorized!' }],
})
})
})
describe('moderator', () => {
beforeEach(async () => {
authenticatedUser = await moderator.toJson()
})
describe('moderate a comment', () => {
beforeEach(async () => {
const trollingComment = await Factory.build('comment', {
id: 'comment-id',
})
const reportAgainstTrollingComment = await Factory.build('report')
await Promise.all([
reportAgainstTrollingComment.relateTo(nonModerator, 'filed', {
resourceId: 'comment-id',
reasonCategory: 'other',
reasonDescription: 'This comment is bigoted',
}),
reportAgainstTrollingComment.relateTo(trollingComment, 'belongsTo'),
])
disableVariables = {
...disableVariables,
resourceId: 'comment-id',
}
})
it('returns disabled resource id', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: { review: { resource: { __typename: 'Comment', id: 'comment-id' } } },
errors: undefined,
})
})
it('returns .reviewed', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Comment', id: 'comment-id' },
report: {
id: expect.any(String),
reviewed: expect.arrayContaining([
{ createdAt: expect.any(String), moderator: { id: 'moderator-id' } },
]),
},
},
},
errors: undefined,
})
})
it('updates .disabled on comment', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: {
review: { resource: { __typename: 'Comment', id: 'comment-id', disabled: true } },
},
errors: undefined,
})
})
it('can be closed with one review', async () => {
closeReportVariables = {
...disableVariables,
closed: true,
}
await expect(
mutate({ mutation: reviewMutation, variables: closeReportVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Comment', id: 'comment-id' },
report: { id: expect.any(String), closed: true },
},
},
errors: undefined,
})
})
})
describe('moderate a post', () => {
beforeEach(async () => {
const trollingPost = await Factory.build('post', {
id: 'post-id',
})
const reportAgainstTrollingPost = await Factory.build('report')
await Promise.all([
reportAgainstTrollingPost.relateTo(nonModerator, 'filed', {
resourceId: 'post-id',
reasonCategory: 'doxing',
reasonDescription: "This shouldn't be shown to anybody else! It's my private thing!",
}),
reportAgainstTrollingPost.relateTo(trollingPost, 'belongsTo'),
])
disableVariables = {
...disableVariables,
resourceId: 'post-id',
}
})
it('returns disabled resource id', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Post', id: 'post-id' },
},
},
errors: undefined,
})
})
it('returns .reviewed', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Post', id: 'post-id' },
report: {
id: expect.any(String),
reviewed: expect.arrayContaining([
{ createdAt: expect.any(String), moderator: { id: 'moderator-id' } },
]),
},
},
},
errors: undefined,
})
})
it('updates .disabled on post', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: { review: { resource: { __typename: 'Post', id: 'post-id', disabled: true } } },
errors: undefined,
})
})
it('can be closed with one review', async () => {
closeReportVariables = {
...disableVariables,
closed: true,
}
await expect(
mutate({ mutation: reviewMutation, variables: closeReportVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Post', id: 'post-id' },
report: { id: expect.any(String), closed: true },
},
},
errors: undefined,
})
})
})
describe('moderate a user', () => {
beforeEach(async () => {
const troll = await Factory.build('user', {
id: 'user-id',
})
const reportAgainstTroll = await Factory.build('report')
await Promise.all([
reportAgainstTroll.relateTo(nonModerator, 'filed', {
resourceId: 'user-id',
reasonCategory: 'discrimination_etc',
reasonDescription: 'This user is harassing me with bigoted remarks!',
}),
reportAgainstTroll.relateTo(troll, 'belongsTo'),
])
disableVariables = {
...disableVariables,
resourceId: 'user-id',
}
})
it('returns disabled resource id', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: { review: { resource: { __typename: 'User', id: 'user-id' } } },
errors: undefined,
})
})
it('returns .reviewed', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'User', id: 'user-id' },
report: {
id: expect.any(String),
reviewed: expect.arrayContaining([
{ createdAt: expect.any(String), moderator: { id: 'moderator-id' } },
]),
},
},
},
errors: undefined,
})
})
it('updates .disabled on user', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: disableVariables }),
).resolves.toMatchObject({
data: { review: { resource: { __typename: 'User', id: 'user-id', disabled: true } } },
errors: undefined,
})
})
it('can be closed with one review', async () => {
closeReportVariables = {
...disableVariables,
closed: true,
}
await expect(
mutate({ mutation: reviewMutation, variables: closeReportVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'User', id: 'user-id' },
report: { id: expect.any(String), closed: true },
},
},
errors: undefined,
})
})
})
})
})
describe('review to re-enable after disabled', () => {
describe('unautenticated user', () => {
it('throws authorization error', async () => {
enableVariables = {
...enableVariables,
resourceId: 'post-id',
}
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
errors: [{ message: 'Not Authorized!' }],
})
})
})
describe('authenticated user', () => {
describe('non moderator', () => {
beforeEach(async () => {
authenticatedUser = await nonModerator.toJson()
})
it('throws authorization error', async () => {
enableVariables = {
...enableVariables,
resourceId: 'post-id',
}
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
errors: [{ message: 'Not Authorized!' }],
})
})
})
describe('moderator', () => {
beforeEach(async () => {
authenticatedUser = await moderator.toJson()
})
describe('moderate a comment', () => {
beforeEach(async () => {
const trollingComment = await Factory.build('comment', {
id: 'comment-id',
})
const reportAgainstTrollingComment = await Factory.build('report')
await Promise.all([
reportAgainstTrollingComment.relateTo(nonModerator, 'filed', {
resourceId: 'comment-id',
reasonCategory: 'other',
reasonDescription: 'This comment is bigoted',
}),
reportAgainstTrollingComment.relateTo(trollingComment, 'belongsTo'),
])
await Promise.all([
reportAgainstTrollingComment.relateTo(moderator, 'reviewed', {
...disableVariables,
resourceId: 'comment-id',
}),
trollingComment.update({ disabled: true, updatedAt: new Date().toISOString() }),
])
enableVariables = {
...enableVariables,
resourceId: 'comment-id',
}
})
it('returns enabled resource id', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: { review: { resource: { __typename: 'Comment', id: 'comment-id' } } },
})
})
it('returns .reviewed', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Comment', id: 'comment-id' },
report: {
id: expect.any(String),
reviewed: expect.arrayContaining([
{ createdAt: expect.any(String), moderator: { id: 'moderator-id' } },
]),
},
},
},
})
})
it('updates .disabled on comment', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: {
review: { resource: { __typename: 'Comment', id: 'comment-id', disabled: false } },
},
})
})
})
describe('moderate a post', () => {
beforeEach(async () => {
const trollingPost = await Factory.build('post', {
id: 'post-id',
})
const reportAgainstTrollingPost = await Factory.build('report')
await Promise.all([
reportAgainstTrollingPost.relateTo(nonModerator, 'filed', {
resourceId: 'post-id',
reasonCategory: 'doxing',
reasonDescription:
"This shouldn't be shown to anybody else! It's my private thing!",
}),
reportAgainstTrollingPost.relateTo(trollingPost, 'belongsTo'),
])
await Promise.all([
reportAgainstTrollingPost.relateTo(moderator, 'reviewed', {
...disableVariables,
resourceId: 'comment-id',
}),
trollingPost.update({ disabled: true, updatedAt: new Date().toISOString() }),
])
enableVariables = {
...enableVariables,
resourceId: 'post-id',
}
})
it('returns enabled resource id', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: { review: { resource: { __typename: 'Post', id: 'post-id' } } },
})
})
it('returns .reviewed', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'Post', id: 'post-id' },
report: {
id: expect.any(String),
reviewed: expect.arrayContaining([
{ createdAt: expect.any(String), moderator: { id: 'moderator-id' } },
]),
},
},
},
})
})
it('updates .disabled on post', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: {
review: { resource: { __typename: 'Post', id: 'post-id', disabled: false } },
},
})
})
})
describe('moderate a user', () => {
beforeEach(async () => {
const troll = await Factory.build('user', {
id: 'user-id',
})
const reportAgainstTroll = await Factory.build('report')
await Promise.all([
reportAgainstTroll.relateTo(nonModerator, 'filed', {
resourceId: 'user-id',
reasonCategory: 'discrimination_etc',
reasonDescription: 'This user is harassing me with bigoted remarks!',
}),
reportAgainstTroll.relateTo(troll, 'belongsTo'),
])
await Promise.all([
reportAgainstTroll.relateTo(moderator, 'reviewed', {
...disableVariables,
resourceId: 'comment-id',
}),
troll.update({ disabled: true, updatedAt: new Date().toISOString() }),
])
enableVariables = {
...enableVariables,
resourceId: 'user-id',
}
})
it('returns enabled resource id', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: { review: { resource: { __typename: 'User', id: 'user-id' } } },
})
})
it('returns .reviewed', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: {
review: {
resource: { __typename: 'User', id: 'user-id' },
report: {
id: expect.any(String),
reviewed: expect.arrayContaining([
{ createdAt: expect.any(String), moderator: { id: 'moderator-id' } },
]),
},
},
},
})
})
it('updates .disabled on user', async () => {
await expect(
mutate({ mutation: reviewMutation, variables: enableVariables }),
).resolves.toMatchObject({
data: {
review: { resource: { __typename: 'User', id: 'user-id', disabled: false } },
},
})
})
})
})
})
})
})