Refactor reports query, tests

- Query returns an array of Reports with all the filedReports that
belong to them
- Mutation returns the same
This commit is contained in:
mattwr18 2019-11-26 21:34:21 +01:00
parent 2f249a73c5
commit eceeecd9b7
4 changed files with 165 additions and 102 deletions

View File

@ -19,7 +19,7 @@ export default {
WITH submitter, resource, report WITH submitter, resource, report
CREATE (report)<-[filed:FILED {createdAt: $createdAt, reasonCategory: $reasonCategory, reasonDescription: $reasonDescription}]-(submitter) CREATE (report)<-[filed:FILED {createdAt: $createdAt, reasonCategory: $reasonCategory, reasonDescription: $reasonDescription}]-(submitter)
RETURN submitter, report, filed, resource, labels(resource)[0] AS type RETURN submitter, report, resource, labels(resource)[0] AS type
`, `,
{ {
resourceId, resourceId,
@ -32,7 +32,6 @@ export default {
return reportRelationshipTransactionResponse.records.map(record => ({ return reportRelationshipTransactionResponse.records.map(record => ({
submitter: record.get('submitter').properties, submitter: record.get('submitter').properties,
report: record.get('report').properties, report: record.get('report').properties,
filed: record.get('filed').properties,
resource: record.get('resource').properties, resource: record.get('resource').properties,
type: record.get('type'), type: record.get('type'),
})) }))
@ -40,10 +39,9 @@ export default {
try { try {
const txResult = await writeTxResultPromise const txResult = await writeTxResultPromise
if (!txResult[0]) return null if (!txResult[0]) return null
const { submitter, report, filed, resource, type } = txResult[0] const { submitter, report, resource, type } = txResult[0]
createdRelationshipWithNestedAttributes = { createdRelationshipWithNestedAttributes = {
...filed, ...report,
report,
post: null, post: null,
comment: null, comment: null,
user: null, user: null,
@ -74,10 +72,10 @@ export default {
let reports, orderByClause let reports, orderByClause
switch (params.orderBy) { switch (params.orderBy) {
case 'createdAt_asc': case 'createdAt_asc':
orderByClause = 'ORDER BY report.createdAt ASC, filed.createdAt DESC' orderByClause = 'ORDER BY report.createdAt ASC'
break break
case 'createdAt_desc': case 'createdAt_desc':
orderByClause = 'ORDER BY report.createdAt DESC, filed.createdAt DESC' orderByClause = 'ORDER BY report.createdAt DESC'
break break
default: default:
orderByClause = '' orderByClause = ''
@ -87,7 +85,7 @@ export default {
` `
MATCH (submitter:User)-[filed:FILED]->(report:Report)-[:BELONGS_TO]->(resource) MATCH (submitter:User)-[filed:FILED]->(report:Report)-[:BELONGS_TO]->(resource)
WHERE resource:User OR resource:Post OR resource:Comment WHERE resource:User OR resource:Post OR resource:Comment
RETURN submitter, report, filed, resource, labels(resource)[0] as type RETURN submitter, report, resource, labels(resource)[0] as type
${orderByClause} ${orderByClause}
`, `,
{}, {},
@ -95,7 +93,6 @@ export default {
return allReportsTransactionResponse.records.map(record => ({ return allReportsTransactionResponse.records.map(record => ({
submitter: record.get('submitter').properties, submitter: record.get('submitter').properties,
report: record.get('report').properties, report: record.get('report').properties,
filed: record.get('filed').properties,
resource: record.get('resource').properties, resource: record.get('resource').properties,
type: record.get('type'), type: record.get('type'),
})) }))
@ -104,10 +101,9 @@ export default {
const txResult = await readTxPromise const txResult = await readTxPromise
if (!txResult[0]) return null if (!txResult[0]) return null
reports = txResult.map(reportedRecord => { reports = txResult.map(reportedRecord => {
const { report, submitter, filed, resource, type } = reportedRecord const { report, submitter, resource, type } = reportedRecord
const relationshipWithNestedAttributes = { const relationshipWithNestedAttributes = {
...report, ...report,
filed,
post: null, post: null,
comment: null, comment: null,
user: null, user: null,
@ -133,4 +129,40 @@ export default {
return reports return reports
}, },
}, },
Report: {
reportsFiled: async (parent, _params, context, _resolveInfo) => {
if (typeof parent.reportsFiled !== 'undefined') return parent.reportsFiled
const session = context.driver.session()
const { id } = parent
let reportsFiled
const readTxPromise = session.readTransaction(async tx => {
const allReportsTransactionResponse = await tx.run(
`
MATCH (submitter:User)-[filed:FILED]->(report:Report {id: $id})
RETURN filed, submitter
`,
{ id },
)
return allReportsTransactionResponse.records.map(record => ({
submitter: record.get('submitter').properties,
filed: record.get('filed').properties,
}))
})
try {
const txResult = await readTxPromise
if (!txResult[0]) return null
reportsFiled = txResult.map(reportedRecord => {
const { submitter, filed } = reportedRecord
const relationshipWithNestedAttributes = {
...filed,
submitter,
}
return relationshipWithNestedAttributes
})
} finally {
session.close()
}
return reportsFiled
},
},
} }

View File

@ -18,13 +18,12 @@ describe('file a report on a resource', () => {
reasonCategory: $reasonCategory reasonCategory: $reasonCategory
reasonDescription: $reasonDescription reasonDescription: $reasonDescription
) { ) {
id
createdAt createdAt
reasonCategory updatedAt
reasonDescription disable
closed
type type
submitter {
email
}
user { user {
name name
} }
@ -34,12 +33,13 @@ describe('file a report on a resource', () => {
comment { comment {
content content
} }
report { reportsFiled {
submitter {
id id
}
createdAt createdAt
updatedAt reasonCategory
disable reasonDescription
closed
} }
} }
} }
@ -129,14 +129,15 @@ describe('file a report on a resource', () => {
).resolves.toMatchObject({ ).resolves.toMatchObject({
data: { data: {
fileReport: { fileReport: {
type: 'User',
report: {
id: expect.any(String), id: expect.any(String),
createdAt: expect.any(String), createdAt: expect.any(String),
updatedAt: expect.any(String), updatedAt: expect.any(String),
disable: false, disable: false,
closed: false, closed: false,
user: {
name: 'abusive-user',
}, },
type: 'User',
}, },
}, },
errors: undefined, errors: undefined,
@ -153,7 +154,7 @@ describe('file a report on a resource', () => {
mutation: reportMutation, mutation: reportMutation,
variables: { ...variables, resourceId: 'abusive-user-id' }, variables: { ...variables, resourceId: 'abusive-user-id' },
}) })
expect(firstReport.data.fileReport.report).toEqual(secondReport.data.fileReport.report) expect(firstReport.data.fileReport.id).toEqual(secondReport.data.fileReport.id)
}) })
it.todo('creates multiple reports') it.todo('creates multiple reports')
@ -169,7 +170,22 @@ describe('file a report on a resource', () => {
).resolves.toMatchObject({ ).resolves.toMatchObject({
data: { data: {
fileReport: { fileReport: {
id: expect.any(String),
createdAt: expect.any(String),
updatedAt: expect.any(String),
disable: false,
closed: false,
type: 'User', type: 'User',
reportsFiled: [
{
submitter: {
id: 'current-user-id',
},
createdAt: expect.any(String),
reasonCategory: 'other',
reasonDescription: 'Violates code of conduct !!!',
},
],
}, },
}, },
errors: undefined, errors: undefined,
@ -203,10 +219,14 @@ describe('file a report on a resource', () => {
).resolves.toMatchObject({ ).resolves.toMatchObject({
data: { data: {
fileReport: { fileReport: {
reportsFiled: [
{
submitter: { submitter: {
email: 'test@example.org', id: 'current-user-id',
}, },
}, },
],
},
}, },
errors: undefined, errors: undefined,
}) })
@ -241,8 +261,12 @@ describe('file a report on a resource', () => {
).resolves.toMatchObject({ ).resolves.toMatchObject({
data: { data: {
fileReport: { fileReport: {
reportsFiled: [
{
reasonCategory: 'criminal_behavior_violation_german_law', reasonCategory: 'criminal_behavior_violation_german_law',
}, },
],
},
}, },
errors: undefined, errors: undefined,
}) })
@ -282,8 +306,12 @@ describe('file a report on a resource', () => {
).resolves.toMatchObject({ ).resolves.toMatchObject({
data: { data: {
fileReport: { fileReport: {
reportsFiled: [
{
reasonDescription: 'My reason!', reasonDescription: 'My reason!',
}, },
],
},
}, },
errors: undefined, errors: undefined,
}) })
@ -302,8 +330,12 @@ describe('file a report on a resource', () => {
).resolves.toMatchObject({ ).resolves.toMatchObject({
data: { data: {
fileReport: { fileReport: {
reportsFiled: [
{
reasonDescription: 'My reason !', reasonDescription: 'My reason !',
}, },
],
},
}, },
errors: undefined, errors: undefined,
}) })
@ -469,12 +501,11 @@ describe('file a report on a resource', () => {
const reportsQuery = gql` const reportsQuery = gql`
query { query {
reports(orderBy: createdAt_desc) { reports(orderBy: createdAt_desc) {
createdAt
reasonCategory
reasonDescription
submitter {
id id
} createdAt
updatedAt
disable
closed
type type
user { user {
id id
@ -485,12 +516,13 @@ describe('file a report on a resource', () => {
comment { comment {
id id
} }
report { reportsFiled {
submitter {
id id
}
createdAt createdAt
updatedAt reasonCategory
disable reasonDescription
closed
} }
} }
} }
@ -602,67 +634,73 @@ describe('file a report on a resource', () => {
const expected = { const expected = {
reports: expect.arrayContaining([ reports: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(String),
createdAt: expect.any(String), createdAt: expect.any(String),
reasonCategory: 'doxing', updatedAt: expect.any(String),
reasonDescription: 'This user is harassing me with bigoted remarks', disable: false,
submitter: expect.objectContaining({ closed: false,
id: 'current-user-id',
}),
type: 'User', type: 'User',
user: expect.objectContaining({ user: expect.objectContaining({
id: 'abusive-user-1', id: 'abusive-user-1',
}), }),
post: null, post: null,
comment: null, comment: null,
report: { reportsFiled: expect.arrayContaining([
expect.objectContaining({
submitter: expect.objectContaining({
id: 'current-user-id',
}),
createdAt: expect.any(String),
reasonCategory: 'doxing',
reasonDescription: 'This user is harassing me with bigoted remarks',
}),
]),
}),
expect.objectContaining({
id: expect.any(String), id: expect.any(String),
createdAt: expect.any(String), createdAt: expect.any(String),
updatedAt: expect.any(String), updatedAt: expect.any(String),
disable: false, disable: false,
closed: false, closed: false,
},
}),
expect.objectContaining({
createdAt: expect.any(String),
reasonCategory: 'other',
reasonDescription: 'This comment is bigoted',
submitter: expect.objectContaining({
id: 'current-user-id',
}),
type: 'Post', type: 'Post',
user: null, user: null,
post: expect.objectContaining({ post: expect.objectContaining({
id: 'abusive-post-1', id: 'abusive-post-1',
}), }),
comment: null, comment: null,
report: { reportsFiled: expect.arrayContaining([
expect.objectContaining({
submitter: expect.objectContaining({
id: 'current-user-id',
}),
createdAt: expect.any(String),
reasonCategory: 'other',
reasonDescription: 'This comment is bigoted',
}),
]),
}),
expect.objectContaining({
id: expect.any(String), id: expect.any(String),
createdAt: expect.any(String), createdAt: expect.any(String),
updatedAt: expect.any(String), updatedAt: expect.any(String),
disable: false, disable: false,
closed: false, closed: false,
},
}),
expect.objectContaining({
createdAt: expect.any(String),
reasonCategory: 'discrimination_etc',
reasonDescription: 'This post is bigoted',
submitter: expect.objectContaining({
id: 'current-user-id',
}),
type: 'Comment', type: 'Comment',
user: null, user: null,
post: null, post: null,
comment: expect.objectContaining({ comment: expect.objectContaining({
id: 'abusive-comment-1', id: 'abusive-comment-1',
}), }),
report: { reportsFiled: expect.arrayContaining([
id: expect.any(String), expect.objectContaining({
submitter: expect.objectContaining({
id: 'current-user-id',
}),
createdAt: expect.any(String), createdAt: expect.any(String),
updatedAt: expect.any(String), reasonCategory: 'discrimination_etc',
disable: false, reasonDescription: 'This post is bigoted',
closed: false, }),
}, ]),
}), }),
]), ]),
} }

View File

@ -2,17 +2,7 @@ type FILED {
createdAt: String! createdAt: String!
reasonCategory: ReasonCategory! reasonCategory: ReasonCategory!
reasonDescription: String! reasonDescription: String!
report: Report @cypher(
statement: "MATCH (resource)<-[:BELONGS_TO]-(report:Report)<-[:FILED]-(:User) WHERE NOT resource.deleted = true AND NOT resource.disabled = true RETURN report"
)
submitter: User submitter: User
# @cypher(statement: "MATCH (resource)<-[:FILED]-(user:User) RETURN user")
type: String
# @cypher(statement: "MATCH (resource)<-[:FILED]-(user:User) RETURN labels(resource)[0]")
user: User
post: Post
comment: Comment
} }
# this list equals the strings of an array in file "webapp/constants/modals.js" # this list equals the strings of an array in file "webapp/constants/modals.js"
@ -34,11 +24,3 @@ enum ReportOrdering {
createdAt_asc createdAt_asc
createdAt_desc createdAt_desc
} }
type Query {
reports(orderBy: ReportOrdering): [FILED]
}
type Mutation {
fileReport(resourceId: ID!, reasonCategory: ReasonCategory!, reasonDescription: String!): FILED
}

View File

@ -5,12 +5,23 @@ type Report {
rule: ReportRule! rule: ReportRule!
disable: Boolean! disable: Boolean!
closed: Boolean! closed: Boolean!
resource: ReportResource reportsFiled: [FILED]
filed: [FILED] user: User
post: Post
comment: Comment
type: String
} }
# not yet supported # not yet supported
union ReportResource = User | Post | Comment # union ReportResource = User | Post | Comment
enum ReportRule { enum ReportRule {
latestReviewUpdatedAtRules latestReviewUpdatedAtRules
} }
type Mutation {
fileReport(resourceId: ID!, reasonCategory: ReasonCategory!, reasonDescription: String!): Report
}
type Query {
reports(orderBy: ReportOrdering): [Report]
}