diff --git a/backend/src/middleware/handleHtmlContent/handleContentData.js b/backend/src/middleware/handleHtmlContent/handleContentData.js index ab0456f9a..9b5df87e7 100644 --- a/backend/src/middleware/handleHtmlContent/handleContentData.js +++ b/backend/src/middleware/handleHtmlContent/handleContentData.js @@ -10,12 +10,15 @@ const notifyMentions = async (label, id, idsOfMentionedUsers, context) => { MATCH (source) WHERE source.id = $id AND $label IN LABELS(source) MATCH (source)<-[:WROTE]-(author: User) - MATCH (u: User) - WHERE u.id in $idsOfMentionedUsers - AND NOT (u)<-[:BLOCKED]-(author) - CREATE (n: Notification {id: apoc.create.uuid(), read: false, createdAt: $createdAt }) - MERGE (source)-[:NOTIFIED]->(n)-[:NOTIFIED]->(u) + MATCH (user: User) + WHERE user.id in $idsOfMentionedUsers + AND NOT (user)<-[:BLOCKED]-(author) + CREATE (notification: Notification {id: apoc.create.uuid(), read: false, createdAt: $createdAt }) + MERGE (source)-[:NOTIFIED]->(notification)-[:NOTIFIED]->(user) ` + // "author" of comment, blocked Peter: Jenny + // "user" mentioned on post by Jenny: Peter + // owner of post: Bob await session.run(cypher, { idsOfMentionedUsers, label, @@ -88,4 +91,4 @@ export default { CreateComment: handleContentDataOfComment, // UpdateComment: handleContentDataOfComment, }, -} +} \ No newline at end of file diff --git a/backend/src/middleware/handleHtmlContent/handleContentData.spec.js b/backend/src/middleware/handleHtmlContent/handleContentData.spec.js index 40d8a2481..e9c56863a 100644 --- a/backend/src/middleware/handleHtmlContent/handleContentData.spec.js +++ b/backend/src/middleware/handleHtmlContent/handleContentData.spec.js @@ -1,7 +1,14 @@ -import { gql } from '../../jest/helpers' +import { + gql +} from '../../jest/helpers' import Factory from '../../seed/factories' -import { createTestClient } from 'apollo-server-testing' -import { neode, getDriver } from '../../bootstrap/neo4j' +import { + createTestClient +} from 'apollo-server-testing' +import { + neode, + getDriver +} from '../../bootstrap/neo4j' import createServer from '../../server' const factory = Factory() @@ -44,7 +51,7 @@ afterEach(async () => { }) describe('notifications', () => { - const notificationQuery = gql` + const notificationQuery = gql ` query($read: Boolean) { currentUser { notifications(read: $read, orderBy: createdAt_desc) { @@ -63,12 +70,12 @@ describe('notifications', () => { }) describe('given another user', () => { - let author + let postAuthor beforeEach(async () => { - author = await instance.create('User', { - email: 'author@example.org', + postAuthor = await instance.create('User', { + email: 'post-author@example.org', password: '1234', - id: 'author', + id: 'postAuthor', }) }) @@ -78,7 +85,7 @@ describe('notifications', () => { 'Hey @al-capone how do you do?' const createPostAction = async () => { - const createPostMutation = gql` + const createPostMutation = gql ` mutation($id: ID, $title: String!, $content: String!) { CreatePost(id: $id, title: $title, content: $content) { id @@ -87,10 +94,14 @@ describe('notifications', () => { } } ` - authenticatedUser = await author.toJson() + authenticatedUser = await postAuthor.toJson() await mutate({ mutation: createPostMutation, - variables: { id: 'p47', title, content }, + variables: { + id: 'p47', + title, + content + }, }) authenticatedUser = await user.toJson() } @@ -101,12 +112,26 @@ describe('notifications', () => { 'Hey @al-capone how do you do?' const expected = expect.objectContaining({ data: { - currentUser: { notifications: [{ read: false, post: { content: expectedContent } }] }, + currentUser: { + notifications: [{ + read: false, + post: { + content: expectedContent + } + }] + }, }, }) - const { query } = createTestClient(server) + const { + query + } = createTestClient(server) await expect( - query({ query: notificationQuery, variables: { read: false } }), + query({ + query: notificationQuery, + variables: { + read: false + } + }), ).resolves.toEqual(expected) }) @@ -126,7 +151,7 @@ describe('notifications', () => { @al-capone ` - const updatePostMutation = gql` + const updatePostMutation = gql ` mutation($id: ID!, $title: String!, $content: String!) { UpdatePost(id: $id, content: $content, title: $title) { title @@ -134,7 +159,7 @@ describe('notifications', () => { } } ` - authenticatedUser = await author.toJson() + authenticatedUser = await postAuthor.toJson() await mutate({ mutation: updatePostMutation, variables: { @@ -154,32 +179,115 @@ describe('notifications', () => { const expected = expect.objectContaining({ data: { currentUser: { - notifications: [ - { read: false, post: { content: expectedContent } }, - { read: false, post: { content: expectedContent } }, + notifications: [{ + read: false, + post: { + content: expectedContent + } + }, + { + read: false, + post: { + content: expectedContent + } + }, ], }, }, }) await expect( - query({ query: notificationQuery, variables: { read: false } }), + query({ + query: notificationQuery, + variables: { + read: false + } + }), ).resolves.toEqual(expected) }) }) describe('but the author of the post blocked me', () => { beforeEach(async () => { - await author.relateTo(user, 'blocked') + await postAuthor.relateTo(user, 'blocked') }) it('sends no notification', async () => { await createPostAction() const expected = expect.objectContaining({ - data: { currentUser: { notifications: [] } }, + data: { + currentUser: { + notifications: [] + } + }, }) - const { query } = createTestClient(server) + const { + query + } = createTestClient(server) await expect( - query({ query: notificationQuery, variables: { read: false } }), + query({ + query: notificationQuery, + variables: { + read: false + } + }), + ).resolves.toEqual(expected) + }) + }) + + describe('but the author of the post blocked a user I mention in a comment', () => { + const createCommentOnPostAction = async () => { + await createPostAction() + const createCommentMutation = gql ` + mutation($id: ID, $title: String!, $content: String!) { + CreateComment(id: $id, postId: $postId, content: $commentContent) { + id + content + } + } + ` + // authenticatedUser = await postAuthor.toJson() + // authenticatedUser = await user.toJson() + await mutate({ + mutation: createCommentMutation, + variables: { + id: 'c47', + postId: 'p47', + commentContent: 'One mention of me with .' + }, + }) + } + let mentioner + + beforeEach(async () => { + await postAuthor.relateTo(user, 'blocked') + mentioner = await instance.create('User', { + id: 'mentioner', + name: 'Mr Mentioner', + slug: 'mr-mentioner', + email: 'mentioner@example.org', + password: '1234', + }) + }) + + it('sends no notification', async () => { + await createPostAction() + const expected = expect.objectContaining({ + data: { + currentUser: { + notifications: [] + } + }, + }) + const { + query + } = createTestClient(server) + await expect( + query({ + query: notificationQuery, + variables: { + read: false + } + }), ).resolves.toEqual(expected) }) }) @@ -193,7 +301,7 @@ describe('Hashtags', () => { const postTitle = 'Two Hashtags' const postContent = '

Hey Dude, #Democracy should work equal for everybody!? That seems to be the only way to have equal #Liberty for everyone.

' - const postWithHastagsQuery = gql` + const postWithHastagsQuery = gql ` query($id: ID) { Post(id: $id) { tags { @@ -206,7 +314,7 @@ describe('Hashtags', () => { const postWithHastagsVariables = { id: postId, } - const createPostMutation = gql` + const createPostMutation = gql ` mutation($postId: ID, $postTitle: String!, $postContent: String!) { CreatePost(id: $postId, title: $postTitle, content: $postContent) { id @@ -234,20 +342,26 @@ describe('Hashtags', () => { }) it('both Hashtags are created with the "id" set to their "name"', async () => { - const expected = [ - { id: 'Democracy', name: 'Democracy' }, - { id: 'Liberty', name: 'Liberty' }, + const expected = [{ + id: 'Democracy', + name: 'Democracy' + }, + { + id: 'Liberty', + name: 'Liberty' + }, ] await expect( - query({ query: postWithHastagsQuery, variables: postWithHastagsVariables }), + query({ + query: postWithHastagsQuery, + variables: postWithHastagsVariables + }), ).resolves.toEqual( expect.objectContaining({ data: { - Post: [ - { - tags: expect.arrayContaining(expected), - }, - ], + Post: [{ + tags: expect.arrayContaining(expected), + }, ], }, }), ) @@ -257,7 +371,7 @@ describe('Hashtags', () => { // The already existing Hashtag has no class at this point. const updatedPostContent = '

Hey Dude, #Elections should work equal for everybody!? That seems to be the only way to have equal #Liberty for everyone.

' - const updatePostMutation = gql` + const updatePostMutation = gql ` mutation($postId: ID!, $postTitle: String!, $updatedPostContent: String!) { UpdatePost(id: $postId, title: $postTitle, content: $updatedPostContent) { id @@ -277,16 +391,26 @@ describe('Hashtags', () => { }, }) - const expected = [ - { id: 'Elections', name: 'Elections' }, - { id: 'Liberty', name: 'Liberty' }, + const expected = [{ + id: 'Elections', + name: 'Elections' + }, + { + id: 'Liberty', + name: 'Liberty' + }, ] await expect( - query({ query: postWithHastagsQuery, variables: postWithHastagsVariables }), + query({ + query: postWithHastagsQuery, + variables: postWithHastagsVariables + }), ).resolves.toEqual( expect.objectContaining({ data: { - Post: [{ tags: expect.arrayContaining(expected) }], + Post: [{ + tags: expect.arrayContaining(expected) + }], }, }), ) @@ -294,4 +418,4 @@ describe('Hashtags', () => { }) }) }) -}) +}) \ No newline at end of file diff --git a/webapp/components/notifications/Notification/Notification.vue b/webapp/components/notifications/Notification/Notification.vue index ae1eeddc9..173753fb8 100644 --- a/webapp/components/notifications/Notification/Notification.vue +++ b/webapp/components/notifications/Notification/Notification.vue @@ -3,19 +3,21 @@ + - {{ $t('notifications.menu.mentioned', { resource: post.id ? 'post' : 'comment' }) }} + {{ $t('notifications.menu.mentioned', { resource: resourceType }) }} @@ -26,9 +28,14 @@ class="notifications-card" > - -
- +
{{ post.contentExcerpt | removeHtml }}
+
+ + Comment: + + + {{ comment.contentExcerpt | removeHtml }} +
@@ -50,11 +57,8 @@ export default { }, }, computed: { - excerpt() { - const excerpt = this.post.id ? this.post.contentExcerpt : this.comment.contentExcerpt - return ( - (!this.post.id ? 'Comment: ' : '') + excerpt.replace(/<(?:.|\n)*?>/gm, '').trim() - ) + resourceType() { + return this.post.id ? 'Post' : 'Comment' }, post() { return this.notification.post || {} @@ -62,7 +66,7 @@ export default { comment() { return this.notification.comment || {} }, - postParams() { + params() { return { id: this.post.id || this.comment.post.id, slug: this.post.slug || this.comment.post.slug, diff --git a/webapp/components/notifications/NotificationMenu/spec.js b/webapp/components/notifications/NotificationMenu/NotificationMenu.spec.js similarity index 97% rename from webapp/components/notifications/NotificationMenu/spec.js rename to webapp/components/notifications/NotificationMenu/NotificationMenu.spec.js index 673a85944..b8d988b58 100644 --- a/webapp/components/notifications/NotificationMenu/spec.js +++ b/webapp/components/notifications/NotificationMenu/NotificationMenu.spec.js @@ -1,5 +1,5 @@ import { config, shallowMount, createLocalVue } from '@vue/test-utils' -import NotificationMenu from '.' +import NotificationMenu from './NotificationMenu' import Styleguide from '@human-connection/styleguide' import Filters from '~/plugins/vue-filters' diff --git a/webapp/components/notifications/NotificationMenu/index.vue b/webapp/components/notifications/NotificationMenu/NotificationMenu.vue similarity index 55% rename from webapp/components/notifications/NotificationMenu/index.vue rename to webapp/components/notifications/NotificationMenu/NotificationMenu.vue index 408bce228..c534f2986 100644 --- a/webapp/components/notifications/NotificationMenu/index.vue +++ b/webapp/components/notifications/NotificationMenu/NotificationMenu.vue @@ -17,80 +17,9 @@