diff --git a/backend/src/index.js b/backend/src/index.js index 0eb4f51b6..59718dad1 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,10 +1,11 @@ import createServer from './server' import CONFIG from './config' -const { app, server, httpServer } = createServer() +const { server, httpServer } = createServer() const url = new URL(CONFIG.GRAPHQL_URI) httpServer.listen({ port: url.port }, () => { /* eslint-disable-next-line no-console */ console.log(`🚀 Server ready at http://localhost:${url.port}${server.graphqlPath}`) + /* eslint-disable-next-line no-console */ console.log(`🚀 Subscriptions ready at ws://localhost:${url.port}${server.subscriptionsPath}`) }) diff --git a/backend/src/middleware/notifications/notificationsMiddleware.js b/backend/src/middleware/notifications/notificationsMiddleware.js index d20873ceb..87818c5d7 100644 --- a/backend/src/middleware/notifications/notificationsMiddleware.js +++ b/backend/src/middleware/notifications/notificationsMiddleware.js @@ -1,9 +1,10 @@ import extractMentionedUsers from './mentions/extractMentionedUsers' import { validateNotifyUsers } from '../validation/validationMiddleware' -import { PubSub } from 'apollo-server' - -const pubsub = new PubSub() -const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED' +import { + pubsub, + NOTIFICATION_ADDED, + transformReturnType, +} from '../../schema/resolvers/notifications' const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => { const idsOfUsers = extractMentionedUsers(args.content) @@ -56,6 +57,7 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => { WHERE user.id in $idsOfUsers AND NOT (user)-[:BLOCKED]-(author) MERGE (post)-[notification:NOTIFIED {reason: $reason}]->(user) + WITH notification, post AS resource, user ` break } @@ -67,6 +69,7 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => { AND NOT (user)-[:BLOCKED]-(author) AND NOT (user)-[:BLOCKED]-(postAuthor) MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(user) + WITH notification, comment AS resource, user ` break } @@ -78,12 +81,16 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => { WHEN notification.createdAt IS NULL THEN notification END ).createdAt = toString(datetime()) SET notification.updatedAt = toString(datetime()) - RETURN notification + RETURN notification, resource, user, labels(resource)[0] AS type ` const session = context.driver.session() const writeTxResultPromise = session.writeTransaction(async transaction => { - const notificationTransactionResponse = await transaction.run(mentionedCypher, { id, idsOfUsers, reason }) - return notificationTransactionResponse.records.map(record => record.get('notification').properties) + const notificationTransactionResponse = await transaction.run(mentionedCypher, { + id, + idsOfUsers, + reason, + }) + return notificationTransactionResponse.records.map(transformReturnType) }) try { const [notification] = await writeTxResultPromise diff --git a/backend/src/schema/resolvers/notifications.js b/backend/src/schema/resolvers/notifications.js index f92292bfc..c8d36b034 100644 --- a/backend/src/schema/resolvers/notifications.js +++ b/backend/src/schema/resolvers/notifications.js @@ -1,16 +1,14 @@ import log from './helpers/databaseLogger' import { PubSub } from 'apollo-server' +import { withFilter } from 'graphql-subscriptions' -const pubsub = new PubSub() -const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED' - -const resourceTypes = ['Post', 'Comment'] - -const transformReturnType = record => { +export const pubsub = new PubSub() +export const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED' +export const transformReturnType = record => { return { ...record.get('notification').properties, from: { - __typename: record.get('resource').labels.find(l => resourceTypes.includes(l)), + __typename: record.get('type'), ...record.get('resource').properties, }, to: { @@ -22,7 +20,12 @@ const transformReturnType = record => { export default { Subscription: { notificationAdded: { - subscribe: () => pubsub.asyncIterator([NOTIFICATION_ADDED]), + subscribe: withFilter( + () => pubsub.asyncIterator(NOTIFICATION_ADDED), + (payload, variables) => { + return payload.notificationAdded.to.id === variables.userId + }, + ), }, }, Query: { @@ -90,7 +93,7 @@ export default { ` MATCH (resource {id: $resourceId})-[notification:NOTIFIED {read: FALSE}]->(user:User {id:$id}) SET notification.read = TRUE - RETURN resource, notification, user + RETURN resource, notification, user, labels(resource)[0] AS type `, { resourceId: args.id, id: currentUser.id }, ) diff --git a/backend/src/schema/resolvers/posts.js b/backend/src/schema/resolvers/posts.js index 11f6eebc3..4cb787e2f 100644 --- a/backend/src/schema/resolvers/posts.js +++ b/backend/src/schema/resolvers/posts.js @@ -1,16 +1,14 @@ import uuid from 'uuid/v4' import { neo4jgraphql } from 'neo4j-graphql-js' import { isEmpty } from 'lodash' -import { UserInputError } from 'apollo-server' +import { UserInputError, PubSub } from 'apollo-server' import fileUpload from './fileUpload' import Resolver from './helpers/Resolver' import { filterForMutedUsers } from './helpers/filterForMutedUsers' -import { PubSub } from 'apollo-server' const pubsub = new PubSub() const POST_ADDED = 'POST_ADDED' - const maintainPinnedPosts = params => { const pinnedPostFilter = { pinned: true } if (isEmpty(params.filter)) { diff --git a/backend/src/schema/types/type/NOTIFIED.gql b/backend/src/schema/types/type/NOTIFIED.gql index af91460f7..558041b6a 100644 --- a/backend/src/schema/types/type/NOTIFIED.gql +++ b/backend/src/schema/types/type/NOTIFIED.gql @@ -30,3 +30,7 @@ type Query { type Mutation { markAsRead(id: ID!): NOTIFIED } + +type Subscription { + notificationAdded(userId: ID!): NOTIFIED +} \ No newline at end of file diff --git a/backend/src/schema/types/type/Post.gql b/backend/src/schema/types/type/Post.gql index 71fcb9605..484ad937e 100644 --- a/backend/src/schema/types/type/Post.gql +++ b/backend/src/schema/types/type/Post.gql @@ -245,3 +245,7 @@ type Query { """ ) } + +type Subscription { + postAdded: Post +} diff --git a/backend/src/schema/types/type/Subscription.gql b/backend/src/schema/types/type/Subscription.gql deleted file mode 100644 index a2f8b11b9..000000000 --- a/backend/src/schema/types/type/Subscription.gql +++ /dev/null @@ -1,4 +0,0 @@ -type Subscription { - postAdded: Post - notificationAdded: NOTIFIED -} \ No newline at end of file diff --git a/backend/src/server.js b/backend/src/server.js index d20fa5e63..b7e751bae 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -3,7 +3,6 @@ import http from 'http' import helmet from 'helmet' import { ApolloServer } from 'apollo-server-express' - import CONFIG from './config' import middleware from './middleware' import { getNeode, getDriver } from './db/neo4j' @@ -11,23 +10,22 @@ import decode from './jwt/decode' import schema from './schema' import webfinger from './activitypub/routes/webfinger' - const driver = getDriver() const neode = getNeode() -const getContext = async (req) => { - const user = await decode(driver, req.headers.authorization) - return { - driver, - neode, - user, - req, - cypherParams: { - currentUserId: user ? user.id : null, - }, - } +const getContext = async req => { + const user = await decode(driver, req.headers.authorization) + return { + driver, + neode, + user, + req, + cypherParams: { + currentUserId: user ? user.id : null, + }, + } } -export const context = async (options) => { +export const context = async options => { const { connection, req } = options if (connection) { return connection.context @@ -63,9 +61,8 @@ const createServer = options => { app.use('/.well-known/', webfinger()) app.use(express.static('public')) server.applyMiddleware({ app, path: '/' }) - const httpServer = http.createServer(app); - server.installSubscriptionHandlers(httpServer); - + const httpServer = http.createServer(app) + server.installSubscriptionHandlers(httpServer) return { server, httpServer, app } } diff --git a/webapp/components/NotificationMenu/NotificationMenu.vue b/webapp/components/NotificationMenu/NotificationMenu.vue index b18203b45..d00ab2837 100644 --- a/webapp/components/NotificationMenu/NotificationMenu.vue +++ b/webapp/components/NotificationMenu/NotificationMenu.vue @@ -22,13 +22,12 @@