diff --git a/backend/src/graphql/messages.ts b/backend/src/graphql/messages.ts index 08afe64f4..34c7d559b 100644 --- a/backend/src/graphql/messages.ts +++ b/backend/src/graphql/messages.ts @@ -32,3 +32,11 @@ export const messageQuery = () => { } ` } + +export const markMessagesAsSeen = () => { + return gql` + mutation ($messageIds: [String!]) { + MarkMessagesAsSeen(messageIds: $messageIds) + } + ` +} diff --git a/backend/src/middleware/permissionsMiddleware.ts b/backend/src/middleware/permissionsMiddleware.ts index 81ba93e3c..c07098a3c 100644 --- a/backend/src/middleware/permissionsMiddleware.ts +++ b/backend/src/middleware/permissionsMiddleware.ts @@ -463,6 +463,7 @@ export default shield( saveCategorySettings: isAuthenticated, CreateRoom: isAuthenticated, CreateMessage: isAuthenticated, + MarkMessagesAsSeen: isAuthenticated, }, User: { email: or(isMyOwn, isAdmin), diff --git a/backend/src/schema/resolvers/messages.spec.ts b/backend/src/schema/resolvers/messages.spec.ts index 8001e8bc5..59512e323 100644 --- a/backend/src/schema/resolvers/messages.spec.ts +++ b/backend/src/schema/resolvers/messages.spec.ts @@ -2,7 +2,7 @@ import { createTestClient } from 'apollo-server-testing' import Factory, { cleanDatabase } from '../../db/factories' import { getNeode, getDriver } from '../../db/neo4j' import { createRoomMutation } from '../../graphql/rooms' -import { createMessageMutation, messageQuery } from '../../graphql/messages' +import { createMessageMutation, messageQuery, markMessagesAsSeen } from '../../graphql/messages' import createServer from '../../server' const driver = getDriver() @@ -323,4 +323,74 @@ describe('Message', () => { }) }) }) + + describe('marks massges as seen', () => { + describe('unauthenticated', () => { + beforeAll(() => { + authenticatedUser = null + }) + + it('throws authorization error', async () => { + await expect( + mutate({ + mutation: markMessagesAsSeen(), + variables: { + messageIds: ['some-id'], + }, + }), + ).resolves.toMatchObject({ + errors: [{ message: 'Not Authorized!' }], + }) + }) + }) + + describe('authenticated', () => { + const messageIds: string[] = [] + beforeAll(async () => { + authenticatedUser = await otherChattingUser.toJson() + const msgs = await query({ + query: messageQuery(), + variables: { + roomId, + }, + }) + msgs.data.Message.forEach((m) => messageIds.push(m.id)) + }) + + it('returns true', async () => { + await expect( + mutate({ + mutation: markMessagesAsSeen(), + variables: { + messageIds, + }, + }), + ).resolves.toMatchObject({ + errors: undefined, + data: { + MarkMessagesAsSeen: true, + }, + }) + }) + + it('has seen prop set to true', async () => { + await expect( + query({ + query: messageQuery(), + variables: { + roomId, + }, + }), + ).resolves.toMatchObject({ + data: { + Message: [ + expect.objectContaining({ seen: true }), + expect.objectContaining({ seen: true }), + expect.objectContaining({ seen: true }), + ], + }, + }) + }) + }) + }) }) diff --git a/backend/src/schema/resolvers/messages.ts b/backend/src/schema/resolvers/messages.ts index 7a2ba418c..82024c310 100644 --- a/backend/src/schema/resolvers/messages.ts +++ b/backend/src/schema/resolvers/messages.ts @@ -89,6 +89,29 @@ export default { session.close() } }, + MarkMessagesAsSeen: async (_parent, params, context, _resolveInfo) => { + const { messageIds } = params + const session = context.driver.session() + const writeTxResultPromise = session.writeTransaction(async (transaction) => { + const setSeenCypher = ` + MATCH (m:Message) WHERE m.id IN $messageIds + SET m.seen = true + RETURN m { .* } + ` + const setSeenTxResponse = await transaction.run(setSeenCypher, { + messageIds, + }) + const messages = await setSeenTxResponse.records.map((record) => record.get('m')) + return messages + }) + try { + await writeTxResultPromise + // send subscription to author to updated the messages + return true + } finally { + session.close() + } + }, }, Message: { ...Resolver('Message', { diff --git a/backend/src/schema/types/type/Message.gql b/backend/src/schema/types/type/Message.gql index a22828a7e..8b9263336 100644 --- a/backend/src/schema/types/type/Message.gql +++ b/backend/src/schema/types/type/Message.gql @@ -27,6 +27,8 @@ type Mutation { roomId: ID! content: String! ): Message + + MarkMessagesAsSeen(messageIds: [String!]): Boolean } type Query {