mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
feat(backend): notifications for groups
This commit is contained in:
parent
f3bf64ea4f
commit
28952567b0
@ -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 handleContentDataOfPost = async (resolve, root, args, context, resolveInfo) => {
|
||||||
const idsOfUsers = extractMentionedUsers(args.content)
|
const idsOfUsers = extractMentionedUsers(args.content)
|
||||||
const post = await resolve(root, args, context, resolveInfo)
|
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) => {
|
const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||||
if (!(idsOfUsers && idsOfUsers.length)) return []
|
if (!(idsOfUsers && idsOfUsers.length)) return []
|
||||||
await validateNotifyUsers(label, reason)
|
await validateNotifyUsers(label, reason)
|
||||||
@ -188,5 +231,6 @@ export default {
|
|||||||
UpdatePost: handleContentDataOfPost,
|
UpdatePost: handleContentDataOfPost,
|
||||||
CreateComment: handleContentDataOfComment,
|
CreateComment: handleContentDataOfComment,
|
||||||
UpdateComment: handleContentDataOfComment,
|
UpdateComment: handleContentDataOfComment,
|
||||||
|
JoinGroup: handleJoinGroup,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,14 @@ import { cleanDatabase } from '../../db/factories'
|
|||||||
import { createTestClient } from 'apollo-server-testing'
|
import { createTestClient } from 'apollo-server-testing'
|
||||||
import { getNeode, getDriver } from '../../db/neo4j'
|
import { getNeode, getDriver } from '../../db/neo4j'
|
||||||
import createServer, { pubsub } from '../../server'
|
import createServer, { pubsub } from '../../server'
|
||||||
|
import {
|
||||||
|
createGroupMutation,
|
||||||
|
joinGroupMutation,
|
||||||
|
leaveGroupMutation,
|
||||||
|
changeGroupMemberRoleMutation,
|
||||||
|
removeUserFromGroupMutation,
|
||||||
|
} from '../../graphql/groups'
|
||||||
|
|
||||||
|
|
||||||
let server, query, mutate, notifiedUser, authenticatedUser
|
let server, query, mutate, notifiedUser, authenticatedUser
|
||||||
let publishSpy
|
let publishSpy
|
||||||
@ -102,6 +110,9 @@ describe('notifications', () => {
|
|||||||
id
|
id
|
||||||
content
|
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,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,4 +2,5 @@ enum ReasonNotification {
|
|||||||
mentioned_in_post
|
mentioned_in_post
|
||||||
mentioned_in_comment
|
mentioned_in_comment
|
||||||
commented_on_post
|
commented_on_post
|
||||||
|
user_joined_group
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ type NOTIFIED {
|
|||||||
reason: NotificationReason
|
reason: NotificationReason
|
||||||
}
|
}
|
||||||
|
|
||||||
union NotificationSource = Post | Comment
|
union NotificationSource = Post | Comment | Group
|
||||||
|
|
||||||
enum NotificationOrdering {
|
enum NotificationOrdering {
|
||||||
createdAt_asc
|
createdAt_asc
|
||||||
@ -21,6 +21,7 @@ enum NotificationReason {
|
|||||||
mentioned_in_post
|
mentioned_in_post
|
||||||
mentioned_in_comment
|
mentioned_in_comment
|
||||||
commented_on_post
|
commented_on_post
|
||||||
|
user_joined_group
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user