feat(backend): notifications for groups

This commit is contained in:
Moriz Wahl 2023-03-15 15:27:22 +01:00
parent f3bf64ea4f
commit 28952567b0
4 changed files with 126 additions and 1 deletions

View File

@ -51,6 +51,19 @@ const publishNotifications = async (context, promises) => {
})
}
const handleJoinGroup = async (resolve, root, args, context, resolveInfo) => {
const { groupId } = args
const user = await resolve(root, args, context, resolveInfo)
if (user) {
await publishNotifications(
context,
[notifyOwnersOfGroup(groupId, 'user_joined_group', context)]
)
}
return user
}
const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => {
const idsOfUsers = extractMentionedUsers(args.content)
const post = await resolve(root, args, context, resolveInfo)
@ -94,6 +107,36 @@ const postAuthorOfComment = async (commentId, { context }) => {
}
}
const notifyOwnersOfGroup = async (groupId, reason, context) => {
const cypher = `
MATCH (group:Group { id: $groupId })<-[membership:MEMBER_OF]-(owner:User)
WHERE membership.role = 'owner'
WITH owner, group
MERGE (group)-[notification:NOTIFIED {reason: $reason}]->(owner)
WITH group, owner, notification
SET notification.read = FALSE
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
SET notification.updatedAt = toString(datetime())
RETURN notification {.*, from: group, to: properties(owner)}
`
const session = context.driver.session()
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
const notificationTransactionResponse = await transaction.run(cypher, {
groupId,
reason,
})
return notificationTransactionResponse.records.map((record) => record.get('notification'))
})
try {
const notifications = await writeTxResultPromise
return notifications
} catch (error) {
throw new Error(error)
} finally {
session.close()
}
}
const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
if (!(idsOfUsers && idsOfUsers.length)) return []
await validateNotifyUsers(label, reason)
@ -188,5 +231,6 @@ export default {
UpdatePost: handleContentDataOfPost,
CreateComment: handleContentDataOfComment,
UpdateComment: handleContentDataOfComment,
JoinGroup: handleJoinGroup,
},
}

View File

@ -3,6 +3,14 @@ import { cleanDatabase } from '../../db/factories'
import { createTestClient } from 'apollo-server-testing'
import { getNeode, getDriver } from '../../db/neo4j'
import createServer, { pubsub } from '../../server'
import {
createGroupMutation,
joinGroupMutation,
leaveGroupMutation,
changeGroupMemberRoleMutation,
removeUserFromGroupMutation,
} from '../../graphql/groups'
let server, query, mutate, notifiedUser, authenticatedUser
let publishSpy
@ -102,6 +110,9 @@ describe('notifications', () => {
id
content
}
... on Group {
id
}
}
}
}
@ -616,4 +627,72 @@ describe('notifications', () => {
})
})
})
describe('group notifications', () => {
let groupOwner
let group
beforeEach(async () => {
groupOwner = await neode.create(
'User',
{
id: 'group-owner',
name: 'Group Owner',
slug: 'group-owner',
},
{
email: 'owner@example.org',
password: '1234',
},
)
authenticatedUser = await groupOwner.toJson()
await mutate({
mutation: createGroupMutation(),
variables: {
id: 'closed-group',
name: 'The Closed Group',
about: 'Will test the closed group!',
description: 'Some description' + Array(50).join('_'),
groupType: 'public',
actionRadius: 'regional',
categoryIds,
},
})
})
describe('user joins group', () => {
beforeEach(async () => {
authenticatedUser = await notifiedUser.toJson()
await mutate({
mutation: joinGroupMutation(),
variables: {
groupId: 'closed-group',
userId: authenticatedUser.id,
},
})
authenticatedUser = await groupOwner.toJson()
})
it('works', async () => {
await expect(query({
query: notificationQuery,
})).resolves.toMatchObject({
data: {
notifications: [
{
read: false,
reason: 'user_joined_group',
createdAt: expect.any(String),
from: {
__typename: 'Group',
id: 'closed-group',
}
},
],
},
errors: undefined,
})
})
})
})
})

View File

@ -2,4 +2,5 @@ enum ReasonNotification {
mentioned_in_post
mentioned_in_comment
commented_on_post
user_joined_group
}

View File

@ -8,7 +8,7 @@ type NOTIFIED {
reason: NotificationReason
}
union NotificationSource = Post | Comment
union NotificationSource = Post | Comment | Group
enum NotificationOrdering {
createdAt_asc
@ -21,6 +21,7 @@ enum NotificationReason {
mentioned_in_post
mentioned_in_comment
commented_on_post
user_joined_group
}
type Query {