diff --git a/backend/src/middleware/handleHtmlContent/handleContentData.js b/backend/src/middleware/handleHtmlContent/handleContentData.js index 3ab95b471..c492b0c3e 100644 --- a/backend/src/middleware/handleHtmlContent/handleContentData.js +++ b/backend/src/middleware/handleHtmlContent/handleContentData.js @@ -7,7 +7,7 @@ const notifyMentionOfPost = async (postId, idsOfMentionedUsers, context) => { const session = context.driver.session() const createdAt = new Date().toISOString() const cypher = ` - MATCH (u: User) WHERE u.id in $idsOfMentionedUsers + MATCH (u: User) WHERE u.id IN $idsOfMentionedUsers MATCH (p: Post) WHERE p.id = $postId CREATE (n: Notification { id: apoc.create.uuid(), read: false, createdAt: $createdAt }) MERGE (n)-[:NOTIFIED]->(u) diff --git a/backend/src/schema/resolvers/notifications.spec.js b/backend/src/schema/resolvers/notifications.spec.js index 3876a4be3..d7205bc1f 100644 --- a/backend/src/schema/resolvers/notifications.spec.js +++ b/backend/src/schema/resolvers/notifications.spec.js @@ -1,6 +1,11 @@ -import { GraphQLClient } from 'graphql-request' +import { + GraphQLClient +} from 'graphql-request' import Factory from '../../seed/factories' -import { host, login } from '../../jest/helpers' +import { + host, + login +} from '../../jest/helpers' const factory = Factory() let client @@ -39,8 +44,13 @@ describe('currentUser { notifications }', () => { describe('authenticated', () => { let headers beforeEach(async () => { - headers = await login({ email: 'test@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) + headers = await login({ + email: 'test@example.org', + password: '1234' + }) + client = new GraphQLClient(host, { + headers + }) }) describe('given some notifications', () => { @@ -52,19 +62,46 @@ describe('currentUser { notifications }', () => { } await Promise.all([ factory.create('User', neighborParams), - factory.create('Notification', { id: 'not-for-you' }), - factory.create('Notification', { id: 'already-seen', read: true }), + factory.create('Notification', { + id: 'not-for-you' + }), + factory.create('Notification', { + id: 'already-seen', + read: true + }), ]) - await factory.create('Notification', { id: 'unseen' }) + await factory.create('Notification', { + id: 'unseen' + }) await factory.authenticateAs(neighborParams) - await factory.create('Post', { id: 'p1' }) + await factory.create('Post', { + id: 'p1' + }) await Promise.all([ - factory.relate('Notification', 'User', { from: 'not-for-you', to: 'neighbor' }), - factory.relate('Notification', 'Post', { from: 'p1', to: 'not-for-you' }), - factory.relate('Notification', 'User', { from: 'unseen', to: 'you' }), - factory.relate('Notification', 'Post', { from: 'p1', to: 'unseen' }), - factory.relate('Notification', 'User', { from: 'already-seen', to: 'you' }), - factory.relate('Notification', 'Post', { from: 'p1', to: 'already-seen' }), + factory.relate('Notification', 'User', { + from: 'not-for-you', + to: 'neighbor' + }), + factory.relate('Notification', 'Post', { + from: 'p1', + to: 'not-for-you' + }), + factory.relate('Notification', 'User', { + from: 'unseen', + to: 'you' + }), + factory.relate('Notification', 'Post', { + from: 'p1', + to: 'unseen' + }), + factory.relate('Notification', 'User', { + from: 'already-seen', + to: 'you' + }), + factory.relate('Notification', 'Post', { + from: 'p1', + to: 'already-seen' + }), ]) }) @@ -79,11 +116,18 @@ describe('currentUser { notifications }', () => { } } }` - let variables = { read: false } + let variables = { + read: false + } it('returns only unread notifications of current user', async () => { const expected = { currentUser: { - notifications: [{ id: 'unseen', post: { id: 'p1' } }], + notifications: [{ + id: 'unseen', + post: { + id: 'p1' + } + }], }, } await expect(client.request(query, variables)).resolves.toEqual(expected) @@ -104,9 +148,18 @@ describe('currentUser { notifications }', () => { it('returns all notifications of current user', async () => { const expected = { currentUser: { - notifications: [ - { id: 'unseen', post: { id: 'p1' } }, - { id: 'already-seen', post: { id: 'p1' } }, + notifications: [{ + id: 'unseen', + post: { + id: 'p1' + } + }, + { + id: 'already-seen', + post: { + id: 'p1' + } + }, ], }, } @@ -123,7 +176,10 @@ describe('UpdateNotification', () => { id read } }` - const variables = { id: 'to-be-updated', read: true } + const variables = { + id: 'to-be-updated', + read: true + } describe('given a notifications', () => { let headers @@ -136,12 +192,22 @@ describe('UpdateNotification', () => { slug: 'mentioned', } await factory.create('User', mentionedParams) - await factory.create('Notification', { id: 'to-be-updated' }) + await factory.create('Notification', { + id: 'to-be-updated' + }) await factory.authenticateAs(userParams) - await factory.create('Post', { id: 'p1' }) + await factory.create('Post', { + id: 'p1' + }) await Promise.all([ - factory.relate('Notification', 'User', { from: 'to-be-updated', to: 'mentioned-1' }), - factory.relate('Notification', 'Post', { from: 'p1', to: 'to-be-updated' }), + factory.relate('Notification', 'User', { + from: 'to-be-updated', + to: 'mentioned-1' + }), + factory.relate('Notification', 'Post', { + from: 'p1', + to: 'to-be-updated' + }), ]) }) @@ -154,8 +220,13 @@ describe('UpdateNotification', () => { describe('authenticated', () => { beforeEach(async () => { - headers = await login({ email: 'test@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) + headers = await login({ + email: 'test@example.org', + password: '1234' + }) + client = new GraphQLClient(host, { + headers + }) }) it('throws authorization error', async () => { @@ -164,15 +235,25 @@ describe('UpdateNotification', () => { describe('and owner', () => { beforeEach(async () => { - headers = await login({ email: 'mentioned@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) + headers = await login({ + email: 'mentioned@example.org', + password: '1234' + }) + client = new GraphQLClient(host, { + headers + }) }) it('updates notification', async () => { - const expected = { UpdateNotification: { id: 'to-be-updated', read: true } } + const expected = { + UpdateNotification: { + id: 'to-be-updated', + read: true + } + } await expect(client.request(mutation, variables)).resolves.toEqual(expected) }) }) }) }) -}) +}) \ No newline at end of file diff --git a/backend/src/schema/types/schema.gql b/backend/src/schema/types/schema.gql index 40d8239b8..d18644d05 100644 --- a/backend/src/schema/types/schema.gql +++ b/backend/src/schema/types/schema.gql @@ -55,7 +55,7 @@ type Notification { read: Boolean user: User @relation(name: "NOTIFIED", direction: "OUT") post: Post @relation(name: "NOTIFIED", direction: "IN") - comment: Post @relation(name: "NOTIFIED", direction: "IN") + comment: Comment @relation(name: "NOTIFIED", direction: "IN") createdAt: String } diff --git a/backend/src/seed/seed-db.js b/backend/src/seed/seed-db.js index f1c88899f..e0155bb6b 100644 --- a/backend/src/seed/seed-db.js +++ b/backend/src/seed/seed-db.js @@ -45,42 +45,49 @@ import Factory from './factories' f.create('User', { id: 'u1', name: 'Peter Lustig', + slug: 'peter-lustig', role: 'admin', email: 'admin@example.org', }), f.create('User', { id: 'u2', name: 'Bob der Baumeister', + slug: 'bob-der-baumeister', role: 'moderator', email: 'moderator@example.org', }), f.create('User', { id: 'u3', name: 'Jenny Rostock', + slug: 'jenny-rostock', role: 'user', email: 'user@example.org', }), f.create('User', { id: 'u4', - name: 'Tick', + name: 'Huey (Tick)', + slug: 'huey-tick', role: 'user', - email: 'tick@example.org', + email: 'huey@example.org', }), f.create('User', { id: 'u5', - name: 'Trick', + name: 'Dewey (Trick)', + slug: 'dewey-trick', role: 'user', - email: 'trick@example.org', + email: 'dewey@example.org', }), f.create('User', { id: 'u6', - name: 'Track', + name: 'Louie (Track)', + slug: 'louie-track', role: 'user', - email: 'track@example.org', + email: 'louie@example.org', }), f.create('User', { id: 'u7', name: 'Dagobert', + slug: 'dagobert', role: 'user', email: 'dagobert@example.org', }), @@ -100,15 +107,15 @@ import Factory from './factories' password: '1234', }), Factory().authenticateAs({ - email: 'tick@example.org', + email: 'huey@example.org', password: '1234', }), Factory().authenticateAs({ - email: 'trick@example.org', + email: 'dewey@example.org', password: '1234', }), Factory().authenticateAs({ - email: 'track@example.org', + email: 'louie@example.org', password: '1234', }), ]) diff --git a/webapp/components/notifications/Notification/index.vue b/webapp/components/notifications/Notification/index.vue index 5f14632e3..336e6b332 100644 --- a/webapp/components/notifications/Notification/index.vue +++ b/webapp/components/notifications/Notification/index.vue @@ -2,11 +2,9 @@ - + - - {{ $t('notifications.menu.mentioned') }} - + {{ $t('notifications.menu.mentioned') }} diff --git a/webapp/components/notifications/NotificationMenu/index.vue b/webapp/components/notifications/NotificationMenu/index.vue index 20a9a7074..fff718b89 100644 --- a/webapp/components/notifications/NotificationMenu/index.vue +++ b/webapp/components/notifications/NotificationMenu/index.vue @@ -21,26 +21,73 @@ import NotificationList from '../NotificationList' import Dropdown from '~/components/Dropdown' import gql from 'graphql-tag' -const MARK_AS_READ = gql(` -mutation($id: ID!, $read: Boolean!) { - UpdateNotification(id: $id, read: $read) { - id - read +const MARK_AS_READ = gql` + mutation($id: ID!, $read: Boolean!) { + UpdateNotification(id: $id, read: $read) { + id + read + } } -}`) +` -const NOTIFICATIONS = gql(`{ - currentUser { - id - notifications(read: false, orderBy: createdAt_desc) { - id read createdAt - post { - id createdAt disabled deleted title contentExcerpt slug - author { id slug name disabled deleted } +const NOTIFICATIONS = gql` + { + currentUser { + id + notifications(read: false, orderBy: createdAt_desc) { + id + read + createdAt + post { + id + createdAt + disabled + deleted + title + contentExcerpt + slug + author { + id + slug + name + disabled + deleted + } + } + comment { + id + createdAt + disabled + deleted + contentExcerpt + author { + id + slug + name + disabled + deleted + } + post { + id + createdAt + disabled + deleted + title + contentExcerpt + slug + author { + id + slug + name + disabled + deleted + } + } + } } } } -}`) +` export default { name: 'NotificationMenu', diff --git a/webapp/graphql/UserProfile/User.js b/webapp/graphql/UserProfile/User.js index 897b5b91d..7fae13cd4 100644 --- a/webapp/graphql/UserProfile/User.js +++ b/webapp/graphql/UserProfile/User.js @@ -2,7 +2,7 @@ import gql from 'graphql-tag' export default i18n => { const lang = i18n.locale().toUpperCase() - return gql(` + return gql` query User($id: ID!) { User(id: $id) { id @@ -72,5 +72,5 @@ export default i18n => { } } } - `) + ` }