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 { neo4jgraphql } from 'neo4j-graphql-js'
import fileUpload from './fileUpload'
import { getBlockedUsers, getBlockedByUsers } from './users.js'
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: {
UpdatePost: async (object, params, context, resolveInfo) => {
const { categoryIds } = params
@ -112,39 +161,4 @@ export default {
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,21 +6,41 @@ import Resolver from './helpers/Resolver'
const instance = neode()
export const getBlockedUsers = async context => {
const { neode } = context
const userModel = neode.model('User')
let blockedUsers = neode
.query()
.match('user', userModel)
.where('user.id', context.user.id)
.relationship(userModel.relationships().get('blocked'))
.to('blocked', userModel)
.return('blocked')
blockedUsers = await blockedUsers.execute()
blockedUsers = blockedUsers.records.map(r => r.get('blocked').properties)
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 {
const userModel = instance.model('User')
let blockedUsers = instance
.query()
.match('user', userModel)
.where('user.id', context.user.id)
.relationship(userModel.relationships().get('blocked'))
.to('blocked', userModel)
.return('blocked')
blockedUsers = await blockedUsers.execute()
blockedUsers = blockedUsers.records.map(r => r.get('blocked').properties)
return blockedUsers
return getBlockedUsers(context)
} catch (e) {
throw new UserInputError(e.message)
}

View File

@ -20,6 +20,7 @@ beforeEach(() => {
return {
user: authenticatedUser,
driver,
neode: instance,
cypherParams: {
currentUserId: authenticatedUser ? authenticatedUser.id : null,
},
@ -153,7 +154,15 @@ describe('block', () => {
it('unfollows the user', async () => {
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)
await expect(query({ query: queryUser })).resolves.toEqual(
expect.objectContaining({
@ -182,53 +191,104 @@ describe('block', () => {
})
await Promise.all([
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 { 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',
}
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',
},
{
id: 'p23',
title: 'A post written by the blocked user',
author: {
name: 'Blocked User',
id: 'u2',
}
},
{
id: 'p23',
title: 'A post written by the blocked user',
author: {
name: 'Blocked User',
id: 'u2',
},
],
},
}),
)
}
},
],
},
}),
)
}
describe('from the perspective of the current user', () => {
it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed)
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', () => {
beforeEach(async () => {
authenticatedUser = await blockedUser.toJson()
})
it('both posts are in the newsfeed', bothPostsAreInTheNewsfeed)
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 CONFIG, { requiredConfigs } from './config'
import middleware from './middleware'
import { getDriver } from './bootstrap/neo4j'
import { neode as getNeode, getDriver } from './bootstrap/neo4j'
import decode from './jwt/decode'
import schema from './schema'
@ -16,6 +16,7 @@ Object.entries(requiredConfigs).map(entry => {
})
const driver = getDriver()
const neode = getNeode()
const createServer = options => {
const defaults = {
@ -23,6 +24,7 @@ const createServer = options => {
const user = await decode(driver, req.headers.authorization)
return {
driver,
neode,
user,
req,
cypherParams: {