From d18d9228b0057fae22b4b846f9d41f5223cd6e69 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Wed, 27 Nov 2019 17:35:30 +0100 Subject: [PATCH] Refactor tests/resolvers - we were making multiple http requests to report resources in this test, now we are bypassing these requests by setting the database up to how we want to test, then testing what we want in isolation. - also added tests for closing a report - favor union for returning resource - simplify review mutation --- backend/src/schema/resolvers/moderation.js | 95 +-- .../src/schema/resolvers/moderation.spec.js | 723 ++++++++++-------- backend/src/schema/types/type/REVIEWED.gql | 16 +- 3 files changed, 452 insertions(+), 382 deletions(-) diff --git a/backend/src/schema/resolvers/moderation.js b/backend/src/schema/resolvers/moderation.js index 9d687dd42..730ff73c3 100644 --- a/backend/src/schema/resolvers/moderation.js +++ b/backend/src/schema/resolvers/moderation.js @@ -1,94 +1,45 @@ +const transformReturnType = record => { + return { + ...record.get('review').properties, + report: record.get('report').properties, + to: { + __typename: record.get('type'), + ...record.get('resource').properties, + }, + } +} + export default { Mutation: { review: async (_object, params, context, _resolveInfo) => { - const { resourceId } = params - let { disable, closed } = params - disable = disable === undefined ? null : disable - closed = closed === undefined ? null : closed const { user: moderator, driver } = context let createdRelationshipWithNestedAttributes = null // return value - const session = driver.session() try { const cypher = ` + MATCH (resource {id: $params.resourceId})<-[:BELONGS_TO]-(report:Report {closed: false}) MATCH (moderator:User {id: $moderatorId}) - MATCH (resource {id: $resourceId}) WHERE resource:User OR resource:Post OR resource:Comment - - // no open report, create one, update existing - MERGE (resource)<-[:BELONGS_TO]-(report:Report {closed: false}) - ON CREATE SET report.id = randomUUID(), report.createdAt = $dateTime, report.updatedAt = report.createdAt, report.rule = 'latestReviewUpdatedAtRules', report.disable = resource.disabled, report.closed = false - ON MATCH SET report.updatedAt = $dateTime - // report.disable and report.closed are set after setting them in review - - // Create review on report - WITH moderator, resource, report - MERGE (report)<-[review:REVIEWED]-(moderator) - ON CREATE SET review.createdAt = $dateTime, review.updatedAt = review.createdAt, - review.disable = CASE WHEN $disable IS NULL - THEN report.disable - ELSE $disable END, - review.closed = CASE WHEN $closed IS NULL - THEN report.closed - ELSE $closed END - ON MATCH SET - review.updatedAt = $dateTime, - review.disable = CASE WHEN $disable IS NULL - THEN review.disable - ELSE $disable END, - review.closed = CASE WHEN $closed IS NULL - THEN review.closed - ELSE $closed END - - SET report.disable = review.disable, report.closed = review.closed + MERGE (report)<-[review:REVIEWED { disable: $params.disable, closed: $params.closed }]-(moderator) + ON CREATE SET review.createdAt = $dateTime, review.updatedAt = review.createdAt + ON MATCH SET review.updatedAt = $dateTime + SET report.updatedAt = $dateTime, report.closed = review.closed SET resource.disabled = review.disable - RETURN moderator, review, report, resource, labels(resource)[0] AS type + RETURN review, report, resource, labels(resource)[0] AS type ` - const mutateDecisionWriteTxResultPromise = session.writeTransaction(async txc => { - const mutateDecisionTransactionResponse = await txc.run(cypher, { - resourceId, + const reviewWriteTxResultPromise = session.writeTransaction(async txc => { + const reviewTransactionResponse = await txc.run(cypher, { + params, moderatorId: moderator.id, dateTime: new Date().toISOString(), - disable, - closed, }) - return mutateDecisionTransactionResponse.records.map(record => ({ - moderator: record.get('moderator'), - review: record.get('review'), - report: record.get('report'), - resource: record.get('resource'), - type: record.get('type'), - })) + return reviewTransactionResponse.records.map(transformReturnType) }) - const txResult = await mutateDecisionWriteTxResultPromise + const txResult = await reviewWriteTxResultPromise if (!txResult[0]) return null - const { moderator: moderatorInResult, review, report, resource, type } = txResult[0] - createdRelationshipWithNestedAttributes = { - ...review.properties, - reportId: report.properties.id, - reportCreatedAt: report.properties.createdAt, - reportUpdatedAt: report.properties.updatedAt, - reportDisable: report.properties.disable, - reportClosed: report.properties.closed, - moderator: moderatorInResult.properties, - type, - post: null, - comment: null, - user: null, - } - switch (type) { - case 'Post': - createdRelationshipWithNestedAttributes.post = resource.properties - break - case 'Comment': - createdRelationshipWithNestedAttributes.comment = resource.properties - break - case 'User': - createdRelationshipWithNestedAttributes.user = resource.properties - break - } + createdRelationshipWithNestedAttributes = txResult[0] } finally { session.close() } diff --git a/backend/src/schema/resolvers/moderation.spec.js b/backend/src/schema/resolvers/moderation.spec.js index 1c056500e..6dd2b41f7 100644 --- a/backend/src/schema/resolvers/moderation.spec.js +++ b/backend/src/schema/resolvers/moderation.spec.js @@ -8,63 +8,50 @@ const factory = Factory() const neode = getNeode() const driver = getDriver() -let query, - mutate, +let mutate, authenticatedUser, disableVariables, enableVariables, - resourceVariables, moderator, - nonModerator + nonModerator, + closeReportVariables -const reportMutation = gql` - mutation($resourceId: ID!, $reasonCategory: ReasonCategory!, $reasonDescription: String!) { - fileReport( - resourceId: $resourceId - reasonCategory: $reasonCategory - reasonDescription: $reasonDescription - ) { - type - } - } -` const reviewMutation = gql` mutation($resourceId: ID!, $disable: Boolean, $closed: Boolean) { review(resourceId: $resourceId, disable: $disable, closed: $closed) { - post { - id + createdAt + updatedAt + to { + __typename + ... on User { + id + disabled + } + ... on Post { + id + disabled + } + ... on Comment { + id + disabled + } } - comment { - id - } - } - } -` -const commentQuery = gql` - query($id: ID!) { - Comment(id: $id) { - id - disabled - reviewedByModerator { - id - } - } - } -` -const postQuery = gql` - query($id: ID) { - Post(id: $id) { - id - disabled - reviewedByModerator { + report { id + createdAt + updatedAt + closed + reviewedByModerator { + id + } } } } ` describe('moderate resources', () => { - beforeAll(() => { + beforeAll(async () => { + await factory.cleanDatabase() authenticatedUser = undefined const { server } = createServer({ context: () => { @@ -76,13 +63,9 @@ describe('moderate resources', () => { }, }) mutate = createTestClient(server).mutate - query = createTestClient(server).query }) beforeEach(async () => { - resourceVariables = { - id: 'undefined-resource', - } disableVariables = { resourceId: 'undefined-resource', disable: true, @@ -101,12 +84,81 @@ describe('moderate resources', () => { password: '1234', role: 'moderator', }) + nonModerator = await factory.create('User', { + id: 'non-moderator', + name: 'Non Moderator', + email: 'non.moderator@example.org', + password: '1234', + }) }) afterEach(async () => { await factory.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 Authorised!' }], + }) + }) + }) + + 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 Authorised!' }], + }) + }) + }) + + describe('moderator', () => { + beforeEach(async () => { + authenticatedUser = await moderator.toJson() + const questionablePost = await factory.create('Post', { + id: 'should-i-be-disabled', + }) + const reportAgainstQuestionablePost = await factory.create('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: { + to: { __typename: 'Post', id: 'should-i-be-disabled', disabled: false }, + report: { id: expect.any(String), closed: true }, + }, + }, + errors: undefined, + }) + }) + }) + }) + describe('review to disable', () => { describe('unauthenticated', () => { it('throws authorization error', async () => { @@ -119,218 +171,256 @@ describe('moderate resources', () => { }) describe('authenticated', () => { - describe('non moderator', () => { + 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 Authorised!' }], + }) + }) + }) + + describe('moderator', () => { + beforeEach(async () => { + authenticatedUser = await moderator.toJson() + }) + + describe('review of a resource that is not a (Comment|Post|User) ', () => { beforeEach(async () => { - nonModerator = await factory.create('User', { - id: 'non-moderator', - name: 'Non Moderator', - email: 'non.moderator@example.org', - password: '1234', - }) - authenticatedUser = await nonModerator.toJson() + disableVariables = { + ...disableVariables, + resourceId: 'tag-id', + } + await factory.create('Tag', { id: 'tag-id' }) }) - it('throws authorization error', async () => { + it('returns null', async () => { await expect( mutate({ mutation: reviewMutation, variables: disableVariables }), ).resolves.toMatchObject({ - errors: [{ message: 'Not Authorised!' }], + data: { review: null }, }) }) }) - describe('moderator', () => { + describe('moderate a comment', () => { beforeEach(async () => { - authenticatedUser = await moderator.toJson() + const trollingComment = await factory.create('Comment', { + id: 'comment-id', + }) + const reportAgainstTrollingComment = await factory.create('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', + } }) - describe('moderate a resource that is not a (Comment|Post|User) ', () => { - beforeEach(async () => { - disableVariables = { - ...disableVariables, - resourceId: 'sample-tag-id', - } - await factory.create('Tag', { id: 'sample-tag-id' }) - }) - - it('returns null', async () => { - await expect( - mutate({ mutation: reviewMutation, variables: disableVariables }), - ).resolves.toMatchObject({ - data: { review: null }, - }) + it('returns disabled resource id', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { review: { to: { __typename: 'Comment', id: 'comment-id' } } }, + errors: undefined, }) }) - describe('moderate a comment', () => { - beforeEach(async () => { - await factory.create('Comment', { - id: 'comment-id', - }) - await mutate({ - mutation: reportMutation, - variables: { - resourceId: 'comment-id', - reasonCategory: 'discrimination_etc', - reasonDescription: 'I am what I am !!!', + it('returns .reviewedByModerator', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'Comment', id: 'comment-id' }, + report: { id: expect.any(String), reviewedByModerator: { id: 'moderator-id' } }, }, - }) - }) - - it('returns disabled resource id', async () => { - disableVariables = { - ...disableVariables, - resourceId: 'comment-id', - } - await expect( - mutate({ mutation: reviewMutation, variables: disableVariables }), - ).resolves.toMatchObject({ - data: { review: { comment: { id: 'comment-id' } } }, - errors: undefined, - }) - }) - - it('changes .reviewedByModerator', async () => { - resourceVariables = { - id: 'comment-id', - } - disableVariables = { - ...disableVariables, - resourceId: 'comment-id', - } - const before = { data: { Comment: [{ id: 'comment-id', reviewedByModerator: null }] } } - const expected = { - data: { - Comment: [{ id: 'comment-id', reviewedByModerator: { id: 'moderator-id' } }], - }, - } - await expect( - query({ query: commentQuery, variables: resourceVariables }), - ).resolves.toMatchObject(before) - await expect( - mutate({ mutation: reviewMutation, variables: disableVariables }), - ).resolves.toMatchObject({ - data: { review: { comment: { id: 'comment-id' } } }, - }) - await expect( - query({ query: commentQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) - }) - - it('updates .disabled on comment', async () => { - resourceVariables = { - id: 'comment-id', - } - disableVariables = { - ...disableVariables, - resourceId: 'comment-id', - } - const before = { data: { Comment: [{ id: 'comment-id', disabled: false }] } } - const expected = { data: { Comment: [{ id: 'comment-id', disabled: true }] } } - - await expect( - query({ query: commentQuery, variables: resourceVariables }), - ).resolves.toMatchObject(before) - await expect( - mutate({ mutation: reviewMutation, variables: disableVariables }), - ).resolves.toMatchObject({ - data: { review: { comment: { id: 'comment-id' } } }, - }) - await expect( - query({ query: commentQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) + }, }) }) - describe('moderate a post', () => { - beforeEach(async () => { - await factory.create('Post', { - id: 'sample-post-id', - }) - await mutate({ - mutation: reportMutation, - variables: { - resourceId: 'sample-post-id', - reasonCategory: 'discrimination_etc', - reasonDescription: 'I am what I am !!!', + it('updates .disabled on comment', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { review: { to: { __typename: 'Comment', id: 'comment-id', disabled: true } } }, + }) + }) + + it('can be closed with one review', async () => { + closeReportVariables = { + ...disableVariables, + closed: true, + } + await expect( + mutate({ mutation: reviewMutation, variables: closeReportVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'Comment', id: 'comment-id' }, + report: { id: expect.any(String), closed: true }, }, - }) + }, }) + }) + }) - it('returns disabled resource id', async () => { - disableVariables = { - ...disableVariables, - resourceId: 'sample-post-id', - } - await expect( - mutate({ mutation: reviewMutation, variables: disableVariables }), - ).resolves.toMatchObject({ - data: { review: { post: { id: 'sample-post-id' } } }, - }) + describe('moderate a post', () => { + beforeEach(async () => { + const trollingPost = await factory.create('Post', { + id: 'post-id', }) + const reportAgainstTrollingPost = await factory.create('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('changes .reviewedByModerator', async () => { - resourceVariables = { - id: 'sample-post-id', - } - disableVariables = { - ...disableVariables, - resourceId: 'sample-post-id', - } - const before = { data: { Post: [{ id: 'sample-post-id', reviewedByModerator: null }] } } - const expected = { - data: { - Post: [{ id: 'sample-post-id', reviewedByModerator: { id: 'moderator-id' } }], + it('returns disabled resource id', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'Post', id: 'post-id' }, }, - } - - await expect( - query({ query: postQuery, variables: resourceVariables }), - ).resolves.toMatchObject(before) - await expect( - mutate({ mutation: reviewMutation, variables: disableVariables }), - ).resolves.toMatchObject({ - data: { review: { post: { id: 'sample-post-id' } } }, - }) - await expect( - query({ query: postQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) + }, }) + }) - it('updates .disabled on post', async () => { - resourceVariables = { - id: 'sample-post-id', - } - disableVariables = { - ...disableVariables, - resourceId: 'sample-post-id', - } - const before = { data: { Post: [{ id: 'sample-post-id', disabled: false }] } } - const expected = { data: { Post: [{ id: 'sample-post-id', disabled: true }] } } + it('returns .reviewedByModerator', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'Post', id: 'post-id' }, + report: { id: expect.any(String), reviewedByModerator: { id: 'moderator-id' } }, + }, + }, + }) + }) - await expect( - query({ query: postQuery, variables: resourceVariables }), - ).resolves.toMatchObject(before) - await expect( - mutate({ mutation: reviewMutation, variables: disableVariables }), - ).resolves.toMatchObject({ - data: { review: { post: { id: 'sample-post-id' } } }, - }) - await expect( - query({ query: postQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) + it('updates .disabled on post', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { review: { to: { __typename: 'Post', id: 'post-id', disabled: true } } }, + }) + }) + + it('can be closed with one review', async () => { + closeReportVariables = { + ...disableVariables, + closed: true, + } + await expect( + mutate({ mutation: reviewMutation, variables: closeReportVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'Post', id: 'post-id' }, + report: { id: expect.any(String), closed: true }, + }, + }, + }) + }) + }) + + describe('moderate a user', () => { + beforeEach(async () => { + const troll = await factory.create('User', { + id: 'user-id', + }) + const reportAgainstTroll = await factory.create('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: { to: { __typename: 'User', id: 'user-id' } } }, + }) + }) + + it('returns .reviewedByModerator', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'User', id: 'user-id' }, + report: { id: expect.any(String), reviewedByModerator: { id: 'moderator-id' } }, + }, + }, + }) + }) + + it('updates .disabled on user', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: disableVariables }), + ).resolves.toMatchObject({ + data: { review: { to: { __typename: 'User', id: 'user-id', disabled: true } } }, + }) + }) + + it('can be closed with one review', async () => { + closeReportVariables = { + ...disableVariables, + closed: true, + } + await expect( + mutate({ mutation: reviewMutation, variables: closeReportVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'User', id: 'user-id' }, + report: { id: expect.any(String), closed: true }, + }, + }, }) }) }) }) }) - describe('enable', () => { + describe('review to re-enable after disabled', () => { describe('unautenticated user', () => { it('throws authorization error', async () => { enableVariables = { ...enableVariables, - resourceId: 'sample-post-id', + resourceId: 'post-id', } await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), @@ -343,19 +433,13 @@ describe('moderate resources', () => { describe('authenticated user', () => { describe('non moderator', () => { beforeEach(async () => { - nonModerator = await factory.create('User', { - id: 'non-moderator', - name: 'Non Moderator', - email: 'non.moderator@example.org', - password: '1234', - }) authenticatedUser = await nonModerator.toJson() }) it('throws authorization error', async () => { enableVariables = { ...enableVariables, - resourceId: 'sample-post-id', + resourceId: 'post-id', } await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), @@ -372,13 +456,13 @@ describe('moderate resources', () => { describe('moderate a resource that is not a (Comment|Post|User) ', () => { beforeEach(async () => { - await Promise.all([factory.create('Tag', { id: 'sample-tag-id' })]) + await Promise.all([factory.create('Tag', { id: 'tag-id' })]) }) it('returns null', async () => { enableVariables = { ...enableVariables, - resourceId: 'sample-tag-id', + resourceId: 'tag-id', } await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), @@ -390,132 +474,175 @@ describe('moderate resources', () => { describe('moderate a comment', () => { beforeEach(async () => { - resourceVariables = { + const trollingComment = await factory.create('Comment', { id: 'comment-id', - } - disableVariables = { - ...disableVariables, - resourceId: 'comment-id', - } + }) + const reportAgainstTrollingComment = await factory.create('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', } - await factory.create('Comment', { - id: 'comment-id', - }) - await mutate({ - mutation: reportMutation, - variables: { - resourceId: 'comment-id', - reasonCategory: 'discrimination_etc', - reasonDescription: 'I am what I am !!!', - }, - }) - await mutate({ mutation: reviewMutation, variables: disableVariables }) }) it('returns enabled resource id', async () => { await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), ).resolves.toMatchObject({ - data: { review: { comment: { id: 'comment-id' } } }, + data: { review: { to: { __typename: 'Comment', id: 'comment-id' } } }, }) }) - it('changes .reviewedByModerator', async () => { - const expected = { - data: { - Comment: [{ id: 'comment-id', reviewedByModerator: { id: 'moderator-id' } }], - }, - } - + it('returns .reviewedByModerator', async () => { await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), ).resolves.toMatchObject({ - data: { review: { comment: { id: 'comment-id' } } }, + data: { + review: { + to: { __typename: 'Comment', id: 'comment-id' }, + report: { id: expect.any(String), reviewedByModerator: { id: 'moderator-id' } }, + }, + }, }) - await expect( - query({ query: commentQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) }) it('updates .disabled on comment', async () => { - const expected = { - data: { Comment: [{ id: 'comment-id', disabled: false }] }, - } - await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), ).resolves.toMatchObject({ - data: { review: { comment: { id: 'comment-id' } } }, + data: { + review: { to: { __typename: 'Comment', id: 'comment-id', disabled: false } }, + }, }) - await expect( - query({ query: commentQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) }) }) describe('moderate a post', () => { beforeEach(async () => { - resourceVariables = { id: 'post-id' } - disableVariables = { - ...disableVariables, - resourceId: 'post-id', - } + const trollingPost = await factory.create('Post', { + id: 'post-id', + }) + const reportAgainstTrollingPost = await factory.create('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', } - await factory.create('Post', { - id: 'post-id', - }) - await mutate({ - mutation: reportMutation, - variables: { - resourceId: 'post-id', - reasonCategory: 'discrimination_etc', - reasonDescription: 'I am what I am !!!', - }, - }) - await mutate({ mutation: reviewMutation, variables: disableVariables }) }) it('returns enabled resource id', async () => { await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), ).resolves.toMatchObject({ - data: { review: { post: { id: 'post-id' } } }, + data: { review: { to: { __typename: 'Post', id: 'post-id' } } }, }) }) - it('changes .reviewedByModerator', async () => { - const expected = { - data: { Post: [{ id: 'post-id', reviewedByModerator: { id: 'moderator-id' } }] }, - } + it('returns .reviewedByModerator', async () => { await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), ).resolves.toMatchObject({ - data: { review: { post: { id: 'post-id' } } }, + data: { + review: { + to: { __typename: 'Post', id: 'post-id' }, + report: { id: expect.any(String), reviewedByModerator: { id: 'moderator-id' } }, + }, + }, }) - await expect( - query({ query: postQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) }) it('updates .disabled on post', async () => { - const expected = { - data: { Post: [{ id: 'post-id', disabled: false }] }, - } - await expect( mutate({ mutation: reviewMutation, variables: enableVariables }), ).resolves.toMatchObject({ - data: { review: { post: { id: 'post-id' } } }, + data: { review: { to: { __typename: 'Post', id: 'post-id', disabled: false } } }, }) + }) + }) + + describe('moderate a user', () => { + beforeEach(async () => { + const troll = await factory.create('User', { + id: 'user-id', + }) + const reportAgainstTroll = await factory.create('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( - query({ query: postQuery, variables: resourceVariables }), - ).resolves.toMatchObject(expected) + mutate({ mutation: reviewMutation, variables: enableVariables }), + ).resolves.toMatchObject({ + data: { review: { to: { __typename: 'User', id: 'user-id' } } }, + }) + }) + + it('returns .reviewedByModerator', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: enableVariables }), + ).resolves.toMatchObject({ + data: { + review: { + to: { __typename: 'User', id: 'user-id' }, + report: { id: expect.any(String), reviewedByModerator: { id: 'moderator-id' } }, + }, + }, + }) + }) + + it('updates .disabled on user', async () => { + await expect( + mutate({ mutation: reviewMutation, variables: enableVariables }), + ).resolves.toMatchObject({ + data: { review: { to: { __typename: 'User', id: 'user-id', disabled: false } } }, + }) }) }) }) diff --git a/backend/src/schema/types/type/REVIEWED.gql b/backend/src/schema/types/type/REVIEWED.gql index c296483ea..5b4a392ae 100644 --- a/backend/src/schema/types/type/REVIEWED.gql +++ b/backend/src/schema/types/type/REVIEWED.gql @@ -1,23 +1,15 @@ type REVIEWED { createdAt: String! updatedAt: String! - # reasonCategory: ReasonCategory - # reasonDescription: String disable: Boolean! closed: Boolean! - - reportId: ID! - reportCreatedAt: String! - reportUpdatedAt: String! - reportDisable: Boolean! - reportClosed: Boolean! - + report: Report + # @cypher(statement: "MATCH (report:Report)<-[this:REVIEWED]-(:User) RETURN report") moderator: User type: String - user: User - post: Post - comment: Comment + to: ReviewedResource } +union ReviewedResource = User | Post | Comment type Mutation { review(resourceId: ID!, disable: Boolean, closed: Boolean): REVIEWED