mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-12 23:35:58 +00:00
feat(backend): do not notify blocked or muted users (#8403)
* no more notifications of blocked or muted users in groups * do not receive notifications on mentions or observed posts from muted users
This commit is contained in:
parent
de4325cb50
commit
89b0fa7a51
@ -118,7 +118,7 @@ afterAll(async () => {
|
||||
})
|
||||
|
||||
describe('notify group members of new posts in group', () => {
|
||||
beforeAll(async () => {
|
||||
beforeEach(async () => {
|
||||
postAuthor = await Factory.build(
|
||||
'user',
|
||||
{
|
||||
@ -193,8 +193,12 @@ describe('notify group members of new posts in group', () => {
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await cleanDatabase()
|
||||
})
|
||||
|
||||
describe('group owner posts in group', () => {
|
||||
beforeAll(async () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks()
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await markAllAsRead()
|
||||
@ -275,29 +279,15 @@ describe('notify group members of new posts in group', () => {
|
||||
})
|
||||
|
||||
describe('group member mutes group', () => {
|
||||
it('sets the muted status correctly', async () => {
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: muteGroupMutation,
|
||||
variables: {
|
||||
groupId: 'g-1',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
muteGroup: {
|
||||
isMutedByMe: true,
|
||||
},
|
||||
await mutate({
|
||||
mutation: muteGroupMutation,
|
||||
variables: {
|
||||
groupId: 'g-1',
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('sends NO notification when another post is posted', async () => {
|
||||
jest.clearAllMocks()
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await markAllAsRead()
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: createPostMutation,
|
||||
@ -308,7 +298,9 @@ describe('notify group members of new posts in group', () => {
|
||||
groupId: 'g-1',
|
||||
},
|
||||
})
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
})
|
||||
|
||||
it('sends NO notification when another post is posted', async () => {
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
@ -329,30 +321,18 @@ describe('notify group members of new posts in group', () => {
|
||||
})
|
||||
|
||||
describe('group member unmutes group again but disables email', () => {
|
||||
beforeAll(async () => {
|
||||
beforeEach(async () => {
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await mutate({
|
||||
mutation: unmuteGroupMutation,
|
||||
variables: {
|
||||
groupId: 'g-1',
|
||||
},
|
||||
})
|
||||
jest.clearAllMocks()
|
||||
await groupMember.update({ emailNotificationsPostInGroup: false })
|
||||
})
|
||||
|
||||
it('sets the muted status correctly', async () => {
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: unmuteGroupMutation,
|
||||
variables: {
|
||||
groupId: 'g-1',
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
unmuteGroup: {
|
||||
isMutedByMe: false,
|
||||
},
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('sends notification when another post is posted', async () => {
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await markAllAsRead()
|
||||
@ -396,5 +376,85 @@ describe('notify group members of new posts in group', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('group member blocks author', () => {
|
||||
beforeEach(async () => {
|
||||
await groupMember.relateTo(postAuthor, 'blocked')
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await markAllAsRead()
|
||||
jest.clearAllMocks()
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: createPostMutation,
|
||||
variables: {
|
||||
id: 'post-1',
|
||||
title: 'This is another post in the group',
|
||||
content: 'This is the content of another post in the group',
|
||||
groupId: 'g-1',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('sends no notification to the user', async () => {
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
variables: {
|
||||
read: false,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
notifications: [],
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('sends NO email', () => {
|
||||
expect(sendMailMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('group member mutes author', () => {
|
||||
beforeEach(async () => {
|
||||
await groupMember.relateTo(postAuthor, 'muted')
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await markAllAsRead()
|
||||
jest.clearAllMocks()
|
||||
authenticatedUser = await postAuthor.toJson()
|
||||
await mutate({
|
||||
mutation: createPostMutation,
|
||||
variables: {
|
||||
id: 'post-1',
|
||||
title: 'This is another post in the group',
|
||||
content: 'This is the content of another post in the group',
|
||||
groupId: 'g-1',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('sends no notification to the user', async () => {
|
||||
authenticatedUser = await groupMember.toJson()
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
variables: {
|
||||
read: false,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
notifications: [],
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('sends NO email', () => {
|
||||
expect(sendMailMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -294,6 +294,25 @@ describe('notifications', () => {
|
||||
).resolves.toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('if I have muted the comment author', () => {
|
||||
it('sends me no notification', async () => {
|
||||
await notifiedUser.relateTo(commentAuthor, 'muted')
|
||||
await createCommentOnPostAction()
|
||||
const expected = expect.objectContaining({
|
||||
data: { notifications: [] },
|
||||
})
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
variables: {
|
||||
read: false,
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('commenter is me', () => {
|
||||
@ -581,6 +600,48 @@ describe('notifications', () => {
|
||||
expect(pubsubSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('but the author of the post muted me', () => {
|
||||
beforeEach(async () => {
|
||||
await postAuthor.relateTo(notifiedUser, 'muted')
|
||||
})
|
||||
|
||||
it('sends me a notification', async () => {
|
||||
await createPostAction()
|
||||
const expected = expect.objectContaining({
|
||||
data: {
|
||||
notifications: [
|
||||
{
|
||||
createdAt: expect.any(String),
|
||||
from: {
|
||||
__typename: 'Post',
|
||||
content:
|
||||
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?',
|
||||
id: 'p47',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_post',
|
||||
relatedUser: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
variables: {
|
||||
read: false,
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual(expected)
|
||||
})
|
||||
|
||||
it('publishes `NOTIFICATION_ADDED`', async () => {
|
||||
await createPostAction()
|
||||
expect(pubsubSpy).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('mentions me in a comment', () => {
|
||||
@ -736,6 +797,72 @@ describe('notifications', () => {
|
||||
expect(pubsubSpy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('but the author of the post muted me', () => {
|
||||
beforeEach(async () => {
|
||||
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',
|
||||
{
|
||||
id: 'commentAuthor',
|
||||
name: 'Mrs Comment',
|
||||
slug: 'mrs-comment',
|
||||
},
|
||||
{
|
||||
email: 'comment-author@example.org',
|
||||
password: '1234',
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('sends me a notification', async () => {
|
||||
await createCommentOnPostAction()
|
||||
await expect(
|
||||
query({
|
||||
query: notificationQuery,
|
||||
variables: {
|
||||
read: false,
|
||||
},
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
data: {
|
||||
notifications: [
|
||||
{
|
||||
createdAt: expect.any(String),
|
||||
from: {
|
||||
__typename: 'Comment',
|
||||
content:
|
||||
'One mention about me with <a data-mention-id="you" class="mention" href="/profile/you" target="_blank">@al-capone</a>.',
|
||||
id: 'c47',
|
||||
},
|
||||
read: false,
|
||||
reason: 'mentioned_in_comment',
|
||||
relatedUser: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
errors: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
it('publishes `NOTIFICATION_ADDED` to authenticated user and me', async () => {
|
||||
await createCommentOnPostAction()
|
||||
expect(pubsubSpy).toHaveBeenCalledWith(
|
||||
'NOTIFICATION_ADDED',
|
||||
expect.objectContaining({
|
||||
notificationAdded: expect.objectContaining({
|
||||
reason: 'commented_on_post',
|
||||
to: expect.objectContaining({
|
||||
id: 'postAuthor', // that's expected, it's not me but the post author
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
)
|
||||
expect(pubsubSpy).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -245,6 +245,8 @@ const notifyGroupMembersOfNewPost = async (postId, groupId, context) => {
|
||||
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
|
||||
MERGE (post)-[notification:NOTIFIED {reason: $reason}]->(user)
|
||||
@ -360,7 +362,10 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
case 'mentioned_in_post': {
|
||||
mentionedCypher = `
|
||||
MATCH (post: Post { id: $id })<-[:WROTE]-(author: User)
|
||||
MATCH (user: User) WHERE user.id in $idsOfUsers AND NOT (user)-[:BLOCKED]-(author)
|
||||
MATCH (user: User)
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)-[:BLOCKED]-(author)
|
||||
AND NOT (user)-[:MUTED]->(author)
|
||||
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']
|
||||
@ -376,6 +381,8 @@ const notifyUsersOfMention = async (label, id, idsOfUsers, reason, context) => {
|
||||
WHERE user.id in $idsOfUsers
|
||||
AND NOT (user)-[:BLOCKED]-(commenter)
|
||||
AND NOT (user)-[:BLOCKED]-(postAuthor)
|
||||
AND NOT (user)-[:MUTED]->(commenter)
|
||||
AND NOT (user)-[:MUTED]->(postAuthor)
|
||||
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']
|
||||
@ -422,7 +429,9 @@ const notifyUsersOfComment = async (label, commentId, reason, context) => {
|
||||
const notificationTransactionResponse = await transaction.run(
|
||||
`
|
||||
MATCH (observingUser:User)-[:OBSERVES { active: true }]->(post:Post)<-[:COMMENTS]-(comment:Comment { id: $commentId })<-[:WROTE]-(commenter:User)
|
||||
WHERE NOT (observingUser)-[:BLOCKED]-(commenter) AND NOT observingUser.id = $userId
|
||||
WHERE NOT (observingUser)-[:BLOCKED]-(commenter)
|
||||
AND NOT (observingUser)-[:MUTED]->(commenter)
|
||||
AND NOT observingUser.id = $userId
|
||||
WITH observingUser, post, comment, commenter
|
||||
MATCH (postAuthor:User)-[:WROTE]->(post)
|
||||
MERGE (comment)-[notification:NOTIFIED {reason: $reason}]->(observingUser)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user