From c8becbccb5ad493cb93d46d57d74396814d39f75 Mon Sep 17 00:00:00 2001 From: negue Date: Mon, 30 Jul 2018 16:11:56 +0200 Subject: [PATCH] prevent multiple notifications (#10524) * WIP - prevent multiple notifications * merge promises to one * update test, iterate each user * revert changes in `groups.js` - filter duplicate notifications in `convertNotificationsToSafeJson` --- .../prevent-multiple-notification.js | 39 +++++++++++++++++++ website/server/models/user/methods.js | 4 +- website/server/models/userNotification.js | 14 ++++++- 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 test/api/v3/integration/notifications/prevent-multiple-notification.js diff --git a/test/api/v3/integration/notifications/prevent-multiple-notification.js b/test/api/v3/integration/notifications/prevent-multiple-notification.js new file mode 100644 index 0000000000..6fcf655d55 --- /dev/null +++ b/test/api/v3/integration/notifications/prevent-multiple-notification.js @@ -0,0 +1,39 @@ +import { + createAndPopulateGroup, +} from '../../../../helpers/api-integration/v3'; + +describe('Prevent multiple notifications', () => { + let partyLeader, partyMembers, party; + + before(async () => { + let { group, groupLeader, members } = await createAndPopulateGroup({ + groupDetails: { + type: 'party', + privacy: 'private', + }, + members: 4, + }); + + party = group; + partyLeader = groupLeader; + partyMembers = members; + }); + + it('does not add the same notification twice', async () => { + const multipleChatMessages = []; + + for (let i = 0; i < 4; i++) { + for (let memberIndex = 0; memberIndex < partyMembers.length; memberIndex++) { + multipleChatMessages.push( + partyMembers[memberIndex].post(`/groups/${party._id}/chat`, { message: `Message ${i}_${memberIndex}`}), + ); + } + } + + await Promise.all(multipleChatMessages); + + const userWithNotification = await partyLeader.get('/user'); + + expect(userWithNotification.notifications.length).to.be.eq(1); + }); +}); diff --git a/website/server/models/user/methods.js b/website/server/models/user/methods.js index 183f881d34..078ae60cab 100644 --- a/website/server/models/user/methods.js +++ b/website/server/models/user/methods.js @@ -7,8 +7,8 @@ import { model as Group, } from '../group'; -import { defaults, map, flatten, flow, compact, uniq, partialRight } from 'lodash'; -import { model as UserNotification } from '../userNotification'; +import {defaults, map, flatten, flow, compact, uniq, partialRight} from 'lodash'; +import {model as UserNotification} from '../userNotification'; import schema from './schema'; import payments from '../../libs/payments/payments'; import amazonPayments from '../../libs/payments/amazon'; diff --git a/website/server/models/userNotification.js b/website/server/models/userNotification.js index 5f0ac2c09f..15b4cec4d6 100644 --- a/website/server/models/userNotification.js +++ b/website/server/models/userNotification.js @@ -2,6 +2,7 @@ import mongoose from 'mongoose'; import baseModel from '../libs/baseModel'; import { v4 as uuid } from 'uuid'; import validator from 'validator'; +import _ from 'lodash'; const NOTIFICATION_TYPES = [ 'DROPS_ENABLED', @@ -74,13 +75,22 @@ export let schema = new Schema({ schema.statics.convertNotificationsToSafeJson = function convertNotificationsToSafeJson (notifications) { if (!notifications) return notifications; - return notifications.filter(n => { + let filteredNotifications = notifications.filter(n => { // Exclude notifications with a nullish value if (!n) return false; // Exclude notifications without an id or a type if (!n.id || !n.type) return false; return true; - }).map(n => { + }); + + filteredNotifications = _.uniqWith(filteredNotifications, (val, otherVal) => { + if (val.type === otherVal.type && val.type === 'NEW_CHAT_MESSAGE') { + return val.data.group.id === otherVal.data.group.id; + } + return false; + }); + + return filteredNotifications.map(n => { return n.toJSON(); }); };