mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
fix(backend): fix notification emails with different name (#8419)
* fix diffent name notifications We had emails sent with incorrect names. This PR combines the query for the email with the user the notification is sent to since the notification in database was correct. The underlying problem is the unstable order in which the database can return values. The results of the two queries were matched by id since it was assumed that they always return the same order of elements. lint fixes fix typo fix factory fix tests * fix tests accoridng to review also test for the right amount of emails in every test
This commit is contained in:
parent
5883818b91
commit
649491f7cb
@ -16,20 +16,21 @@ import createServer from '@src/server'
|
||||
|
||||
CONFIG.CATEGORIES_ACTIVE = false
|
||||
|
||||
const sendMailMock = jest.fn()
|
||||
jest.mock('../helpers/email/sendMail', () => ({
|
||||
sendMail: () => sendMailMock(),
|
||||
const sendMailMock: (notification) => void = jest.fn()
|
||||
jest.mock('@middleware/helpers/email/sendMail', () => ({
|
||||
sendMail: (notification) => sendMailMock(notification),
|
||||
}))
|
||||
|
||||
let server, query, mutate, authenticatedUser
|
||||
let server, query, mutate, authenticatedUser, emaillessMember
|
||||
|
||||
let postAuthor, groupMember
|
||||
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
|
||||
const mentionString =
|
||||
'<a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member">@group-member</a>'
|
||||
const mentionString = `
|
||||
<a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member">@group-member</a>
|
||||
<a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member">@email-less-member</a>`
|
||||
|
||||
const createPostMutation = gql`
|
||||
mutation ($id: ID, $title: String!, $content: String!, $groupId: ID) {
|
||||
@ -148,6 +149,11 @@ describe('emails sent for notifications', () => {
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
emaillessMember = await neode.create('User', {
|
||||
id: 'email-less-member',
|
||||
name: 'Email-less Member',
|
||||
slug: 'email-less-member',
|
||||
})
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: createGroupMutation(),
|
||||
@ -171,6 +177,18 @@ describe('emails sent for notifications', () => {
|
||||
mutation: followUserMutation,
|
||||
variables: { id: 'post-author' },
|
||||
})
|
||||
authenticatedUser = await emaillessMember.toJson()
|
||||
await mutate({
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'public-group',
|
||||
userId: 'group-member',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: followUserMutation,
|
||||
variables: { id: 'post-author' },
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
@ -188,7 +206,7 @@ describe('emails sent for notifications', () => {
|
||||
variables: {
|
||||
id: 'post',
|
||||
title: 'This is the post',
|
||||
content: `Hello, ${mentionString}, my trusty follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
groupId: 'public-group',
|
||||
},
|
||||
})
|
||||
@ -213,7 +231,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'post_in_group',
|
||||
@ -225,7 +243,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'followed_user_posted',
|
||||
@ -237,7 +255,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
@ -260,7 +278,7 @@ describe('emails sent for notifications', () => {
|
||||
variables: {
|
||||
id: 'post',
|
||||
title: 'This is the post',
|
||||
content: `Hello, ${mentionString}, my trusty follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
groupId: 'public-group',
|
||||
},
|
||||
})
|
||||
@ -285,7 +303,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'post_in_group',
|
||||
@ -297,7 +315,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'followed_user_posted',
|
||||
@ -309,7 +327,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
@ -333,7 +351,7 @@ describe('emails sent for notifications', () => {
|
||||
variables: {
|
||||
id: 'post',
|
||||
title: 'This is the post',
|
||||
content: `Hello, ${mentionString}, my trusty follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
groupId: 'public-group',
|
||||
},
|
||||
})
|
||||
@ -358,7 +376,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'post_in_group',
|
||||
@ -370,7 +388,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'followed_user_posted',
|
||||
@ -382,7 +400,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
@ -407,7 +425,7 @@ describe('emails sent for notifications', () => {
|
||||
variables: {
|
||||
id: 'post',
|
||||
title: 'This is the post',
|
||||
content: `Hello, ${mentionString}, my trusty follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
groupId: 'public-group',
|
||||
},
|
||||
})
|
||||
@ -432,7 +450,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'post_in_group',
|
||||
@ -444,7 +462,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'followed_user_posted',
|
||||
@ -456,7 +474,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my trusty follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
@ -481,7 +499,7 @@ describe('emails sent for notifications', () => {
|
||||
variables: {
|
||||
id: 'post',
|
||||
title: 'This is the post',
|
||||
content: `Hello, ${mentionString}, my trusty follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
groupId: 'public-group',
|
||||
},
|
||||
})
|
||||
@ -501,7 +519,7 @@ describe('emails sent for notifications', () => {
|
||||
mutation: createCommentMutation,
|
||||
variables: {
|
||||
id: 'comment-2',
|
||||
content: `Hello, ${mentionString}, my beloved follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
postId: 'post',
|
||||
},
|
||||
})
|
||||
@ -529,7 +547,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Comment',
|
||||
id: 'comment-2',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my beloved follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'commented_on_post',
|
||||
@ -541,7 +559,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Comment',
|
||||
id: 'comment-2',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my beloved follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_comment',
|
||||
@ -563,7 +581,7 @@ describe('emails sent for notifications', () => {
|
||||
variables: {
|
||||
id: 'post',
|
||||
title: 'This is the post',
|
||||
content: `Hello, ${mentionString}, my trusty follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
groupId: 'public-group',
|
||||
},
|
||||
})
|
||||
@ -583,7 +601,7 @@ describe('emails sent for notifications', () => {
|
||||
mutation: createCommentMutation,
|
||||
variables: {
|
||||
id: 'comment-2',
|
||||
content: `Hello, ${mentionString}, my beloved follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
postId: 'post',
|
||||
},
|
||||
})
|
||||
@ -611,7 +629,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Comment',
|
||||
id: 'comment-2',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my beloved follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'commented_on_post',
|
||||
@ -623,7 +641,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Comment',
|
||||
id: 'comment-2',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my beloved follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_comment',
|
||||
@ -646,7 +664,7 @@ describe('emails sent for notifications', () => {
|
||||
variables: {
|
||||
id: 'post',
|
||||
title: 'This is the post',
|
||||
content: `Hello, ${mentionString}, my trusty follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
groupId: 'public-group',
|
||||
},
|
||||
})
|
||||
@ -666,7 +684,7 @@ describe('emails sent for notifications', () => {
|
||||
mutation: createCommentMutation,
|
||||
variables: {
|
||||
id: 'comment-2',
|
||||
content: `Hello, ${mentionString}, my beloved follower.`,
|
||||
content: `Hello, ${mentionString}, my trusty followers.`,
|
||||
postId: 'post',
|
||||
},
|
||||
})
|
||||
@ -694,7 +712,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Comment',
|
||||
id: 'comment-2',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my beloved follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'commented_on_post',
|
||||
@ -706,7 +724,7 @@ describe('emails sent for notifications', () => {
|
||||
__typename: 'Comment',
|
||||
id: 'comment-2',
|
||||
content:
|
||||
'Hello, <a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>, my beloved follower.',
|
||||
'Hello, <br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a><br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>, my trusty followers.',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_comment',
|
||||
|
||||
@ -14,14 +14,14 @@ import createServer from '@src/server'
|
||||
|
||||
CONFIG.CATEGORIES_ACTIVE = false
|
||||
|
||||
const sendMailMock = jest.fn()
|
||||
jest.mock('../helpers/email/sendMail', () => ({
|
||||
sendMail: () => sendMailMock(),
|
||||
const sendMailMock: (notification) => void = jest.fn()
|
||||
jest.mock('@middleware/helpers/email/sendMail', () => ({
|
||||
sendMail: (notification) => sendMailMock(notification),
|
||||
}))
|
||||
|
||||
let server, query, mutate, authenticatedUser
|
||||
|
||||
let postAuthor, firstFollower, secondFollower
|
||||
let postAuthor, firstFollower, secondFollower, thirdFollower, emaillessFollower
|
||||
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
@ -107,7 +107,7 @@ describe('following users notifications', () => {
|
||||
slug: 'post-author',
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
email: 'post-author@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
@ -119,7 +119,7 @@ describe('following users notifications', () => {
|
||||
slug: 'first-follower',
|
||||
},
|
||||
{
|
||||
email: 'test2@example.org',
|
||||
email: 'first-follower@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
@ -131,10 +131,27 @@ describe('following users notifications', () => {
|
||||
slug: 'second-follower',
|
||||
},
|
||||
{
|
||||
email: 'test3@example.org',
|
||||
email: 'second-follower@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
thirdFollower = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'third-follower',
|
||||
name: 'Third Follower',
|
||||
slug: 'third-follower',
|
||||
},
|
||||
{
|
||||
email: 'third-follower@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
emaillessFollower = await neode.create('User', {
|
||||
id: 'email-less-follower',
|
||||
name: 'Email-less Follower',
|
||||
slug: 'email-less-follower',
|
||||
})
|
||||
await secondFollower.update({ emailNotificationsFollowingUsers: false })
|
||||
authenticatedUser = await firstFollower.toJson()
|
||||
await mutate({
|
||||
@ -146,6 +163,16 @@ describe('following users notifications', () => {
|
||||
mutation: followUserMutation,
|
||||
variables: { id: 'post-author' },
|
||||
})
|
||||
authenticatedUser = await thirdFollower.toJson()
|
||||
await mutate({
|
||||
mutation: followUserMutation,
|
||||
variables: { id: 'post-author' },
|
||||
})
|
||||
authenticatedUser = await emaillessFollower.toJson()
|
||||
await mutate({
|
||||
mutation: followUserMutation,
|
||||
variables: { id: 'post-author' },
|
||||
})
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
@ -221,8 +248,43 @@ describe('following users notifications', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('sends only one email, as second follower has emails disabled', () => {
|
||||
expect(sendMailMock).toHaveBeenCalledTimes(1)
|
||||
it('sends notification to the email-less follower', async () => {
|
||||
authenticatedUser = await emaillessFollower.toJson()
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
notifications: [
|
||||
{
|
||||
from: {
|
||||
__typename: 'Post',
|
||||
id: 'post',
|
||||
},
|
||||
read: false,
|
||||
reason: 'followed_user_posted',
|
||||
},
|
||||
],
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('sends only two emails, as second follower has emails disabled and email-less follower has no email', () => {
|
||||
expect(sendMailMock).toHaveBeenCalledTimes(2)
|
||||
expect(sendMailMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
html: expect.stringContaining('Hello First Follower'),
|
||||
to: 'first-follower@example.org',
|
||||
}),
|
||||
)
|
||||
expect(sendMailMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
html: expect.stringContaining('Hello Third Follower'),
|
||||
to: 'third-follower@example.org',
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -17,22 +17,23 @@ import createServer from '@src/server'
|
||||
|
||||
CONFIG.CATEGORIES_ACTIVE = false
|
||||
|
||||
const sendMailMock = jest.fn()
|
||||
jest.mock('../helpers/email/sendMail', () => ({
|
||||
sendMail: () => sendMailMock(),
|
||||
const sendMailMock: (notification) => void = jest.fn()
|
||||
jest.mock('@middleware/helpers/email/sendMail', () => ({
|
||||
sendMail: (notification) => sendMailMock(notification),
|
||||
}))
|
||||
|
||||
let server, query, mutate, authenticatedUser
|
||||
|
||||
let postAuthor, groupMember, pendingMember, noMember
|
||||
let postAuthor, groupMember, pendingMember, noMember, emaillessMember
|
||||
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
|
||||
const mentionString = `
|
||||
<a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member">@no-meber</a>
|
||||
<a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member">@no-member</a>
|
||||
<a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member">@pending-member</a>
|
||||
<a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member">@group-member</a>.
|
||||
<a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member">@email-less-member</a>.
|
||||
`
|
||||
|
||||
const createPostMutation = gql`
|
||||
@ -168,6 +169,12 @@ describe('mentions in groups', () => {
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
emaillessMember = await neode.create('User', {
|
||||
id: 'email-less-member',
|
||||
name: 'Email-less Member',
|
||||
slug: 'email-less-member',
|
||||
})
|
||||
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: createGroupMutation(),
|
||||
@ -243,6 +250,28 @@ describe('mentions in groups', () => {
|
||||
userId: 'pending-member',
|
||||
},
|
||||
})
|
||||
authenticatedUser = await emaillessMember.toJson()
|
||||
await mutate({
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'public-group',
|
||||
userId: 'group-member',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'closed-group',
|
||||
userId: 'group-member',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'group-member',
|
||||
},
|
||||
})
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
@ -260,8 +289,26 @@ describe('mentions in groups', () => {
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'closed-group',
|
||||
userId: 'email-less-member',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'hidden-group',
|
||||
userId: 'email-less-member',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await markAllAsRead()
|
||||
authenticatedUser = await emaillessMember.toJson()
|
||||
await markAllAsRead()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
@ -327,7 +374,7 @@ describe('mentions in groups', () => {
|
||||
__typename: 'Post',
|
||||
id: 'public-post',
|
||||
content:
|
||||
'Hey <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-meber</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br>! Please read this',
|
||||
'Hey <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-member</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>.<br>! Please read this',
|
||||
},
|
||||
read: false,
|
||||
reason: 'post_in_group',
|
||||
@ -339,7 +386,7 @@ describe('mentions in groups', () => {
|
||||
__typename: 'Post',
|
||||
id: 'public-post',
|
||||
content:
|
||||
'Hey <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-meber</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br>! Please read this',
|
||||
'Hey <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-member</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>.<br>! Please read this',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
@ -351,7 +398,7 @@ describe('mentions in groups', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('sends 3 emails, one for each user', () => {
|
||||
it('sends only 3 emails, one for each user with an email', () => {
|
||||
expect(sendMailMock).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
})
|
||||
@ -423,7 +470,7 @@ describe('mentions in groups', () => {
|
||||
__typename: 'Post',
|
||||
id: 'closed-post',
|
||||
content:
|
||||
'Hey members <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-meber</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br>! Please read this',
|
||||
'Hey members <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-member</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>.<br>! Please read this',
|
||||
},
|
||||
read: false,
|
||||
reason: 'post_in_group',
|
||||
@ -435,7 +482,7 @@ describe('mentions in groups', () => {
|
||||
__typename: 'Post',
|
||||
id: 'closed-post',
|
||||
content:
|
||||
'Hey members <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-meber</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br>! Please read this',
|
||||
'Hey members <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-member</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>.<br>! Please read this',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
@ -519,7 +566,7 @@ describe('mentions in groups', () => {
|
||||
__typename: 'Post',
|
||||
id: 'hidden-post',
|
||||
content:
|
||||
'Hey hiders <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-meber</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br>! Please read this',
|
||||
'Hey hiders <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-member</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>.<br>! Please read this',
|
||||
},
|
||||
read: false,
|
||||
reason: 'post_in_group',
|
||||
@ -531,7 +578,7 @@ describe('mentions in groups', () => {
|
||||
__typename: 'Post',
|
||||
id: 'hidden-post',
|
||||
content:
|
||||
'Hey hiders <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-meber</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br>! Please read this',
|
||||
'Hey hiders <br><a class="mention" data-mention-id="no-member" href="/profile/no-member/no-member" target="_blank">@no-member</a><br><a class="mention" data-mention-id="pending-member" href="/profile/pending-member/pending-member" target="_blank">@pending-member</a><br><a class="mention" data-mention-id="group-member" href="/profile/group-member/group-member" target="_blank">@group-member</a>.<br><a class="mention" data-mention-id="email-less-member" href="/profile/email-less-member/email-less-member" target="_blank">@email-less-member</a>.<br>! Please read this',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
|
||||
@ -6,15 +6,20 @@ import { createTestClient } from 'apollo-server-testing'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import CONFIG from '@config/index'
|
||||
import { cleanDatabase } from '@db/factories'
|
||||
import Factory, { cleanDatabase } from '@db/factories'
|
||||
import { getNeode, getDriver } from '@db/neo4j'
|
||||
import createServer from '@src/server'
|
||||
|
||||
CONFIG.CATEGORIES_ACTIVE = false
|
||||
|
||||
const sendMailMock: (notification) => void = jest.fn()
|
||||
jest.mock('@middleware/helpers/email/sendMail', () => ({
|
||||
sendMail: (notification) => sendMailMock(notification),
|
||||
}))
|
||||
|
||||
let server, query, mutate, authenticatedUser
|
||||
|
||||
let postAuthor, firstCommenter, secondCommenter
|
||||
let postAuthor, firstCommenter, secondCommenter, emaillessObserver
|
||||
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
@ -102,42 +107,47 @@ afterAll(async () => {
|
||||
|
||||
describe('notifications for users that observe a post', () => {
|
||||
beforeAll(async () => {
|
||||
postAuthor = await neode.create(
|
||||
'User',
|
||||
postAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'post-author',
|
||||
name: 'Post Author',
|
||||
slug: 'post-author',
|
||||
},
|
||||
{
|
||||
email: 'test@example.org',
|
||||
email: 'post-author@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
firstCommenter = await neode.create(
|
||||
'User',
|
||||
firstCommenter = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'first-commenter',
|
||||
name: 'First Commenter',
|
||||
slug: 'first-commenter',
|
||||
},
|
||||
{
|
||||
email: 'test2@example.org',
|
||||
email: 'first-commenter@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
secondCommenter = await neode.create(
|
||||
'User',
|
||||
secondCommenter = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'second-commenter',
|
||||
name: 'Second Commenter',
|
||||
slug: 'second-commenter',
|
||||
},
|
||||
{
|
||||
email: 'test3@example.org',
|
||||
email: 'second-commenter@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
emaillessObserver = await neode.create('User', {
|
||||
id: 'email-less-observer',
|
||||
name: 'Email-less Observer',
|
||||
slug: 'email-less-observer',
|
||||
})
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: createPostMutation,
|
||||
@ -147,6 +157,14 @@ describe('notifications for users that observe a post', () => {
|
||||
content: 'This is the content of the post',
|
||||
},
|
||||
})
|
||||
authenticatedUser = await emaillessObserver.toJson()
|
||||
await mutate({
|
||||
mutation: toggleObservePostMutation,
|
||||
variables: {
|
||||
id: 'post',
|
||||
value: true,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
describe('first comment on the post', () => {
|
||||
@ -198,8 +216,18 @@ describe('notifications for users that observe a post', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('sends one email', () => {
|
||||
expect(sendMailMock).toHaveBeenCalledTimes(1)
|
||||
expect(sendMailMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
to: 'post-author@example.org',
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
describe('second comment on post', () => {
|
||||
beforeAll(async () => {
|
||||
jest.clearAllMocks()
|
||||
authenticatedUser = await secondCommenter.toJson()
|
||||
await mutate({
|
||||
mutation: createCommentMutation,
|
||||
@ -277,10 +305,25 @@ describe('notifications for users that observe a post', () => {
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('sends two emails', () => {
|
||||
expect(sendMailMock).toHaveBeenCalledTimes(2)
|
||||
expect(sendMailMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
to: 'post-author@example.org',
|
||||
}),
|
||||
)
|
||||
expect(sendMailMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
to: 'first-commenter@example.org',
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('first commenter unfollows the post and post author comments post', () => {
|
||||
beforeAll(async () => {
|
||||
jest.clearAllMocks()
|
||||
authenticatedUser = await firstCommenter.toJson()
|
||||
await mutate({
|
||||
mutation: toggleObservePostMutation,
|
||||
@ -376,6 +419,15 @@ describe('notifications for users that observe a post', () => {
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('sends one email', () => {
|
||||
expect(sendMailMock).toHaveBeenCalledTimes(1)
|
||||
expect(sendMailMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
to: 'second-commenter@example.org',
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -13,9 +13,9 @@ import createServer from '@src/server'
|
||||
|
||||
CONFIG.CATEGORIES_ACTIVE = false
|
||||
|
||||
const sendMailMock = jest.fn()
|
||||
jest.mock('../helpers/email/sendMail', () => ({
|
||||
sendMail: () => sendMailMock(),
|
||||
const sendMailMock: (notification) => void = jest.fn()
|
||||
jest.mock('@middleware/helpers/email/sendMail', () => ({
|
||||
sendMail: (notification) => sendMailMock(notification),
|
||||
}))
|
||||
|
||||
let isUserOnlineMock = jest.fn().mockReturnValue(false)
|
||||
|
||||
@ -17,14 +17,14 @@ import createServer from '@src/server'
|
||||
|
||||
CONFIG.CATEGORIES_ACTIVE = false
|
||||
|
||||
const sendMailMock = jest.fn()
|
||||
jest.mock('../helpers/email/sendMail', () => ({
|
||||
sendMail: () => sendMailMock(),
|
||||
const sendMailMock: (notification) => void = jest.fn()
|
||||
jest.mock('@middleware/helpers/email/sendMail', () => ({
|
||||
sendMail: (notification) => sendMailMock(notification),
|
||||
}))
|
||||
|
||||
let server, query, mutate, authenticatedUser
|
||||
|
||||
let postAuthor, groupMember, pendingMember
|
||||
let postAuthor, groupMember, pendingMember, emaillessMember
|
||||
|
||||
const driver = getDriver()
|
||||
const neode = getNeode()
|
||||
@ -159,6 +159,12 @@ describe('notify group members of new posts in group', () => {
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
emaillessMember = await neode.create('User', {
|
||||
id: 'email-less-member',
|
||||
name: 'Email-less Member',
|
||||
slug: 'email-less-member',
|
||||
})
|
||||
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: createGroupMutation(),
|
||||
@ -186,6 +192,14 @@ describe('notify group members of new posts in group', () => {
|
||||
userId: 'pending-member',
|
||||
},
|
||||
})
|
||||
authenticatedUser = await emaillessMember.toJson()
|
||||
await mutate({
|
||||
mutation: joinGroupMutation(),
|
||||
variables: {
|
||||
groupId: 'g-1',
|
||||
userId: 'group-member',
|
||||
},
|
||||
})
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
@ -195,6 +209,14 @@ describe('notify group members of new posts in group', () => {
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
await mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: {
|
||||
groupId: 'g-1',
|
||||
userId: 'email-less-member',
|
||||
roleInGroup: 'usual',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
|
||||
@ -18,9 +18,9 @@ import { leaveGroupMutation } from '@graphql/queries/leaveGroupMutation'
|
||||
import { removeUserFromGroupMutation } from '@graphql/queries/removeUserFromGroupMutation'
|
||||
import createServer, { pubsub } from '@src/server'
|
||||
|
||||
const sendMailMock = jest.fn()
|
||||
jest.mock('../helpers/email/sendMail', () => ({
|
||||
sendMail: () => sendMailMock(),
|
||||
const sendMailMock: (notification) => void = jest.fn()
|
||||
jest.mock('@middleware/helpers/email/sendMail', () => ({
|
||||
sendMail: (notification) => sendMailMock(notification),
|
||||
}))
|
||||
|
||||
const chatMessageTemplateMock = jest.fn()
|
||||
@ -195,8 +195,8 @@ describe('notifications', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
commentContent = 'Commenters comment.'
|
||||
commentAuthor = await neode.create(
|
||||
'User',
|
||||
commentAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
@ -345,8 +345,8 @@ describe('notifications', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
postAuthor = await neode.create(
|
||||
'User',
|
||||
postAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'postAuthor',
|
||||
name: 'Mrs Post',
|
||||
@ -658,8 +658,8 @@ describe('notifications', () => {
|
||||
beforeEach(async () => {
|
||||
commentContent =
|
||||
'One mention about me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">@al-capone</a>.'
|
||||
commentAuthor = await neode.create(
|
||||
'User',
|
||||
commentAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
@ -673,15 +673,15 @@ describe('notifications', () => {
|
||||
})
|
||||
|
||||
it('sends only one notification with reason mentioned_in_comment', async () => {
|
||||
postAuthor = await neode.create(
|
||||
'User',
|
||||
postAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'MrPostAuthor',
|
||||
name: 'Mr Author',
|
||||
slug: 'mr-author',
|
||||
},
|
||||
{
|
||||
email: 'post-author@example.org',
|
||||
email: 'post-author2@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
@ -756,8 +756,8 @@ describe('notifications', () => {
|
||||
await postAuthor.relateTo(notifiedUser, 'blocked')
|
||||
commentContent =
|
||||
'One mention about me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">@al-capone</a>.'
|
||||
commentAuthor = await neode.create(
|
||||
'User',
|
||||
commentAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
@ -807,8 +807,8 @@ describe('notifications', () => {
|
||||
await postAuthor.relateTo(notifiedUser, 'muted')
|
||||
commentContent =
|
||||
'One mention about me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">@al-capone</a>.'
|
||||
commentAuthor = await neode.create(
|
||||
'User',
|
||||
commentAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
@ -879,8 +879,8 @@ describe('notifications', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
chatSender = await neode.create(
|
||||
'User',
|
||||
chatSender = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
id: 'chatSender',
|
||||
name: 'chatSender',
|
||||
@ -931,7 +931,7 @@ describe('notifications', () => {
|
||||
content: 'Some nice message to chatReceiver',
|
||||
senderId: 'chatSender',
|
||||
username: 'chatSender',
|
||||
avatar: null,
|
||||
avatar: expect.any(String),
|
||||
date: expect.any(String),
|
||||
saved: true,
|
||||
distributed: false,
|
||||
@ -967,7 +967,7 @@ describe('notifications', () => {
|
||||
content: 'Some nice message to chatReceiver',
|
||||
senderId: 'chatSender',
|
||||
username: 'chatSender',
|
||||
avatar: null,
|
||||
avatar: expect.any(String),
|
||||
date: expect.any(String),
|
||||
saved: true,
|
||||
distributed: false,
|
||||
@ -1046,7 +1046,7 @@ describe('notifications', () => {
|
||||
content: 'Some nice message to chatReceiver',
|
||||
senderId: 'chatSender',
|
||||
username: 'chatSender',
|
||||
avatar: null,
|
||||
avatar: expect.any(String),
|
||||
date: expect.any(String),
|
||||
saved: true,
|
||||
distributed: false,
|
||||
|
||||
@ -18,59 +18,28 @@ import { pubsub, NOTIFICATION_ADDED, ROOM_COUNT_UPDATED, CHAT_MESSAGE_ADDED } fr
|
||||
|
||||
import extractMentionedUsers from './mentions/extractMentionedUsers'
|
||||
|
||||
const queryNotificationEmails = async (context, notificationUserIds) => {
|
||||
if (!notificationUserIds?.length) return []
|
||||
const userEmailCypher = `
|
||||
MATCH (user: User)
|
||||
// blocked users are filtered out from notifications already
|
||||
WHERE user.id in $notificationUserIds
|
||||
WITH user
|
||||
MATCH (user)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
RETURN emailAddress {.email}
|
||||
`
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.readTransaction(async (transaction) => {
|
||||
const emailAddressTransactionResponse = await transaction.run(userEmailCypher, {
|
||||
notificationUserIds,
|
||||
})
|
||||
return emailAddressTransactionResponse.records.map((record) => record.get('emailAddress'))
|
||||
})
|
||||
try {
|
||||
const emailAddresses = await writeTxResultPromise
|
||||
return emailAddresses
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
|
||||
const publishNotifications = async (
|
||||
context,
|
||||
promises,
|
||||
notificationsPromise,
|
||||
emailNotificationSetting: string,
|
||||
emailsSent: string[] = [],
|
||||
): Promise<string[]> => {
|
||||
let notifications = await Promise.all(promises)
|
||||
notifications = notifications.flat()
|
||||
const notificationsEmailAddresses = await queryNotificationEmails(
|
||||
context,
|
||||
notifications.map((notification) => notification.to.id),
|
||||
)
|
||||
notifications.forEach((notificationAdded, index) => {
|
||||
const notifications = await notificationsPromise
|
||||
notifications.forEach((notificationAdded) => {
|
||||
pubsub.publish(NOTIFICATION_ADDED, { notificationAdded })
|
||||
if (
|
||||
notificationAdded.email && // no primary email was found
|
||||
(notificationAdded.to[emailNotificationSetting] ?? true) &&
|
||||
!isUserOnline(notificationAdded.to) &&
|
||||
!emailsSent.includes(notificationsEmailAddresses[index].email)
|
||||
!emailsSent.includes(notificationAdded.email)
|
||||
) {
|
||||
sendMail(
|
||||
notificationTemplate({
|
||||
email: notificationsEmailAddresses[index].email,
|
||||
email: notificationAdded.email,
|
||||
variables: { notification: notificationAdded },
|
||||
}),
|
||||
)
|
||||
emailsSent.push(notificationsEmailAddresses[index].email)
|
||||
emailsSent.push(notificationAdded.email)
|
||||
}
|
||||
})
|
||||
return emailsSent
|
||||
@ -82,7 +51,7 @@ const handleJoinGroup = async (resolve, root, args, context, resolveInfo) => {
|
||||
if (user) {
|
||||
await publishNotifications(
|
||||
context,
|
||||
[notifyOwnersOfGroup(groupId, userId, 'user_joined_group', context)],
|
||||
notifyOwnersOfGroup(groupId, userId, 'user_joined_group', context),
|
||||
'emailNotificationsGroupMemberJoined',
|
||||
)
|
||||
}
|
||||
@ -95,7 +64,7 @@ const handleLeaveGroup = async (resolve, root, args, context, resolveInfo) => {
|
||||
if (user) {
|
||||
await publishNotifications(
|
||||
context,
|
||||
[notifyOwnersOfGroup(groupId, userId, 'user_left_group', context)],
|
||||
notifyOwnersOfGroup(groupId, userId, 'user_left_group', context),
|
||||
'emailNotificationsGroupMemberLeft',
|
||||
)
|
||||
}
|
||||
@ -108,7 +77,7 @@ const handleChangeGroupMemberRole = async (resolve, root, args, context, resolve
|
||||
if (user) {
|
||||
await publishNotifications(
|
||||
context,
|
||||
[notifyMemberOfGroup(groupId, userId, 'changed_group_member_role', context)],
|
||||
notifyMemberOfGroup(groupId, userId, 'changed_group_member_role', context),
|
||||
'emailNotificationsGroupMemberRoleChanged',
|
||||
)
|
||||
}
|
||||
@ -121,7 +90,7 @@ const handleRemoveUserFromGroup = async (resolve, root, args, context, resolveIn
|
||||
if (user) {
|
||||
await publishNotifications(
|
||||
context,
|
||||
[notifyMemberOfGroup(groupId, userId, 'removed_user_from_group', context)],
|
||||
notifyMemberOfGroup(groupId, userId, 'removed_user_from_group', context),
|
||||
'emailNotificationsGroupMemberRemoved',
|
||||
)
|
||||
}
|
||||
@ -135,20 +104,20 @@ const handleContentDataOfPost = async (resolve, root, args, context, resolveInfo
|
||||
if (post) {
|
||||
const sentEmails: string[] = await publishNotifications(
|
||||
context,
|
||||
[notifyUsersOfMention('Post', post.id, idsOfUsers, 'mentioned_in_post', context)],
|
||||
notifyUsersOfMention('Post', post.id, idsOfUsers, 'mentioned_in_post', context),
|
||||
'emailNotificationsMention',
|
||||
)
|
||||
sentEmails.concat(
|
||||
await publishNotifications(
|
||||
context,
|
||||
[notifyFollowingUsers(post.id, groupId, context)],
|
||||
notifyFollowingUsers(post.id, groupId, context),
|
||||
'emailNotificationsFollowingUsers',
|
||||
sentEmails,
|
||||
),
|
||||
)
|
||||
await publishNotifications(
|
||||
context,
|
||||
[notifyGroupMembersOfNewPost(post.id, groupId, context)],
|
||||
notifyGroupMembersOfNewPost(post.id, groupId, context),
|
||||
'emailNotificationsPostInGroup',
|
||||
sentEmails,
|
||||
)
|
||||
@ -164,20 +133,18 @@ const handleContentDataOfComment = async (resolve, root, args, context, resolveI
|
||||
idsOfMentionedUsers = idsOfMentionedUsers.filter((id) => id !== postAuthor.id)
|
||||
const sentEmails: string[] = await publishNotifications(
|
||||
context,
|
||||
[
|
||||
notifyUsersOfMention(
|
||||
'Comment',
|
||||
comment.id,
|
||||
idsOfMentionedUsers,
|
||||
'mentioned_in_comment',
|
||||
context,
|
||||
),
|
||||
],
|
||||
notifyUsersOfMention(
|
||||
'Comment',
|
||||
comment.id,
|
||||
idsOfMentionedUsers,
|
||||
'mentioned_in_comment',
|
||||
context,
|
||||
),
|
||||
'emailNotificationsMention',
|
||||
)
|
||||
await publishNotifications(
|
||||
context,
|
||||
[notifyUsersOfComment('Comment', comment.id, 'commented_on_post', context)],
|
||||
notifyUsersOfComment('Comment', comment.id, 'commented_on_post', context),
|
||||
'emailNotificationsCommentOnObservedPost',
|
||||
sentEmails,
|
||||
)
|
||||
@ -208,17 +175,20 @@ const notifyFollowingUsers = async (postId, groupId, context) => {
|
||||
const cypher = `
|
||||
MATCH (post:Post { id: $postId })<-[:WROTE]-(author:User { id: $userId })<-[:FOLLOWS]-(user:User)
|
||||
OPTIONAL MATCH (post)-[:IN]->(group:Group { id: $groupId })
|
||||
WITH post, author, user, group WHERE group IS NULL OR group.groupType = 'public'
|
||||
OPTIONAL MATCH (user)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
WITH post, author, user, emailAddress, group
|
||||
WHERE group IS NULL OR group.groupType = 'public'
|
||||
MERGE (post)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
SET notification.read = FALSE
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
WITH notification, author, user,
|
||||
WITH notification, author, user, emailAddress.email as email,
|
||||
post {.*, author: properties(author) } AS finalResource
|
||||
RETURN notification {
|
||||
.*,
|
||||
from: finalResource,
|
||||
to: properties(user),
|
||||
email: email,
|
||||
relatedUser: properties(author)
|
||||
}
|
||||
`
|
||||
@ -233,8 +203,7 @@ const notifyFollowingUsers = async (postId, groupId, context) => {
|
||||
return notificationTransactionResponse.records.map((record) => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
const notifications = await writeTxResultPromise
|
||||
return notifications
|
||||
return await writeTxResultPromise
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
@ -247,23 +216,25 @@ const notifyGroupMembersOfNewPost = async (postId, groupId, context) => {
|
||||
const reason = 'post_in_group'
|
||||
const cypher = `
|
||||
MATCH (post:Post { id: $postId })<-[:WROTE]-(author:User { id: $userId })
|
||||
OPTIONAL MATCH (user)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
MATCH (post)-[:IN]->(group:Group { id: $groupId })<-[membership:MEMBER_OF]-(user:User)
|
||||
WHERE NOT membership.role = 'pending'
|
||||
AND NOT (user)-[:MUTED]->(group)
|
||||
AND NOT (user)-[:MUTED]->(author)
|
||||
AND NOT (user)-[:BLOCKED]-(author)
|
||||
AND NOT user.id = $userId
|
||||
WITH post, author, user
|
||||
WITH post, author, user, emailAddress
|
||||
MERGE (post)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
SET notification.read = FALSE
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
WITH notification, author, user,
|
||||
WITH notification, author, user, emailAddress.email as email,
|
||||
post {.*, author: properties(author) } AS finalResource
|
||||
RETURN notification {
|
||||
.*,
|
||||
from: finalResource,
|
||||
to: properties(user),
|
||||
email: email,
|
||||
relatedUser: properties(author)
|
||||
}
|
||||
`
|
||||
@ -278,8 +249,7 @@ const notifyGroupMembersOfNewPost = async (postId, groupId, context) => {
|
||||
return notificationTransactionResponse.records.map((record) => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
const notifications = await writeTxResultPromise
|
||||
return notifications
|
||||
return await writeTxResultPromise
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
@ -295,12 +265,13 @@ const notifyOwnersOfGroup = async (groupId, userId, reason, context) => {
|
||||
WITH owner, group, user, membership
|
||||
MERGE (group)-[notification:NOTIFIED {reason: $reason}]->(owner)
|
||||
WITH group, owner, notification, user, membership
|
||||
OPTIONAL MATCH (owner)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
SET notification.read = FALSE
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
SET notification.relatedUserId = $userId
|
||||
WITH owner, group { __typename: 'Group', .*, myRole: membership.roleInGroup } AS finalGroup, user, notification
|
||||
RETURN notification {.*, from: finalGroup, to: properties(owner), relatedUser: properties(user) }
|
||||
WITH owner, emailAddress.email as email, group { __typename: 'Group', .*, myRole: membership.roleInGroup } AS finalGroup, user, notification
|
||||
RETURN notification {.*, from: finalGroup, to: properties(owner), email: email, relatedUser: properties(user) }
|
||||
`
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
|
||||
@ -312,8 +283,7 @@ const notifyOwnersOfGroup = async (groupId, userId, reason, context) => {
|
||||
return notificationTransactionResponse.records.map((record) => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
const notifications = await writeTxResultPromise
|
||||
return notifications
|
||||
return await writeTxResultPromise
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
@ -327,17 +297,18 @@ const notifyMemberOfGroup = async (groupId, userId, reason, context) => {
|
||||
MATCH (owner:User { id: $ownerId })
|
||||
MATCH (user:User { id: $userId })
|
||||
MATCH (group:Group { id: $groupId })
|
||||
OPTIONAL MATCH (user)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
OPTIONAL MATCH (user)-[membership:MEMBER_OF]->(group)
|
||||
WITH user, group, owner, membership
|
||||
WITH user, group, owner, membership, emailAddress
|
||||
MERGE (group)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
WITH group, user, notification, owner, membership
|
||||
WITH group, user, notification, owner, membership, emailAddress
|
||||
SET notification.read = FALSE
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
SET notification.relatedUserId = $ownerId
|
||||
WITH group { __typename: 'Group', .*, myRole: membership.roleInGroup } AS finalGroup,
|
||||
notification, user, owner
|
||||
RETURN notification {.*, from: finalGroup, to: properties(user), relatedUser: properties(owner) }
|
||||
notification, user, emailAddress.email as email, owner
|
||||
RETURN notification {.*, from: finalGroup, to: properties(user), email: email, relatedUser: properties(owner) }
|
||||
`
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
|
||||
@ -350,8 +321,7 @@ const notifyMemberOfGroup = async (groupId, userId, reason, context) => {
|
||||
return notificationTransactionResponse.records.map((record) => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
const notifications = await writeTxResultPromise
|
||||
return notifications
|
||||
return await writeTxResultPromise
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
@ -371,11 +341,13 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)-[:BLOCKED]-(author)
|
||||
AND NOT (user)-[:MUTED]->(author)
|
||||
OPTIONAL MATCH (user)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
OPTIONAL MATCH (post)-[:IN]->(group:Group)
|
||||
OPTIONAL MATCH (group)<-[membership:MEMBER_OF]-(user)
|
||||
WITH post, author, user, group WHERE group IS NULL OR group.groupType = 'public' OR membership.role IN ['usual', 'admin', 'owner']
|
||||
WITH post, author, user, group, emailAddress
|
||||
WHERE group IS NULL OR group.groupType = 'public' OR membership.role IN ['usual', 'admin', 'owner']
|
||||
MERGE (post)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
WITH post AS resource, notification, user
|
||||
WITH post AS resource, notification, user, emailAddress
|
||||
`
|
||||
break
|
||||
}
|
||||
@ -388,25 +360,27 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
AND NOT (user)-[:BLOCKED]-(postAuthor)
|
||||
AND NOT (user)-[:MUTED]->(commenter)
|
||||
AND NOT (user)-[:MUTED]->(postAuthor)
|
||||
OPTIONAL MATCH (user)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
OPTIONAL MATCH (post)-[:IN]->(group:Group)
|
||||
OPTIONAL MATCH (group)<-[membership:MEMBER_OF]-(user)
|
||||
WITH comment, user, group WHERE group IS NULL OR group.groupType = 'public' OR membership.role IN ['usual', 'admin', 'owner']
|
||||
WITH comment, user, group, emailAddress
|
||||
WHERE group IS NULL OR group.groupType = 'public' OR membership.role IN ['usual', 'admin', 'owner']
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
WITH comment AS resource, notification, user
|
||||
WITH comment AS resource, notification, user, emailAddress
|
||||
`
|
||||
break
|
||||
}
|
||||
}
|
||||
mentionedCypher += `
|
||||
WITH notification, user, resource,
|
||||
WITH notification, user, resource, emailAddress,
|
||||
[(resource)<-[:WROTE]-(author:User) | author {.*}] AS authors,
|
||||
[(resource)-[:COMMENTS]->(post:Post)<-[:WROTE]-(author:User) | post{.*, author: properties(author)} ] AS posts
|
||||
WITH resource, user, notification, authors, posts,
|
||||
WITH resource, user, emailAddress.email as email, notification, authors, posts,
|
||||
resource {.*, __typename: [l IN labels(resource) WHERE l IN ['Post', 'Comment', 'Group']][0], author: authors[0], post: posts[0]} AS finalResource
|
||||
SET notification.read = FALSE
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
RETURN notification {.*, from: finalResource, to: properties(user), relatedUser: properties(user) }
|
||||
RETURN notification {.*, from: finalResource, to: properties(user), email: email, relatedUser: properties(user) }
|
||||
`
|
||||
const session = context.driver.session()
|
||||
const writeTxResultPromise = session.writeTransaction(async (transaction) => {
|
||||
@ -418,8 +392,7 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
return notificationTransactionResponse.records.map((record) => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
const notifications = await writeTxResultPromise
|
||||
return notifications
|
||||
return await writeTxResultPromise
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
} finally {
|
||||
@ -437,18 +410,20 @@ const notifyUsersOfComment = async (label, commentId, reason, context) => {
|
||||
WHERE NOT (observingUser)-[:BLOCKED]-(commenter)
|
||||
AND NOT (observingUser)-[:MUTED]->(commenter)
|
||||
AND NOT observingUser.id = $userId
|
||||
WITH observingUser, post, comment, commenter
|
||||
OPTIONAL MATCH (observingUser)-[:PRIMARY_EMAIL]->(emailAddress:EmailAddress)
|
||||
WITH observingUser, emailAddress, post, comment, commenter
|
||||
MATCH (postAuthor:User)-[:WROTE]->(post)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(observingUser)
|
||||
SET notification.read = FALSE
|
||||
SET notification.createdAt = COALESCE(notification.createdAt, toString(datetime()))
|
||||
SET notification.updatedAt = toString(datetime())
|
||||
WITH notification, observingUser, post, commenter, postAuthor,
|
||||
WITH notification, observingUser, emailAddress.email as email, post, commenter, postAuthor,
|
||||
comment {.*, __typename: labels(comment)[0], author: properties(commenter), post: post {.*, author: properties(postAuthor) } } AS finalResource
|
||||
RETURN notification {
|
||||
.*,
|
||||
from: finalResource,
|
||||
to: properties(observingUser),
|
||||
email: email,
|
||||
relatedUser: properties(commenter)
|
||||
}
|
||||
`,
|
||||
@ -461,8 +436,7 @@ const notifyUsersOfComment = async (label, commentId, reason, context) => {
|
||||
return notificationTransactionResponse.records.map((record) => record.get('notification'))
|
||||
})
|
||||
try {
|
||||
const notifications = await writeTxResultPromise
|
||||
return notifications
|
||||
return await writeTxResultPromise
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user