mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2026-01-13 16:34:45 +00:00
Refactor notificationsMiddleware
- Use transaction functions - extract validations into validationsMiddleware - break notifyUsers into notifyUsersOfMention/notifyUsersOfComment
This commit is contained in:
parent
132951c525
commit
da150e0b27
@ -1,4 +1,29 @@
|
||||
import extractMentionedUsers from './mentions/extractMentionedUsers'
|
||||
import { validateNotifyUsers } from '../validation/validationMiddleware'
|
||||
|
||||
const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => {
|
||||
const idsOfUsers = extractMentionedUsers(args.content)
|
||||
const post = await resolve(root, args, context, resolveInfo)
|
||||
if (post && idsOfUsers && idsOfUsers.length)
|
||||
await notifyUsersOfMention('Post', post.id, idsOfUsers, 'mentioned_in_post', context)
|
||||
return post
|
||||
}
|
||||
|
||||
const handleCreateComment = async (resolve, root, args, context, resolveInfo) => {
|
||||
const comment = await resolve(root, args, context, resolveInfo)
|
||||
if (comment) return handleContentDataOfComment(resolve, root, args, context, resolveInfo)
|
||||
}
|
||||
|
||||
const handleContentDataOfComment = async (resolve, root, args, context, resolveInfo) => {
|
||||
const { content, id: commentId } = args
|
||||
let idsOfUsers = extractMentionedUsers(content)
|
||||
const [postAuthor] = await postAuthorOfComment(commentId, { context })
|
||||
idsOfUsers = idsOfUsers.filter(id => id !== postAuthor.id)
|
||||
if (idsOfUsers && idsOfUsers.length)
|
||||
await notifyUsersOfMention('Comment', commentId, idsOfUsers, 'mentioned_in_comment', context)
|
||||
if (context.user.id !== postAuthor.id)
|
||||
await notifyUsersOfComment('Comment', commentId, postAuthor.id, 'commented_on_post', context)
|
||||
}
|
||||
|
||||
const postAuthorOfComment = async (commentId, { context }) => {
|
||||
const session = context.driver.session()
|
||||
@ -19,105 +44,74 @@ const postAuthorOfComment = async (commentId, { context }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const notifyUsers = async (label, id, idsOfUsers, reason, context) => {
|
||||
if (!idsOfUsers.length) return
|
||||
|
||||
// Checked here, because it does not go through GraphQL checks at all in this file.
|
||||
const reasonsAllowed = ['mentioned_in_post', 'mentioned_in_comment', 'commented_on_post']
|
||||
if (!reasonsAllowed.includes(reason)) {
|
||||
throw new Error('Notification reason is not allowed!')
|
||||
}
|
||||
if (
|
||||
(label === 'Post' && reason !== 'mentioned_in_post') ||
|
||||
(label === 'Comment' && !['mentioned_in_comment', 'commented_on_post'].includes(reason))
|
||||
) {
|
||||
throw new Error('Notification does not fit the reason!')
|
||||
}
|
||||
|
||||
let cypher
|
||||
const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
await validateNotifyUsers(label, reason)
|
||||
let mentionedCypher
|
||||
switch (reason) {
|
||||
case 'mentioned_in_post': {
|
||||
cypher = `
|
||||
mentionedCypher = `
|
||||
MATCH (post: Post { id: $id })<-[:WROTE]-(author: User)
|
||||
MATCH (user: User)
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)<-[:BLOCKED]-(author)
|
||||
MERGE (post)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
SET notification.read = FALSE
|
||||
SET (
|
||||
CASE
|
||||
WHEN notification.createdAt IS NULL
|
||||
THEN notification END ).createdAt = toString(datetime())
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
`
|
||||
break
|
||||
}
|
||||
case 'mentioned_in_comment': {
|
||||
cypher = `
|
||||
MATCH (postAuthor: User)-[:WROTE]->(post: Post)<-[:COMMENTS]-(comment: Comment { id: $id })<-[:WROTE]-(author: User)
|
||||
MATCH (user: User)
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)<-[:BLOCKED]-(author)
|
||||
AND NOT (user)<-[:BLOCKED]-(postAuthor)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
SET notification.read = FALSE
|
||||
SET (
|
||||
CASE
|
||||
WHEN notification.createdAt IS NULL
|
||||
THEN notification END ).createdAt = toString(datetime())
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
`
|
||||
break
|
||||
}
|
||||
case 'commented_on_post': {
|
||||
cypher = `
|
||||
MATCH (postAuthor: User)-[:WROTE]->(post: Post)<-[:COMMENTS]-(comment: Comment { id: $id })<-[:WROTE]-(author: User)
|
||||
MATCH (user: User)
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)<-[:BLOCKED]-(author)
|
||||
AND NOT (author)<-[:BLOCKED]-(user)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
SET notification.read = FALSE
|
||||
SET (
|
||||
CASE
|
||||
WHEN notification.createdAt IS NULL
|
||||
THEN notification END ).createdAt = toString(datetime())
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
mentionedCypher = `
|
||||
MATCH (postAuthor: User)-[:WROTE]->(post: Post)<-[:COMMENTS]-(comment: Comment { id: $id })<-[:WROTE]-(author: User)
|
||||
MATCH (user: User)
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)<-[:BLOCKED]-(author)
|
||||
AND NOT (user)<-[:BLOCKED]-(postAuthor)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
`
|
||||
break
|
||||
}
|
||||
}
|
||||
mentionedCypher += `
|
||||
SET notification.read = FALSE
|
||||
SET (
|
||||
CASE
|
||||
WHEN notification.createdAt IS NULL
|
||||
THEN notification END ).createdAt = toString(datetime())
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
`
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
await session.writeTransaction(transaction => {
|
||||
return transaction.run(cypher, { id, idsOfUsers, reason })
|
||||
return transaction.run(mentionedCypher, { id, idsOfUsers, reason })
|
||||
})
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
|
||||
const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => {
|
||||
const idsOfUsers = extractMentionedUsers(args.content)
|
||||
const post = await resolve(root, args, context, resolveInfo)
|
||||
if (post) await notifyUsers('Post', post.id, idsOfUsers, 'mentioned_in_post', context)
|
||||
return post
|
||||
}
|
||||
const notifyUsersOfComment = async (label, commentId, postAuthorId, reason, context) => {
|
||||
await validateNotifyUsers(label, reason)
|
||||
const session = context.driver.session()
|
||||
|
||||
const handleContentDataOfComment = async (resolve, root, args, context, resolveInfo) => {
|
||||
const { content, id: commentId } = args
|
||||
let idsOfUsers = extractMentionedUsers(content)
|
||||
const [postAuthor] = await postAuthorOfComment(commentId, { context })
|
||||
idsOfUsers = idsOfUsers.filter(id => id !== postAuthor.id)
|
||||
if (idsOfUsers && idsOfUsers.length)
|
||||
await notifyUsers('Comment', commentId, idsOfUsers, 'mentioned_in_comment', context)
|
||||
if (context.user.id !== postAuthor.id)
|
||||
await notifyUsers('Comment', commentId, [postAuthor.id], 'commented_on_post', context)
|
||||
}
|
||||
|
||||
const handleCreateComment = async (resolve, root, args, context, resolveInfo) => {
|
||||
const comment = await resolve(root, args, context, resolveInfo)
|
||||
if (comment) return handleContentDataOfComment(resolve, root, args, context, resolveInfo)
|
||||
try {
|
||||
return session.writeTransaction(async transaction => {
|
||||
await transaction.run(
|
||||
`
|
||||
MATCH (postAuthor:User {id: $postAuthorId})-[:WROTE]->(post:Post)<-[:COMMENTS]-(comment:Comment { id: $commentId })<-[:WROTE]-(commenter:User)
|
||||
WHERE NOT (postAuthor)-[:BLOCKED]-(commenter)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(postAuthor)
|
||||
SET notification.read = FALSE
|
||||
SET (
|
||||
CASE
|
||||
WHEN notification.createdAt IS NULL
|
||||
THEN notification END ).createdAt = toString(datetime())
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
`,
|
||||
{ commentId, postAuthorId, reason },
|
||||
)
|
||||
})
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@ -35,7 +35,8 @@ const createCommentMutation = gql`
|
||||
}
|
||||
`
|
||||
|
||||
beforeAll(() => {
|
||||
beforeAll(async () => {
|
||||
await factory.cleanDatabase()
|
||||
const createServerResult = createServer({
|
||||
context: () => {
|
||||
return {
|
||||
@ -169,7 +170,6 @@ describe('notifications', () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -186,7 +186,7 @@ describe('notifications', () => {
|
||||
const expected = expect.objectContaining({
|
||||
data: { notifications: [] },
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -210,7 +210,7 @@ describe('notifications', () => {
|
||||
const expected = expect.objectContaining({
|
||||
data: { notifications: [] },
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -261,7 +261,7 @@ describe('notifications', () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -405,7 +405,7 @@ describe('notifications', () => {
|
||||
const expected = expect.objectContaining({
|
||||
data: { notifications: [] },
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -463,7 +463,7 @@ describe('notifications', () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -497,7 +497,7 @@ describe('notifications', () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -528,7 +528,7 @@ describe('notifications', () => {
|
||||
const expected = expect.objectContaining({
|
||||
data: { notifications: [] },
|
||||
})
|
||||
const { query } = createTestClient(server)
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
|
||||
@ -115,6 +115,17 @@ const validateReview = async (resolve, root, args, context, info) => {
|
||||
return resolve(root, args, context, info)
|
||||
}
|
||||
|
||||
export const validateNotifyUsers = async (label, reason) => {
|
||||
const reasonsAllowed = ['mentioned_in_post', 'mentioned_in_comment', 'commented_on_post']
|
||||
if (!reasonsAllowed.includes(reason)) throw new Error('Notification reason is not allowed!')
|
||||
if (
|
||||
(label === 'Post' && reason !== 'mentioned_in_post') ||
|
||||
(label === 'Comment' && !['mentioned_in_comment', 'commented_on_post'].includes(reason))
|
||||
) {
|
||||
throw new Error('Notification does not fit the reason!')
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
Mutation: {
|
||||
CreateComment: validateCreateComment,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user