Wrote and tested the mention of a blocked user on a post of a blocker

Co-Authored-By: mattwr18 <mattwr18@gmail.com>
This commit is contained in:
Wolfgang Huß 2019-08-16 18:14:04 +02:00
parent efb5c75c24
commit 0b9a58e317
3 changed files with 109 additions and 99 deletions

View File

@ -6,16 +6,27 @@ const notifyMentions = async (label, id, idsOfMentionedUsers, context) => {
const session = context.driver.session() const session = context.driver.session()
const createdAt = new Date().toISOString() const createdAt = new Date().toISOString()
const cypher = ` let cypher
MATCH (source) if (label === 'Post') {
WHERE source.id = $id AND $label IN LABELS(source) cypher = `
MATCH (source)<-[:WROTE]-(author: User) MATCH (post: Post { id: $id })<-[:WROTE]-(author: User)
MATCH (user: User) MATCH (user: User)
WHERE user.id in $idsOfMentionedUsers WHERE user.id in $idsOfMentionedUsers
AND NOT (user)<-[:BLOCKED]-(author) AND NOT (user)<-[:BLOCKED]-(author)
CREATE (notification: Notification {id: apoc.create.uuid(), read: false, createdAt: $createdAt }) CREATE (notification: Notification {id: apoc.create.uuid(), read: false, createdAt: $createdAt })
MERGE (source)-[:NOTIFIED]->(notification)-[:NOTIFIED]->(user) MERGE (post)-[:NOTIFIED]->(notification)-[:NOTIFIED]->(user)
` `
} else {
cypher = `
MATCH (postAuthor: User)-[:WROTE]->(post: Post)<-[:COMMENTS]-(comment: Comment { id: $id })<-[:WROTE]-(author: User)
MATCH (user: User)
WHERE user.id in $idsOfMentionedUsers
AND NOT (user)<-[:BLOCKED]-(author)
AND NOT (user)<-[:BLOCKED]-(postAuthor)
CREATE (notification: Notification {id: apoc.create.uuid(), read: false, createdAt: $createdAt })
MERGE (comment)-[:NOTIFIED]->(notification)-[:NOTIFIED]->(user)
`
}
// "author" of comment, blocked Peter: Jenny // "author" of comment, blocked Peter: Jenny
// "user" mentioned on post by Jenny: Peter // "user" mentioned on post by Jenny: Peter
// owner of post: Bob // owner of post: Bob
@ -58,12 +69,9 @@ const updateHashtagsOfPost = async (postId, hashtags, context) => {
} }
const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => { const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => {
// extract user ids before xss-middleware removes classes via the following "resolve" call
const idsOfMentionedUsers = extractMentionedUsers(args.content) const idsOfMentionedUsers = extractMentionedUsers(args.content)
// extract tag (hashtag) ids before xss-middleware removes classes via the following "resolve" call
const hashtags = extractHashtags(args.content) const hashtags = extractHashtags(args.content)
// removes classes from the content
const post = await resolve(root, args, context, resolveInfo) const post = await resolve(root, args, context, resolveInfo)
await notifyMentions('Post', post.id, idsOfMentionedUsers, context) await notifyMentions('Post', post.id, idsOfMentionedUsers, context)
@ -73,10 +81,7 @@ const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo
} }
const handleContentDataOfComment = async (resolve, root, args, context, resolveInfo) => { const handleContentDataOfComment = async (resolve, root, args, context, resolveInfo) => {
// extract user ids before xss-middleware removes classes via the following "resolve" call
const idsOfMentionedUsers = extractMentionedUsers(args.content) const idsOfMentionedUsers = extractMentionedUsers(args.content)
// removes classes from the content
const comment = await resolve(root, args, context, resolveInfo) const comment = await resolve(root, args, context, resolveInfo)
await notifyMentions('Comment', comment.id, idsOfMentionedUsers, context) await notifyMentions('Comment', comment.id, idsOfMentionedUsers, context)
@ -89,6 +94,6 @@ export default {
CreatePost: handleContentDataOfPost, CreatePost: handleContentDataOfPost,
UpdatePost: handleContentDataOfPost, UpdatePost: handleContentDataOfPost,
CreateComment: handleContentDataOfComment, CreateComment: handleContentDataOfComment,
// UpdateComment: handleContentDataOfComment, UpdateComment: handleContentDataOfComment,
}, },
} }

View File

