Wolfgang Huß 8acccc99d0 Implemented a reason in the Notification
Used this for displaying in the mentions menu in frontend.
Rewrite backend test.
2019-08-15 19:29:06 +02:00

124 lines
4.1 KiB
JavaScript

import {
UserInputError
} from 'apollo-server'
import extractMentionedUsers from './notifications/extractMentionedUsers'
import extractHashtags from './hashtags/extractHashtags'
const notifyUsers = async (label, id, idsOfUsers, reason, context) => {
if (!idsOfUsers.length) return
// Done here, because Neode validation is not working.
const reasonsAllowed = ['mentioned_in_post', 'mentioned_in_comment', 'comment_on_your_post']
if (!(reasonsAllowed.includes(reason))) {
throw new UserInputError("Notification reason is not allowed!")
}
const session = context.driver.session()
const createdAt = new Date().toISOString()
const cypher = `
MATCH (source)
WHERE source.id = $id AND $label IN LABELS(source)
MATCH (source)<-[:WROTE]-(author: User)
MATCH (u: User)
WHERE u.id in $idsOfUsers
AND NOT (u)<-[:BLOCKED]-(author)
CREATE (n: Notification { id: apoc.create.uuid(), read: false, reason: $reason, createdAt: $createdAt })
MERGE (source)-[:NOTIFIED]->(n)-[:NOTIFIED]->(u)
`
await session.run(cypher, {
label,
id,
idsOfUsers,
reason,
createdAt,
})
session.close()
}
const updateHashtagsOfPost = async (postId, hashtags, context) => {
if (!hashtags.length) return
const session = context.driver.session()
// We need two Cypher statements, because the 'MATCH' in the 'cypherDeletePreviousRelations' statement
// functions as an 'if'. In case there is no previous relation, the rest of the commands are omitted
// and no new Hashtags and relations will be created.
const cypherDeletePreviousRelations = `
MATCH (p: Post { id: $postId })-[previousRelations: TAGGED]->(t: Tag)
DELETE previousRelations
RETURN p, t
`
const cypherCreateNewTagsAndRelations = `
MATCH (p: Post { id: $postId})
UNWIND $hashtags AS tagName
MERGE (t: Tag { id: tagName, name: tagName, disabled: false, deleted: false })
MERGE (p)-[:TAGGED]->(t)
RETURN p, t
`
await session.run(cypherDeletePreviousRelations, {
postId,
})
await session.run(cypherCreateNewTagsAndRelations, {
postId,
hashtags,
})
session.close()
}
const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => {
// extract user ids before xss-middleware removes classes via the following "resolve" call
const idsOfUsers = extractMentionedUsers(args.content)
// extract tag (hashtag) ids before xss-middleware removes classes via the following "resolve" call
const hashtags = extractHashtags(args.content)
// removes classes from the content
const post = await resolve(root, args, context, resolveInfo)
await notifyUsers('Post', post.id, idsOfUsers, 'mentioned_in_post', context)
await updateHashtagsOfPost(post.id, hashtags, context)
return post
}
const handleContentDataOfComment = async (resolve, root, args, context, resolveInfo) => {
// extract user ids before xss-middleware removes classes via the following "resolve" call
const idsOfUsers = extractMentionedUsers(args.content)
// removes classes from the content
const comment = await resolve(root, args, context, resolveInfo)
await notifyUsers('Comment', comment.id, idsOfUsers, 'mentioned_in_comment', context)
return comment
}
const handleCreateComment = async (resolve, root, args, context, resolveInfo) => {
// removes classes from the content
const comment = await handleContentDataOfComment(resolve, root, args, context, resolveInfo)
const session = context.driver.session()
const cypherFindUser = `
MATCH (user: User)-[:WROTE]->(:Post)<-[:COMMENTS]-(:Comment { id: $commentId })
RETURN user { .id }
`
const result = await session.run(cypherFindUser, {
commentId: comment.id,
})
session.close()
const [userWrotePost] = await result.records.map(record => {
return record.get('user')
})
if (context.user.id !== userWrotePost.id) {
await notifyUsers('Comment', comment.id, [userWrotePost.id], 'comment_on_your_post', context)
}
return comment
}
export default {
Mutation: {
CreatePost: handleContentDataOfPost,
UpdatePost: handleContentDataOfPost,
CreateComment: handleCreateComment,
UpdateComment: handleContentDataOfComment,
},
}