diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 336f816f5..6cfd38575 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -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 - }, - }, } diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index 767cde24b..74561c5fe 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -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) } diff --git a/backend/src/schema/resolvers/users/blockedUsers.spec.js b/backend/src/schema/resolvers/users/blockedUsers.spec.js index e20774b0a..887c34494 100644 --- a/backend/src/schema/resolvers/users/blockedUsers.spec.js +++ b/backend/src/schema/resolvers/users/blockedUsers.spec.js @@ -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' }, + }, + ], + }, + }), + ) + }) }) }) }) diff --git a/backend/src/server.js b/backend/src/server.js index 5f13daeea..752cd96fb 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -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: {