@ -1,14 +1,7 @@
import { import { gql } from '../../jest/helpers'
gql
} from '../../jest/helpers'
import Factory from '../../seed/factories' import Factory from '../../seed/factories'
import { import { createTestClient } from 'apollo-server-testing'
createTestClient import { neode, getDriver } from '../../bootstrap/neo4j'
} from 'apollo-server-testing'
import {
neode,
getDriver
} from '../../bootstrap/neo4j'
import createServer from '../../server' import createServer from '../../server'
const factory = Factory() const factory = Factory()
@ -59,6 +52,9 @@ describe('notifications', () => {
post { post {
content content
} }
comment {
content
}
} }
} }
} }
@ -100,7 +96,7 @@ describe('notifications', () => {
variables: { variables: {
id: 'p47', id: 'p47',
title, title,
content content,
}, },
}) })
authenticatedUser = await user.toJson() authenticatedUser = await user.toJson()
@ -113,24 +109,25 @@ describe('notifications', () => {
const expected = expect.objectContaining({ const expected = expect.objectContaining({
data: { data: {
currentUser: { currentUser: {
notifications: [{ notifications: [
{
read: false, read: false,
post: { post: {
content: expectedContent content: expectedContent,
} },
}] comment: null,
},
],
}, },
}, },
}) })
const { const { query } = createTestClient(server)
query
} = createTestClient(server)
await expect( await expect(
query({ query({
query: notificationQuery, query: notificationQuery,
variables: { variables: {
read: false read: false,
} },
}), }),
).resolves.toEqual(expected) ).resolves.toEqual(expected)
}) })
@ -179,17 +176,20 @@ describe('notifications', () => {
const expected = expect.objectContaining({ const expected = expect.objectContaining({
data: { data: {
currentUser: { currentUser: {
notifications: [{ notifications: [
{
read: false, read: false,
post: { post: {
content: expectedContent content: expectedContent,
} },
comment: null,
}, },
{ {
read: false, read: false,
post: { post: {
content: expectedContent content: expectedContent,
} },
comment: null,
}, },
], ],
}, },
@ -199,8 +199,8 @@ describe('notifications', () => {
query({ query({
query: notificationQuery, query: notificationQuery,
variables: { variables: {
read: false read: false,
} },
}), }),
).resolves.toEqual(expected) ).resolves.toEqual(expected)
}) })
@ -216,51 +216,50 @@ describe('notifications', () => {
const expected = expect.objectContaining({ const expected = expect.objectContaining({
data: { data: {
currentUser: { currentUser: {
notifications: [] notifications: [],
} },
}, },
}) })
const { const { query } = createTestClient(server)
query
} = createTestClient(server)
await expect( await expect(
query({ query({
query: notificationQuery, query: notificationQuery,
variables: { variables: {
read: false read: false,
} },
}), }),
).resolves.toEqual(expected) ).resolves.toEqual(expected)
}) })
}) })
describe('but the author of the post blocked a user I mention in a comment', () => { describe('but the author of the post blocked me and a mentioner mentions me in a comment', () => {
const createCommentOnPostAction = async () => { const createCommentOnPostAction = async () => {
await createPostAction() await createPostAction()
const createCommentMutation = gql` const createCommentMutation = gql`
mutation($id: ID, $title: String!, $content: String!) { mutation($id: ID, $postId: ID!, $commentContent: String!) {
CreateComment(id: $id, postId: $postId, content: $commentContent) { CreateComment(id: $id, postId: $postId, content: $commentContent) {
id id
content content
} }
} }
` `
// authenticatedUser = await postAuthor.toJson() authenticatedUser = await commentMentioner.toJson()
// authenticatedUser = await user.toJson()
await mutate({ await mutate({
mutation: createCommentMutation, mutation: createCommentMutation,
variables: { variables: {
id: 'c47', id: 'c47',
postId: 'p47', postId: 'p47',
commentContent: 'One mention of me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">.' commentContent:
'One mention of me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">.',
}, },
}) })
authenticatedUser = await user.toJson()
} }
let mentioner let commentMentioner
beforeEach(async () => { beforeEach(async () => {
await postAuthor.relateTo(user, 'blocked') await postAuthor.relateTo(user, 'blocked')
mentioner = await instance.create('User', { commentMentioner = await instance.create('User', {
id: 'mentioner', id: 'mentioner',
name: 'Mr Mentioner', name: 'Mr Mentioner',
slug: 'mr-mentioner', slug: 'mr-mentioner',
@ -270,23 +269,21 @@ describe('notifications', () => {
}) })
it('sends no notification', async () => { it('sends no notification', async () => {
await createPostAction() await createCommentOnPostAction()
const expected = expect.objectContaining({ const expected = expect.objectContaining({
data: { data: {
currentUser: { currentUser: {
notifications: [] notifications: [],
} },
}, },
}) })
const { const { query } = createTestClient(server)
query
} = createTestClient(server)
await expect( await expect(
query({ query({
query: notificationQuery, query: notificationQuery,
variables: { variables: {
read: false read: false,
} },
}), }),
).resolves.toEqual(expected) ).resolves.toEqual(expected)
}) })
@ -342,26 +339,29 @@ describe('Hashtags', () => {
}) })
it('both Hashtags are created with the "id" set to their "name"', async () => { it('both Hashtags are created with the "id" set to their "name"', async () => {
const expected = [{ const expected = [
{
id: 'Democracy', id: 'Democracy',
name: 'Democracy' name: 'Democracy',
}, },
{ {
id: 'Liberty', id: 'Liberty',
name: 'Liberty' name: 'Liberty',
}, },
] ]
await expect( await expect(
query({ query({
query: postWithHastagsQuery, query: postWithHastagsQuery,
variables: postWithHastagsVariables variables: postWithHastagsVariables,
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
data: { data: {
Post: [{ Post: [
{
tags: expect.arrayContaining(expected), tags: expect.arrayContaining(expected),
}, ], },
],
}, },
}), }),
) )
@ -391,26 +391,29 @@ describe('Hashtags', () => {
}, },
}) })
const expected = [{ const expected = [
{
id: 'Elections', id: 'Elections',
name: 'Elections' name: 'Elections',
}, },
{ {
id: 'Liberty', id: 'Liberty',
name: 'Liberty' name: 'Liberty',
}, },
] ]
await expect( await expect(
query({ query({
query: postWithHastagsQuery, query: postWithHastagsQuery,
variables: postWithHastagsVariables variables: postWithHastagsVariables,
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
data: { data: {
Post: [{ Post: [
tags: expect.arrayContaining(expected) {
}], tags: expect.arrayContaining(expected),
},
],
}, },
}), }),
) )

View File

@ -88,11 +88,9 @@
{{ $t('login.hello') }} {{ $t('login.hello') }}
<b>{{ userName }}</b> <b>{{ userName }}</b>
<template v-if="user.role !== 'user'"> <template v-if="user.role !== 'user'">
<ds-text <ds-text color="softer" size="small" style="margin-bottom: 0">
color="softer" {{ user.role | camelCase }}
size="small" </ds-text>
style="margin-bottom: 0"
>{{ user.role | camelCase }}</ds-text>
</template> </template>
<hr /> <hr />
<ds-menu :routes="routes" :matcher="matcher"> <ds-menu :routes="routes" :matcher="matcher">
@ -131,10 +129,14 @@
<div id="footer" class="ds-footer"> <div id="footer" class="ds-footer">
<a href="https://human-connection.org" target="_blank" v-html="$t('site.made')"></a> <a href="https://human-connection.org" target="_blank" v-html="$t('site.made')"></a>
&nbsp;-&nbsp; &nbsp;-&nbsp;
<nuxt-link to="/imprint">{{ $t('site.imprint') }}</nuxt-link>&nbsp;&nbsp; <nuxt-link to="/imprint">{{ $t('site.imprint') }}</nuxt-link>
<nuxt-link to="/terms-and-conditions">{{ $t('site.termsAndConditions') }}</nuxt-link>&nbsp;&nbsp; &nbsp;&nbsp;
<nuxt-link to="/code-of-conduct">{{ $t('site.code-of-conduct') }}</nuxt-link>&nbsp;&nbsp; <nuxt-link to="/terms-and-conditions">{{ $t('site.termsAndConditions') }}</nuxt-link>
<nuxt-link to="/data-privacy">{{ $t('site.data-privacy') }}</nuxt-link>&nbsp;&nbsp; &nbsp;&nbsp;
<nuxt-link to="/code-of-conduct">{{ $t('site.code-of-conduct') }}</nuxt-link>
&nbsp;&nbsp;
<nuxt-link to="/data-privacy">{{ $t('site.data-privacy') }}</nuxt-link>
&nbsp;&nbsp;
<nuxt-link to="/changelog">{{ $t('site.changelog') }}</nuxt-link> <nuxt-link to="/changelog">{{ $t('site.changelog') }}</nuxt-link>
</div> </div>
<div id="overlay" /> <div id="overlay" />