mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Refactored backend database to a single REPORTED relation
This commit is contained in:
parent
94c7d73019
commit
82228c6c99
@ -122,7 +122,7 @@ const permissions = shield(
|
|||||||
embed: allow,
|
embed: allow,
|
||||||
Category: allow,
|
Category: allow,
|
||||||
Tag: allow,
|
Tag: allow,
|
||||||
Report: isModerator,
|
reports: isModerator,
|
||||||
statistics: allow,
|
statistics: allow,
|
||||||
currentUser: allow,
|
currentUser: allow,
|
||||||
Post: or(onlyEnabledContent, isModerator),
|
Post: or(onlyEnabledContent, isModerator),
|
||||||
|
|||||||
@ -35,7 +35,6 @@ export default applyScalars(
|
|||||||
'Notfication',
|
'Notfication',
|
||||||
'Post',
|
'Post',
|
||||||
'Comment',
|
'Comment',
|
||||||
'REPORTED',
|
|
||||||
'Statistics',
|
'Statistics',
|
||||||
'LoggedInUser',
|
'LoggedInUser',
|
||||||
'Location',
|
'Location',
|
||||||
@ -43,6 +42,7 @@ export default applyScalars(
|
|||||||
'User',
|
'User',
|
||||||
'EMOTED',
|
'EMOTED',
|
||||||
'NOTIFIED',
|
'NOTIFIED',
|
||||||
|
'REPORTED',
|
||||||
],
|
],
|
||||||
// add 'User' here as soon as possible
|
// add 'User' here as soon as possible
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,17 +1,10 @@
|
|||||||
import uuid from 'uuid/v4'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
report: async (
|
report: async (_parent, params, { driver, _req, user }, _resolveInfo) => {
|
||||||
_parent,
|
const { resourceId, reasonCategory, reasonDescription } = params
|
||||||
{ resourceId, reasonCategory, reasonDescription },
|
|
||||||
{ driver, _req, user },
|
|
||||||
_resolveInfo,
|
|
||||||
) => {
|
|
||||||
// Wolle const reportId = uuid()
|
|
||||||
const session = driver.session()
|
const session = driver.session()
|
||||||
const reportProperties = {
|
const reportProperties = {
|
||||||
// Wolle id: reportId,
|
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
reasonCategory,
|
reasonCategory,
|
||||||
reasonDescription,
|
reasonDescription,
|
||||||
@ -54,7 +47,7 @@ export default {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
const [dbResponse] = res.records.map(r => {
|
const [dbResponse] = res.records.map(r => {
|
||||||
return {
|
return {
|
||||||
@ -88,6 +81,60 @@ export default {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Query: {
|
||||||
|
reports: async (_parent, _params, { driver, _req, _user }, _resolveInfo) => {
|
||||||
|
const session = driver.session()
|
||||||
|
const res = await session.run(
|
||||||
|
`
|
||||||
|
MATCH (submitter:User)-[report:REPORTED]->(resource)
|
||||||
|
WHERE resource:User OR resource:Comment OR resource:Post
|
||||||
|
RETURN report, submitter, resource, labels(resource)[0] as type
|
||||||
|
`,
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
const dbResponse = res.records.map(r => {
|
||||||
|
return {
|
||||||
|
report: r.get('report'),
|
||||||
|
submitter: r.get('submitter'),
|
||||||
|
resource: r.get('resource'),
|
||||||
|
type: r.get('type'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!dbResponse) return null
|
||||||
|
|
||||||
|
const response = []
|
||||||
|
dbResponse.forEach(ele => {
|
||||||
|
const { report, submitter, resource, type } = ele
|
||||||
|
|
||||||
|
const responseEle = {
|
||||||
|
...report.properties,
|
||||||
|
resource: resource.properties,
|
||||||
|
resourceId: resource.properties.id,
|
||||||
|
post: null,
|
||||||
|
comment: null,
|
||||||
|
user: null,
|
||||||
|
submitter: submitter.properties,
|
||||||
|
type,
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case 'Post':
|
||||||
|
responseEle.post = resource.properties
|
||||||
|
break
|
||||||
|
case 'Comment':
|
||||||
|
responseEle.comment = resource.properties
|
||||||
|
break
|
||||||
|
case 'User':
|
||||||
|
responseEle.user = resource.properties
|
||||||
|
break
|
||||||
|
}
|
||||||
|
response.push(responseEle)
|
||||||
|
})
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,51 +1,24 @@
|
|||||||
import { GraphQLClient } from 'graphql-request'
|
import { GraphQLClient } from 'graphql-request'
|
||||||
import Factory from '../../seed/factories'
|
import Factory from '../../seed/factories'
|
||||||
import { host, login } from '../../jest/helpers'
|
import { host, login, gql } from '../../jest/helpers'
|
||||||
import { neode } from '../../bootstrap/neo4j'
|
import { getDriver, neode } from '../../bootstrap/neo4j'
|
||||||
|
import { createTestClient } from 'apollo-server-testing'
|
||||||
|
import createServer from '../.././server'
|
||||||
|
|
||||||
const factory = Factory()
|
const factory = Factory()
|
||||||
const instance = neode()
|
const instance = neode()
|
||||||
|
const driver = getDriver()
|
||||||
|
|
||||||
describe('report', () => {
|
describe('report mutation', () => {
|
||||||
let reportMutation
|
let reportMutation
|
||||||
let headers
|
let headers
|
||||||
|
let client
|
||||||
let returnedObject
|
let returnedObject
|
||||||
let variables
|
let variables
|
||||||
let createPostVariables
|
let createPostVariables
|
||||||
let user
|
let user
|
||||||
const categoryIds = ['cat9']
|
const categoryIds = ['cat9']
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
returnedObject = '{ createdAt }'
|
|
||||||
variables = {
|
|
||||||
resourceId: 'whatever',
|
|
||||||
reasonCategory: 'reason-category-dummy',
|
|
||||||
reasonDescription: 'Violates code of conduct !!!',
|
|
||||||
}
|
|
||||||
headers = {}
|
|
||||||
user = await factory.create('User', {
|
|
||||||
email: 'test@example.org',
|
|
||||||
password: '1234',
|
|
||||||
id: 'u1',
|
|
||||||
})
|
|
||||||
await factory.create('User', {
|
|
||||||
id: 'u2',
|
|
||||||
name: 'abusive-user',
|
|
||||||
role: 'user',
|
|
||||||
email: 'abusive-user@example.org',
|
|
||||||
})
|
|
||||||
await instance.create('Category', {
|
|
||||||
id: 'cat9',
|
|
||||||
name: 'Democracy & Politics',
|
|
||||||
icon: 'university',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await factory.cleanDatabase()
|
|
||||||
})
|
|
||||||
|
|
||||||
let client
|
|
||||||
const action = () => {
|
const action = () => {
|
||||||
// because of the template `${returnedObject}` the 'gql' tag from 'jest/helpers' is not working here
|
// because of the template `${returnedObject}` the 'gql' tag from 'jest/helpers' is not working here
|
||||||
reportMutation = `
|
reportMutation = `
|
||||||
@ -59,6 +32,37 @@ describe('report', () => {
|
|||||||
return client.request(reportMutation, variables)
|
return client.request(reportMutation, variables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
returnedObject = '{ createdAt }'
|
||||||
|
variables = {
|
||||||
|
resourceId: 'whatever',
|
||||||
|
reasonCategory: 'reason-category-dummy',
|
||||||
|
reasonDescription: 'Violates code of conduct !!!',
|
||||||
|
}
|
||||||
|
headers = {}
|
||||||
|
user = await factory.create('User', {
|
||||||
|
id: 'u1',
|
||||||
|
role: 'user',
|
||||||
|
email: 'test@example.org',
|
||||||
|
password: '1234',
|
||||||
|
})
|
||||||
|
await factory.create('User', {
|
||||||
|
id: 'u2',
|
||||||
|
role: 'user',
|
||||||
|
name: 'abusive-user',
|
||||||
|
email: 'abusive-user@example.org',
|
||||||
|
})
|
||||||
|
await instance.create('Category', {
|
||||||
|
id: 'cat9',
|
||||||
|
name: 'Democracy & Politics',
|
||||||
|
icon: 'university',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await factory.cleanDatabase()
|
||||||
|
})
|
||||||
|
|
||||||
describe('unauthenticated', () => {
|
describe('unauthenticated', () => {
|
||||||
it('throws authorization error', async () => {
|
it('throws authorization error', async () => {
|
||||||
await expect(action()).rejects.toThrow('Not Authorised')
|
await expect(action()).rejects.toThrow('Not Authorised')
|
||||||
@ -287,3 +291,227 @@ describe('report', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('reports query', () => {
|
||||||
|
let query
|
||||||
|
let mutate
|
||||||
|
let authenticatedUser = null
|
||||||
|
let moderator
|
||||||
|
let user
|
||||||
|
let author
|
||||||
|
const categoryIds = ['cat9']
|
||||||
|
|
||||||
|
const reportMutation = gql`
|
||||||
|
mutation($resourceId: ID!, $reasonCategory: String!, $reasonDescription: String!) {
|
||||||
|
report(
|
||||||
|
resourceId: $resourceId
|
||||||
|
reasonCategory: $reasonCategory
|
||||||
|
reasonDescription: $reasonDescription
|
||||||
|
) {
|
||||||
|
type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const reportsQuery = gql`
|
||||||
|
query {
|
||||||
|
reports(orderBy: createdAt_desc) {
|
||||||
|
createdAt
|
||||||
|
reasonCategory
|
||||||
|
reasonDescription
|
||||||
|
submitter {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
resourceId
|
||||||
|
type
|
||||||
|
user {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
comment {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
const { server } = createServer({
|
||||||
|
context: () => {
|
||||||
|
return {
|
||||||
|
driver,
|
||||||
|
user: authenticatedUser,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
query = createTestClient(server).query
|
||||||
|
mutate = createTestClient(server).mutate
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
authenticatedUser = null
|
||||||
|
|
||||||
|
moderator = await factory.create('User', {
|
||||||
|
id: 'mod1',
|
||||||
|
role: 'moderator',
|
||||||
|
email: 'moderator@example.org',
|
||||||
|
password: '1234',
|
||||||
|
})
|
||||||
|
user = await factory.create('User', {
|
||||||
|
id: 'user1',
|
||||||
|
role: 'user',
|
||||||
|
email: 'test@example.org',
|
||||||
|
password: '1234',
|
||||||
|
})
|
||||||
|
author = await factory.create('User', {
|
||||||
|
id: 'auth1',
|
||||||
|
role: 'user',
|
||||||
|
name: 'abusive-user',
|
||||||
|
email: 'abusive-user@example.org',
|
||||||
|
})
|
||||||
|
await instance.create('Category', {
|
||||||
|
id: 'cat9',
|
||||||
|
name: 'Democracy & Politics',
|
||||||
|
icon: 'university',
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
factory.create('Post', {
|
||||||
|
author,
|
||||||
|
id: 'p1',
|
||||||
|
categoryIds,
|
||||||
|
content: 'Not for you',
|
||||||
|
}),
|
||||||
|
factory.create('Post', {
|
||||||
|
author: moderator,
|
||||||
|
id: 'p2',
|
||||||
|
categoryIds,
|
||||||
|
content: 'Already seen post mention',
|
||||||
|
}),
|
||||||
|
factory.create('Post', {
|
||||||
|
author: user,
|
||||||
|
id: 'p3',
|
||||||
|
categoryIds,
|
||||||
|
content: 'You have been mentioned in a post',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
await Promise.all([
|
||||||
|
factory.create('Comment', {
|
||||||
|
author: user,
|
||||||
|
id: 'c1',
|
||||||
|
postId: 'p1',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
authenticatedUser = await user.toJson()
|
||||||
|
await Promise.all([
|
||||||
|
mutate({
|
||||||
|
mutation: reportMutation,
|
||||||
|
variables: {
|
||||||
|
resourceId: 'p1',
|
||||||
|
reasonCategory: 'other',
|
||||||
|
reasonDescription: 'This comment is bigoted',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
mutate({
|
||||||
|
mutation: reportMutation,
|
||||||
|
variables: {
|
||||||
|
resourceId: 'c1',
|
||||||
|
reasonCategory: 'discrimination-etc',
|
||||||
|
reasonDescription: 'This post is bigoted',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
mutate({
|
||||||
|
mutation: reportMutation,
|
||||||
|
variables: {
|
||||||
|
resourceId: 'auth1',
|
||||||
|
reasonCategory: 'doxing',
|
||||||
|
reasonDescription: 'This user is harassing me with bigoted remarks',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
authenticatedUser = null
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await factory.cleanDatabase()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
it('throws authorization error', async () => {
|
||||||
|
authenticatedUser = null
|
||||||
|
const { data, errors } = await query({ query: reportsQuery })
|
||||||
|
expect(data).toEqual({
|
||||||
|
reports: null,
|
||||||
|
})
|
||||||
|
expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('roll "user" gets no reports', async () => {
|
||||||
|
authenticatedUser = await user.toJson()
|
||||||
|
const { data, errors } = await query({ query: reportsQuery })
|
||||||
|
expect(data).toEqual({
|
||||||
|
reports: null,
|
||||||
|
})
|
||||||
|
expect(errors[0]).toHaveProperty('message', 'Not Authorised!')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('roll "moderator" gets reports', async () => {
|
||||||
|
const expected = {
|
||||||
|
// to check 'orderBy: createdAt_desc' is not possible here, because 'createdAt' does not differ
|
||||||
|
reports: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
reasonCategory: 'doxing',
|
||||||
|
reasonDescription: 'This user is harassing me with bigoted remarks',
|
||||||
|
submitter: expect.objectContaining({
|
||||||
|
id: 'user1',
|
||||||
|
}),
|
||||||
|
resourceId: 'auth1',
|
||||||
|
type: 'User',
|
||||||
|
user: expect.objectContaining({
|
||||||
|
id: 'auth1',
|
||||||
|
}),
|
||||||
|
post: null,
|
||||||
|
comment: null,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
reasonCategory: 'other',
|
||||||
|
reasonDescription: 'This comment is bigoted',
|
||||||
|
submitter: expect.objectContaining({
|
||||||
|
id: 'user1',
|
||||||
|
}),
|
||||||
|
resourceId: 'p1',
|
||||||
|
type: 'Post',
|
||||||
|
user: null,
|
||||||
|
post: expect.objectContaining({
|
||||||
|
id: 'p1',
|
||||||
|
}),
|
||||||
|
comment: null,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
createdAt: expect.any(String),
|
||||||
|
reasonCategory: 'discrimination-etc',
|
||||||
|
reasonDescription: 'This post is bigoted',
|
||||||
|
submitter: expect.objectContaining({
|
||||||
|
id: 'user1',
|
||||||
|
}),
|
||||||
|
resourceId: 'c1',
|
||||||
|
type: 'Comment',
|
||||||
|
user: null,
|
||||||
|
post: null,
|
||||||
|
comment: expect.objectContaining({
|
||||||
|
id: 'c1',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticatedUser = await moderator.toJson()
|
||||||
|
const { data } = await query({ query: reportsQuery })
|
||||||
|
expect(data).toEqual(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@ -34,29 +34,6 @@ type Mutation {
|
|||||||
unfollowUser(id: ID!): User
|
unfollowUser(id: ID!): User
|
||||||
}
|
}
|
||||||
|
|
||||||
# Wolle
|
|
||||||
# type Report {
|
|
||||||
# not necessary
|
|
||||||
# id: ID!
|
|
||||||
# done
|
|
||||||
# createdAt: String!
|
|
||||||
# done
|
|
||||||
# reasonCategory: String!
|
|
||||||
# done
|
|
||||||
# reasonDescription: String!
|
|
||||||
# done
|
|
||||||
# submitter: User @relation(name: "REPORTED", direction: "IN")
|
|
||||||
# done
|
|
||||||
# type: String!
|
|
||||||
# @cypher(statement: "MATCH (resource)<-[:REPORTED]-(this) RETURN labels(resource)[0]")
|
|
||||||
# seems unused
|
|
||||||
# comment: Comment @relation(name: "REPORTED", direction: "OUT")
|
|
||||||
# seems unused
|
|
||||||
# post: Post @relation(name: "REPORTED", direction: "OUT")
|
|
||||||
# seems unused
|
|
||||||
# user: User @relation(name: "REPORTED", direction: "OUT")
|
|
||||||
# }
|
|
||||||
|
|
||||||
enum Deletable {
|
enum Deletable {
|
||||||
Post
|
Post
|
||||||
Comment
|
Comment
|
||||||
|
|||||||
@ -4,8 +4,9 @@ type REPORTED {
|
|||||||
reasonDescription: String
|
reasonDescription: String
|
||||||
submitter: User
|
submitter: User
|
||||||
@cypher(statement: "MATCH (resource)<-[:REPORTED]-(user:User) RETURN user")
|
@cypher(statement: "MATCH (resource)<-[:REPORTED]-(user:User) RETURN user")
|
||||||
resource: ReportReource
|
# not yet supported
|
||||||
@cypher(statement: "MATCH (resource)<-[:REPORTED]-(user:User) RETURN resource")
|
# resource: ReportReource
|
||||||
|
# @cypher(statement: "MATCH (resource)<-[:REPORTED]-(user:User) RETURN resource")
|
||||||
resourceId: ID
|
resourceId: ID
|
||||||
@cypher(statement: "MATCH (resource)<-[:REPORTED]-(user:User) RETURN resource {.id}")
|
@cypher(statement: "MATCH (resource)<-[:REPORTED]-(user:User) RETURN resource {.id}")
|
||||||
type: String
|
type: String
|
||||||
@ -15,14 +16,15 @@ type REPORTED {
|
|||||||
comment: Comment
|
comment: Comment
|
||||||
}
|
}
|
||||||
|
|
||||||
union ReportReource = User | Post | Comment
|
# not yet supported
|
||||||
|
# union ReportReource = User | Post | Comment
|
||||||
|
|
||||||
enum ReportOrdering {
|
enum ReportOrdering {
|
||||||
createdAt_desc
|
createdAt_desc
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
Report(orderBy: ReportOrdering): [REPORTED]
|
reports(orderBy: ReportOrdering): [REPORTED]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
export const reportListQuery = () => {
|
export const reportListQuery = () => {
|
||||||
// no limit vor the moment like before: "Report(first: 20, orderBy: createdAt_desc)"
|
// no limit vor the moment like before: "reports(first: 20, orderBy: createdAt_desc)"
|
||||||
return gql`
|
return gql`
|
||||||
query {
|
query {
|
||||||
Report(orderBy: createdAt_desc) {
|
reports(orderBy: createdAt_desc) {
|
||||||
createdAt
|
createdAt
|
||||||
reasonCategory
|
reasonCategory
|
||||||
reasonDescription
|
reasonDescription
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user