Implement+test blocking a user on backend

This commit is contained in:
Robert Schäfer 2019-08-09 00:55:44 +02:00 committed by roschaefer
parent cc1f932803
commit 5fb60d1132
4 changed files with 173 additions and 77 deletions

View File

@ -1,7 +1,56 @@
import uuid from 'uuid/v4' import uuid from 'uuid/v4'
import { neo4jgraphql } from 'neo4j-graphql-js'
import fileUpload from './fileUpload' import fileUpload from './fileUpload'
import { getBlockedUsers, getBlockedByUsers } from './users.js'
export default { export default {
Query: {
Post: async (object, params, context, resolveInfo) => {
const blockedUsers = await getBlockedUsers(context)
const blockedByUsers = await getBlockedByUsers(context)
params.filter = {
author_not: { id_in: [
...blockedByUsers.map(b => b.id),
...blockedUsers.map(b => b.id),
] }
}
return neo4jgraphql(object, params, context, resolveInfo, false)
},
PostsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => {
const session = context.driver.session()
const { postId, data } = params
const transactionRes = await session.run(
`MATCH (post:Post {id: $postId})<-[emoted:EMOTED {emotion: $data.emotion}]-()
RETURN COUNT(DISTINCT emoted) as emotionsCount
`,
{ postId, data },
)
session.close()
const [emotionsCount] = transactionRes.records.map(record => {
return record.get('emotionsCount').low
})
return emotionsCount
},
PostsEmotionsByCurrentUser: async (object, params, context, resolveInfo) => {
const session = context.driver.session()
const { postId } = params
const transactionRes = await session.run(
`MATCH (user:User {id: $userId})-[emoted:EMOTED]->(post:Post {id: $postId})
RETURN collect(emoted.emotion) as emotion`,
{ userId: context.user.id, postId },
)
session.close()
const [emotions] = transactionRes.records.map(record => {
return record.get('emotion')
})
return emotions
},
},
Mutation: { Mutation: {
UpdatePost: async (object, params, context, resolveInfo) => { UpdatePost: async (object, params, context, resolveInfo) => {
const { categoryIds } = params const { categoryIds } = params
@ -112,39 +161,4 @@ export default {
return emoted return emoted
}, },
}, },
Query: {
PostsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => {
const session = context.driver.session()
const { postId, data } = params
const transactionRes = await session.run(
`MATCH (post:Post {id: $postId})<-[emoted:EMOTED {emotion: $data.emotion}]-()
RETURN COUNT(DISTINCT emoted) as emotionsCount
`,
{ postId, data },
)
session.close()
const [emotionsCount] = transactionRes.records.map(record => {
return record.get('emotionsCount').low
})
return emotionsCount
},
PostsEmotionsByCurrentUser: async (object, params, context, resolveInfo) => {
const session = context.driver.session()
const { postId } = params
const transactionRes = await session.run(
`MATCH (user:User {id: $userId})-[emoted:EMOTED]->(post:Post {id: $postId})
RETURN collect(emoted.emotion) as emotion`,
{ userId: context.user.id, postId },
)
session.close()
const [emotions] = transactionRes.records.map(record => {
return record.get('emotion')
})
return emotions
},
},
} }

View File

@ -6,12 +6,10 @@ import Resolver from './helpers/Resolver'
const instance = neode() const instance = neode()
export default { export const getBlockedUsers = async context => {
Query: { const { neode } = context
blockedUsers: async (object, args, context, resolveInfo) => { const userModel = neode.model('User')
try { let blockedUsers = neode
const userModel = instance.model('User')
let blockedUsers = instance
.query() .query()
.match('user', userModel) .match('user', userModel)
.where('user.id', context.user.id) .where('user.id', context.user.id)
@ -21,6 +19,28 @@ export default {
blockedUsers = await blockedUsers.execute() blockedUsers = await blockedUsers.execute()
blockedUsers = blockedUsers.records.map(r => r.get('blocked').properties) blockedUsers = blockedUsers.records.map(r => r.get('blocked').properties)
return blockedUsers return blockedUsers
}
export const getBlockedByUsers = async context => {
const { neode } = context
const userModel = neode.model('User')
let blockedByUsers = neode
.query()
.match('user', userModel)
.relationship(userModel.relationships().get('blocked'))
.to('blocked', userModel)
.where('blocked.id', context.user.id)
.return('user')
blockedByUsers = await blockedByUsers.execute()
blockedByUsers = blockedByUsers.records.map(r => r.get('user').properties)
return blockedByUsers
}
export default {
Query: {
blockedUsers: async (object, args, context, resolveInfo) => {
try {
return getBlockedUsers(context)
} catch (e) { } catch (e) {
throw new UserInputError(e.message) throw new UserInputError(e.message)
} }

View File

@ -20,6 +20,7 @@ beforeEach(() => {
return { return {
user: authenticatedUser, user: authenticatedUser,
driver, driver,
neode: instance,
cypherParams: { cypherParams: {
currentUserId: authenticatedUser ? authenticatedUser.id : null, currentUserId: authenticatedUser ? authenticatedUser.id : null,
}, },
@ -153,7 +154,15 @@ describe('block', () => {
it('unfollows the user', async () => { it('unfollows the user', async () => {
await currentUser.relateTo(blockedUser, 'following') await currentUser.relateTo(blockedUser, 'following')
const queryUser = gql` query { User(id: "u2") { id isBlocked followedByCurrentUser } }` const queryUser = gql`
query {
User(id: "u2") {
id
isBlocked
followedByCurrentUser
}
}
`
const { query } = createTestClient(server) const { query } = createTestClient(server)
await expect(query({ query: queryUser })).resolves.toEqual( await expect(query({ query: queryUser })).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
@ -182,9 +191,20 @@ describe('block', () => {
}) })
await Promise.all([ await Promise.all([
post1.relateTo(currentUser, 'author'), post1.relateTo(currentUser, 'author'),
post2.relateTo(blockedUser, 'author') post2.relateTo(blockedUser, 'author'),
]) ])
postQuery = gql`query { Post(orderBy: createdAt_asc) { id title author { id name } } }` postQuery = gql`
query {
Post(orderBy: createdAt_asc) {
id
title
author {
id
name
}
}
}
`
}) })
const bothPostsAreInTheNewsfeed = async () => { const bothPostsAreInTheNewsfeed = async () => {
@ -199,7 +219,7 @@ describe('block', () => {
author: { author: {
name: 'Current User', name: 'Current User',
id: 'u1', id: 'u1',
} },
}, },
{ {
id: 'p23', id: 'p23',
@ -207,7 +227,7 @@ describe('block', () => {
author: { author: {
name: 'Blocked User', name: 'Blocked User',
id: 'u2', id: 'u2',
} },
}, },
], ],
}, },
@ -219,16 +239,56 @@ describe('block', () => {
it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed) it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed)
describe('but if the current user blocks the other user', () => { describe('but if the current user blocks the other user', () => {
beforeEach(async () => { }) beforeEach(async () => {
await currentUser.relateTo(blockedUser, 'blocked')
})
it.todo("the blocked user's post won't show up in the newsfeed of the current user") it("the blocked user's post won't show up in the newsfeed of the current user", async () => {
const { query } = createTestClient(server)
await expect(query({ query: postQuery })).resolves.toEqual(
expect.objectContaining({
data: {
Post: [
{
id: 'p12',
title: 'A post written by the current user',
author: { name: 'Current User', id: 'u1' },
},
],
},
}),
)
})
}) })
}) })
describe('from the perspective of the blocked user', () => { describe('from the perspective of the blocked user', () => {
beforeEach(async () => {
authenticatedUser = await blockedUser.toJson()
})
it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed) it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed)
describe('but if the current user blocks the other user', () => { describe('but if the current user blocks the other user', () => {
it.todo("the current user's post won't show up in the newsfeed of the blocked user") beforeEach(async () => {
await currentUser.relateTo(blockedUser, 'blocked')
})
it("the current user's post won't show up in the newsfeed of the blocked user", async () => {
const { query } = createTestClient(server)
await expect(query({ query: postQuery })).resolves.toEqual(
expect.objectContaining({
data: {
Post: [
{
id: 'p23',
title: 'A post written by the blocked user',
author: { name: 'Blocked User', id: 'u2' },
},
],
},
}),
)
})
}) })
}) })
}) })

View File

@ -3,7 +3,7 @@ import helmet from 'helmet'
import { ApolloServer } from 'apollo-server-express' import { ApolloServer } from 'apollo-server-express'
import CONFIG, { requiredConfigs } from './config' import CONFIG, { requiredConfigs } from './config'
import middleware from './middleware' import middleware from './middleware'
import { getDriver } from './bootstrap/neo4j' import { neode as getNeode, getDriver } from './bootstrap/neo4j'
import decode from './jwt/decode' import decode from './jwt/decode'
import schema from './schema' import schema from './schema'
@ -16,6 +16,7 @@ Object.entries(requiredConfigs).map(entry => {
}) })
const driver = getDriver() const driver = getDriver()
const neode = getNeode()
const createServer = options => { const createServer = options => {
const defaults = { const defaults = {
@ -23,6 +24,7 @@ const createServer = options => {
const user = await decode(driver, req.headers.authorization) const user = await decode(driver, req.headers.authorization)
return { return {
driver, driver,
neode,
user, user,
req, req,
cypherParams: { cypherParams: {