Merge pull request #207 from Human-Connection/27_disable_posts

Disable posts
This commit is contained in:
Robert Schäfer 2019-03-07 19:14:33 +01:00 committed by GitHub
commit 2d24fc9945
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 445 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import userManagement from './resolvers/user_management.js'
import statistics from './resolvers/statistics.js'
import reports from './resolvers/reports.js'
import posts from './resolvers/posts.js'
import moderation from './resolvers/moderation.js'
export const typeDefs =
fs.readFileSync(process.env.GRAPHQL_SCHEMA || path.join(__dirname, 'schema.graphql'))
@ -17,6 +18,7 @@ export const resolvers = {
Mutation: {
...userManagement.Mutation,
...reports.Mutation,
...moderation.Mutation,
...posts.Mutation
}
}

View File

@ -55,7 +55,10 @@ const permissions = shield({
report: isAuthenticated,
CreateBadge: isAdmin,
UpdateBadge: isAdmin,
DeleteBadge: isAdmin
DeleteBadge: isAdmin,
enable: isModerator,
disable: isModerator
// addFruitToBasket: isAuthenticated
// CreateUser: allow,
},

View File

@ -10,14 +10,25 @@ let action
beforeEach(async () => {
await Promise.all([
factory.create('User', { role: 'user', email: 'user@example.org', password: '1234' }),
factory.create('User', { role: 'moderator', email: 'moderator@example.org', password: '1234' })
factory.create('User', { id: 'm1', role: 'moderator', email: 'moderator@example.org', password: '1234' })
])
await factory.authenticateAs({ email: 'user@example.org', password: '1234' })
await Promise.all([
factory.create('Post', { title: 'Deleted post', deleted: true, disabled: false }),
factory.create('Post', { title: 'Disabled post', deleted: false, disabled: true }),
factory.create('Post', { title: 'Publicly visible post', deleted: false, disabled: false })
factory.create('Post', { title: 'Deleted post', deleted: true }),
factory.create('Post', { id: 'p2', title: 'Disabled post', deleted: false }),
factory.create('Post', { title: 'Publicly visible post', deleted: false })
])
const moderatorFactory = Factory()
await moderatorFactory.authenticateAs({ email: 'moderator@example.org', password: '1234' })
const disableMutation = `
mutation {
disable(resource: {
id: "p2"
type: contribution
})
}
`
await moderatorFactory.mutate(disableMutation)
})
afterEach(async () => {

View File

@ -0,0 +1,30 @@
export default {
Mutation: {
disable: async (object, params, { user, driver }) => {
const { resource: { id } } = params
const { id: userId } = user
const cypher = `
MATCH (u:User {id: $userId})
MATCH (r {id: $id})
SET r.disabled = true
MERGE (r)<-[:DISABLED]-(u)
`
const session = driver.session()
const res = await session.run(cypher, { id, userId })
session.close()
return Boolean(res)
},
enable: async (object, params, { user, driver }) => {
const { resource: { id } } = params
const cypher = `
MATCH (r {id: $id})<-[d:DISABLED]-()
SET r.disabled = false
DELETE d
`
const session = driver.session()
const res = await session.run(cypher, { id })
session.close()
return Boolean(res)
}
}
}

View File

@ -0,0 +1,370 @@
import Factory from '../seed/factories'
import { GraphQLClient } from 'graphql-request'
import { host, login } from '../jest/helpers'
const factory = Factory()
let client
const setupAuthenticateClient = (params) => {
const authenticateClient = async () => {
await factory.create('User', params)
const headers = await login(params)
client = new GraphQLClient(host, { headers })
}
return authenticateClient
}
let setup
const runSetup = async () => {
await setup.createResource()
await setup.authenticateClient()
}
beforeEach(() => {
setup = {
createResource: () => {
},
authenticateClient: () => {
client = new GraphQLClient(host)
}
}
})
afterEach(async () => {
await factory.cleanDatabase()
})
describe('disable', () => {
const mutation = `
mutation($id: ID!, $type: ResourceEnum!) {
disable(resource: { id: $id, type: $type })
}
`
let variables
beforeEach(() => {
// our defaul set of variables
variables = {
id: 'blabla',
type: 'contribution'
}
})
const action = async () => {
return client.request(mutation, variables)
}
it('throws authorization error', async () => {
await runSetup()
await expect(action()).rejects.toThrow('Not Authorised')
})
describe('authenticated', () => {
beforeEach(() => {
setup.authenticateClient = setupAuthenticateClient({
email: 'user@example.org',
password: '1234'
})
})
it('throws authorization error', async () => {
await runSetup()
await expect(action()).rejects.toThrow('Not Authorised')
})
describe('as moderator', () => {
beforeEach(() => {
setup.authenticateClient = setupAuthenticateClient({
id: 'u7',
email: 'moderator@example.org',
password: '1234',
role: 'moderator'
})
})
describe('on a comment', () => {
beforeEach(async () => {
variables = {
id: 'c47',
type: 'comment'
}
setup.createResource = async () => {
await factory.create('User', { id: 'u45', email: 'commenter@example.org', password: '1234' })
await factory.authenticateAs({ email: 'commenter@example.org', password: '1234' })
await Promise.all([
factory.create('Post', { id: 'p3' }),
factory.create('Comment', { id: 'c47' })
])
await Promise.all([
factory.relate('Comment', 'Author', { from: 'u45', to: 'c47' }),
factory.relate('Comment', 'Post', { from: 'c47', to: 'p3' })
])
}
})
it('returns true', async () => {
const expected = { disable: true }
await runSetup()
await expect(action()).resolves.toEqual(expected)
})
it('changes .disabledBy', async () => {
const before = { Comment: [{ id: 'c47', disabledBy: null }] }
const expected = { Comment: [{ id: 'c47', disabledBy: { id: 'u7' } }] }
await runSetup()
await expect(client.request(
'{ Comment { id, disabledBy { id } } }'
)).resolves.toEqual(before)
await action()
await expect(client.request(
'{ Comment(disabled: true) { id, disabledBy { id } } }'
)).resolves.toEqual(expected)
})
it('updates .disabled on comment', async () => {
const before = { Comment: [ { id: 'c47', disabled: false } ] }
const expected = { Comment: [ { id: 'c47', disabled: true } ] }
await runSetup()
await expect(client.request(
'{ Comment { id disabled } }'
)).resolves.toEqual(before)
await action()
await expect(client.request(
'{ Comment(disabled: true) { id disabled } }'
)).resolves.toEqual(expected)
})
})
describe('on a post', () => {
beforeEach(async () => {
variables = {
id: 'p9',
type: 'contribution'
}
setup.createResource = async () => {
await factory.create('User', { email: 'author@example.org', password: '1234' })
await factory.authenticateAs({ email: 'author@example.org', password: '1234' })
await factory.create('Post', {
id: 'p9' // that's the ID we will look for
})
}
})
it('returns true', async () => {
const expected = { disable: true }
await runSetup()
await expect(action()).resolves.toEqual(expected)
})
it('changes .disabledBy', async () => {
const before = { Post: [{ id: 'p9', disabledBy: null }] }
const expected = { Post: [{ id: 'p9', disabledBy: { id: 'u7' } }] }
await runSetup()
await expect(client.request(
'{ Post { id, disabledBy { id } } }'
)).resolves.toEqual(before)
await action()
await expect(client.request(
'{ Post(disabled: true) { id, disabledBy { id } } }'
)).resolves.toEqual(expected)
})
it('updates .disabled on post', async () => {
const before = { Post: [ { id: 'p9', disabled: false } ] }
const expected = { Post: [ { id: 'p9', disabled: true } ] }
await runSetup()
await expect(client.request(
'{ Post { id disabled } }'
)).resolves.toEqual(before)
await action()
await expect(client.request(
'{ Post(disabled: true) { id disabled } }'
)).resolves.toEqual(expected)
})
})
})
})
})
describe('enable', () => {
const mutation = `
mutation($id: ID!, $type: ResourceEnum!) {
enable(resource: { id: $id, type: $type })
}
`
let variables
const action = async () => {
return client.request(mutation, variables)
}
beforeEach(() => {
// our defaul set of variables
variables = {
id: 'blabla',
type: 'contribution'
}
})
it('throws authorization error', async () => {
await runSetup()
await expect(action()).rejects.toThrow('Not Authorised')
})
describe('authenticated', () => {
beforeEach(() => {
setup.authenticateClient = setupAuthenticateClient({
email: 'user@example.org',
password: '1234'
})
})
it('throws authorization error', async () => {
await runSetup()
await expect(action()).rejects.toThrow('Not Authorised')
})
describe('as moderator', () => {
beforeEach(async () => {
setup.authenticateClient = setupAuthenticateClient({
role: 'moderator',
email: 'someUser@example.org',
password: '1234'
})
})
describe('on a comment', () => {
beforeEach(async () => {
variables = {
id: 'c456',
type: 'comment'
}
setup.createResource = async () => {
await factory.create('User', { id: 'u123', email: 'author@example.org', password: '1234' })
await factory.authenticateAs({ email: 'author@example.org', password: '1234' })
await Promise.all([
factory.create('Post', { id: 'p9' }),
factory.create('Comment', { id: 'c456' })
])
await Promise.all([
factory.relate('Comment', 'Author', { from: 'u123', to: 'c456' }),
factory.relate('Comment', 'Post', { from: 'c456', to: 'p9' })
])
const disableMutation = `
mutation {
disable(resource: {
id: "c456"
type: comment
})
}
`
await factory.mutate(disableMutation) // that's we want to delete
}
})
it('returns true', async () => {
const expected = { enable: true }
await runSetup()
await expect(action()).resolves.toEqual(expected)
})
it('changes .disabledBy', async () => {
const before = { Comment: [{ id: 'c456', disabledBy: { id: 'u123' } }] }
const expected = { Comment: [{ id: 'c456', disabledBy: null }] }
await runSetup()
await expect(client.request(
'{ Comment(disabled: true) { id, disabledBy { id } } }'
)).resolves.toEqual(before)
await action()
await expect(client.request(
'{ Comment { id, disabledBy { id } } }'
)).resolves.toEqual(expected)
})
it('updates .disabled on post', async () => {
const before = { Comment: [ { id: 'c456', disabled: true } ] }
const expected = { Comment: [ { id: 'c456', disabled: false } ] }
await runSetup()
await expect(client.request(
'{ Comment(disabled: true) { id disabled } }'
)).resolves.toEqual(before)
await action() // this updates .disabled
await expect(client.request(
'{ Comment { id disabled } }'
)).resolves.toEqual(expected)
})
})
describe('on a post', () => {
beforeEach(async () => {
variables = {
id: 'p9',
type: 'contribution'
}
setup.createResource = async () => {
await factory.create('User', { id: 'u123', email: 'author@example.org', password: '1234' })
await factory.authenticateAs({ email: 'author@example.org', password: '1234' })
await factory.create('Post', {
id: 'p9' // that's the ID we will look for
})
const disableMutation = `
mutation {
disable(resource: {
id: "p9"
type: contribution
})
}
`
await factory.mutate(disableMutation) // that's we want to delete
}
})
it('returns true', async () => {
const expected = { enable: true }
await runSetup()
await expect(action()).resolves.toEqual(expected)
})
it('changes .disabledBy', async () => {
const before = { Post: [{ id: 'p9', disabledBy: { id: 'u123' } }] }
const expected = { Post: [{ id: 'p9', disabledBy: null }] }
await runSetup()
await expect(client.request(
'{ Post(disabled: true) { id, disabledBy { id } } }'
)).resolves.toEqual(before)
await action()
await expect(client.request(
'{ Post { id, disabledBy { id } } }'
)).resolves.toEqual(expected)
})
it('updates .disabled on post', async () => {
const before = { Post: [ { id: 'p9', disabled: true } ] }
const expected = { Post: [ { id: 'p9', disabled: false } ] }
await runSetup()
await expect(client.request(
'{ Post(disabled: true) { id disabled } }'
)).resolves.toEqual(before)
await action() // this updates .disabled
await expect(client.request(
'{ Post { id disabled } }'
)).resolves.toEqual(expected)
})
})
})
})
})

View File

@ -7,6 +7,8 @@ type Mutation {
login(email: String!, password: String!): String!
signup(email: String!, password: String!): Boolean!
report(resource: Resource!, description: String): Report
disable(resource: Resource!): Boolean!
enable(resource: Resource!): Boolean!
}
type Statistics {
@ -74,6 +76,7 @@ type User {
avatar: String
deleted: Boolean
disabled: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
role: UserGroupEnum
location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l")
@ -133,6 +136,7 @@ type Post {
visibility: VisibilityEnum
deleted: Boolean
disabled: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
createdAt: String
updatedAt: String
@ -162,6 +166,7 @@ type Comment {
updatedAt: String
deleted: Boolean
disabled: Boolean
disabledBy: User @relation(name: "DISABLED", direction: "IN")
}
type Report {

View File

@ -86,6 +86,10 @@ export default function Factory (options = {}) {
this.lastResponse = await this.graphQLClient.request(mutation)
return this
},
async mutate (mutation, variables) {
this.lastResponse = await this.graphQLClient.request(mutation, variables)
return this
},
async cleanDatabase () {
this.lastResponse = await cleanDatabase({ driver: this.neo4jDriver })
return this
@ -94,6 +98,7 @@ export default function Factory (options = {}) {
result.authenticateAs.bind(result)
result.create.bind(result)
result.relate.bind(result)
result.mutate.bind(result)
result.cleanDatabase.bind(result)
return result
}

View File

@ -14,7 +14,6 @@ export default function (params) {
].join('. '),
image = faker.image.image(),
visibility = 'public',
disabled = false,
deleted = false
} = params
@ -26,7 +25,6 @@ export default function (params) {
content: "${content}",
image: "${image}",
visibility: ${visibility},
disabled: ${disabled},
deleted: ${deleted}
) { title, content }
}

View File

@ -25,10 +25,13 @@ export default function create (params) {
disabled: ${disabled},
deleted: ${deleted}
) {
id
name
email
avatar
role
deleted
disabled
}
}
`

View File

@ -87,7 +87,7 @@ import Factory from './factories'
asTrick.create('Post', { id: 'p4' }),
asTrack.create('Post', { id: 'p5' }),
asAdmin.create('Post', { id: 'p6' }),
asModerator.create('Post', { id: 'p7', disabled: true }),
asModerator.create('Post', { id: 'p7' }),
asUser.create('Post', { id: 'p8' }),
asTick.create('Post', { id: 'p9' }),
asTrick.create('Post', { id: 'p10' }),
@ -98,6 +98,16 @@ import Factory from './factories'
asTick.create('Post', { id: 'p15' })
])
const disableMutation = `
mutation {
disable(resource: {
id: "p11"
type: contribution
})
}
`
await asModerator.mutate(disableMutation)
await Promise.all([
f.relate('Post', 'Categories', { from: 'p0', to: 'cat16' }),
f.relate('Post', 'Categories', { from: 'p1', to: 'cat1' }),