This commit is contained in:
Wolfgang Huß 2019-03-12 18:45:49 +01:00
commit a6f96cad78
5 changed files with 76 additions and 39 deletions

View File

@ -6,9 +6,11 @@ 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'))
.toString('utf-8')
export const typeDefs = fs
.readFileSync(
process.env.GRAPHQL_SCHEMA || path.join(__dirname, 'schema.graphql')
)
.toString('utf-8')
export const resolvers = {
Query: {

View File

@ -1,12 +1,14 @@
import uniqueSlug from './slugify/uniqueSlug'
const isUniqueFor = (context, type) => {
return async (slug) => {
return async slug => {
const session = context.driver.session()
const response = await session.run(
`MATCH(p:${type} {slug: $slug }) return p.slug`, {
`MATCH(p:${type} {slug: $slug }) return p.slug`,
{
slug
})
}
)
session.close()
return response.records.length === 0
}
@ -15,19 +17,27 @@ const isUniqueFor = (context, type) => {
export default {
Mutation: {
CreatePost: async (resolve, root, args, context, info) => {
args.slug = args.slug || await uniqueSlug(args.title, isUniqueFor(context, 'Post'))
args.slug =
args.slug ||
(await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
return resolve(root, args, context, info)
},
CreateUser: async (resolve, root, args, context, info) => {
args.slug = args.slug || await uniqueSlug(args.name, isUniqueFor(context, 'User'))
args.slug =
args.slug ||
(await uniqueSlug(args.name, isUniqueFor(context, 'User')))
return resolve(root, args, context, info)
},
CreateOrganization: async (resolve, root, args, context, info) => {
args.slug = args.slug || await uniqueSlug(args.name, isUniqueFor(context, 'Organization'))
args.slug =
args.slug ||
(await uniqueSlug(args.name, isUniqueFor(context, 'Organization')))
return resolve(root, args, context, info)
},
CreateCategory: async (resolve, root, args, context, info) => {
args.slug = args.slug || await uniqueSlug(args.name, isUniqueFor(context, 'Category'))
args.slug =
args.slug ||
(await uniqueSlug(args.name, isUniqueFor(context, 'Category')))
return resolve(root, args, context, info)
}
}

View File

@ -8,7 +8,10 @@ const factory = Factory()
beforeEach(async () => {
await factory.create('User', { email: 'user@example.org', password: '1234' })
await factory.create('User', { email: 'someone@example.org', password: '1234' })
await factory.create('User', {
email: 'someone@example.org',
password: '1234'
})
headers = await login({ email: 'user@example.org', password: '1234' })
authenticatedClient = new GraphQLClient(host, { headers })
})
@ -26,7 +29,9 @@ describe('slugify', () => {
content: "Some content"
) { slug }
}`)
expect(response).toEqual({ CreatePost: { slug: 'i-am-a-brand-new-post' } })
expect(response).toEqual({
CreatePost: { slug: 'i-am-a-brand-new-post' }
})
})
describe('if slug exists', () => {
@ -48,12 +53,15 @@ describe('slugify', () => {
content: "Some content"
) { slug }
}`)
expect(response).toEqual({ CreatePost: { slug: 'pre-existing-post-1' } })
expect(response).toEqual({
CreatePost: { slug: 'pre-existing-post-1' }
})
})
describe('but if the client specifies a slug', () => {
it('rejects CreatePost', async () => {
await expect(authenticatedClient.request(`mutation {
await expect(
authenticatedClient.request(`mutation {
CreatePost(
title: "Pre-existing post",
content: "Some content",
@ -73,28 +81,33 @@ describe('slugify', () => {
}`)
}
it('generates a slug based on name', async () => {
await expect(action('CreateUser', 'name: "I am a user"'))
.resolves.toEqual({ CreateUser: { slug: 'i-am-a-user' } })
await expect(
action('CreateUser', 'name: "I am a user"')
).resolves.toEqual({ CreateUser: { slug: 'i-am-a-user' } })
})
describe('if slug exists', () => {
beforeEach(async () => {
await action('CreateUser', 'name: "Pre-existing user", slug: "pre-existing-user"')
await action(
'CreateUser',
'name: "Pre-existing user", slug: "pre-existing-user"'
)
})
it('chooses another slug', async () => {
await expect(action(
'CreateUser',
'name: "pre-existing-user"'
)).resolves.toEqual({ CreateUser: { slug: 'pre-existing-user-1' } })
await expect(
action('CreateUser', 'name: "pre-existing-user"')
).resolves.toEqual({ CreateUser: { slug: 'pre-existing-user-1' } })
})
describe('but if the client specifies a slug', () => {
it('rejects CreateUser', async () => {
await expect(action(
'CreateUser',
'name: "Pre-existing user", slug: "pre-existing-user"'
)).rejects.toThrow('already exists')
await expect(
action(
'CreateUser',
'name: "Pre-existing user", slug: "pre-existing-user"'
)
).rejects.toThrow('already exists')
})
})
})

View File

@ -4,6 +4,18 @@ type Query {
currentUser: User
"Get the latest Network Statistics"
statistics: Statistics!
findPosts(filter: String!, limit: Int = 10): [Post]! @cypher(
statement: """
CALL db.index.fulltext.queryNodes('full_text_search', $filter)
YIELD node as post, score
MATCH (post)<-[:WROTE]-(user:User)
WHERE score >= 0.2
AND NOT user.deleted = true AND NOT user.disabled = true
AND NOT post.deleted = true AND NOT post.disabled = true
RETURN post
LIMIT $limit
"""
)
}
type Mutation {
"Get a JWT Token for the given Email and password"

View File

@ -1,6 +1,5 @@
import { GraphQLClient, request } from 'graphql-request'
import { getDriver } from '../../bootstrap/neo4j'
import createBadge from './badges.js'
import createUser from './users.js'
import createOrganization from './organizations.js'
@ -23,26 +22,24 @@ const authenticatedHeaders = async ({ email, password }, host) => {
}
}
const factories = {
'Badge': createBadge,
'User': createUser,
'Organization': createOrganization,
'Post': createPost,
'Comment': createComment,
'Category': createCategory,
'Tag': createTag,
'Report': createReport
Badge: createBadge,
User: createUser,
Organization: createOrganization,
Post: createPost,
Comment: createComment,
Category: createCategory,
Tag: createTag,
Report: createReport
}
export const cleanDatabase = async (options = {}) => {
const {
driver = getDriver()
} = options
const { driver = getDriver() } = options
const session = driver.session()
const cypher = 'MATCH (n) DETACH DELETE n'
try {
return await session.run(cypher)
} catch (error) {
throw (error)
throw error
} finally {
session.close()
}
@ -63,7 +60,10 @@ export default function Factory (options = {}) {
factories,
lastResponse: null,
async authenticateAs ({ email, password }) {
const headers = await authenticatedHeaders({ email, password }, seedServerHost)
const headers = await authenticatedHeaders(
{ email, password },
seedServerHost
)
this.lastResponse = headers
this.graphQLClient = new GraphQLClient(seedServerHost, { headers })
return this