@@ -9,6 +9,7 @@ const config = require('./config');
9
9
const notificationServer = require ( '../index' ) ;
10
10
const _ = require ( 'lodash' ) ;
11
11
const service = require ( './service' ) ;
12
+ const helpers = require ( './helpers' ) ;
12
13
const { BUS_API_EVENT } = require ( './constants' ) ;
13
14
const EVENTS = require ( './events-config' ) . EVENTS ;
14
15
const PROJECT_ROLE_RULES = require ( './events-config' ) . PROJECT_ROLE_RULES ;
@@ -85,27 +86,28 @@ const getNotificationsForMentionedUser = (logger, eventConfig, content) => {
85
86
// only one per userHandle
86
87
notifications = _ . uniqBy ( notifications , 'userHandle' ) ;
87
88
88
- return new Promise ( ( resolve , reject ) => { // eslint-disable-line no-unused-vars
89
- const handles = _ . map ( notifications , 'userHandle' ) ;
90
- if ( handles . length > 0 ) {
91
- service . getUsersByHandle ( handles ) . then ( ( users ) => {
92
- _ . forEach ( notifications , ( notification ) => {
93
- const mentionedUser = _ . find ( users , { handle : notification . userHandle } ) ;
94
- notification . userId = mentionedUser ? mentionedUser . userId . toString ( ) : notification . userHandle ;
95
- } ) ;
96
- resolve ( notifications ) ;
97
- } ) . catch ( ( error ) => {
98
- if ( logger ) {
99
- logger . error ( error ) ;
100
- logger . info ( 'Unable to send notification to mentioned user' )
89
+ const handles = _ . map ( notifications , 'userHandle' ) ;
90
+ if ( handles . length > 0 ) {
91
+ return service . getUsersByHandle ( handles ) . then ( ( users ) => {
92
+ _ . forEach ( notifications , ( notification ) => {
93
+ const mentionedUser = _ . find ( users , { handle : notification . userHandle } ) ;
94
+ notification . userId = mentionedUser ? mentionedUser . userId . toString ( ) : null ;
95
+ if ( ! notification . userId && logger ) { // such notifications would be discarded later after aggregation
96
+ logger . info ( `Unable to find user with handle ${ notification . userHandle } ` ) ;
101
97
}
102
- //resolves with empty notification which essentially means we are unable to send notification to mentioned user
103
- resolve ( [ ] ) ;
104
98
} ) ;
105
- } else {
106
- resolve ( [ ] ) ;
107
- }
108
- } ) ;
99
+ return Promise . resolve ( notifications ) ;
100
+ } ) . catch ( ( error ) => {
101
+ if ( logger ) {
102
+ logger . error ( error ) ;
103
+ logger . info ( 'Unable to send notification to mentioned user' ) ;
104
+ }
105
+ //resolves with empty notification which essentially means we are unable to send notification to mentioned user
106
+ return Promise . resolve ( [ ] ) ;
107
+ } ) ;
108
+ } else {
109
+ return Promise . resolve ( [ ] ) ;
110
+ }
109
111
} ;
110
112
111
113
/**
@@ -150,7 +152,7 @@ const getProjectMembersNotifications = (eventConfig, project) => {
150
152
return Promise . resolve ( [ ] ) ;
151
153
}
152
154
153
- return new Promise ( ( resolve ) => {
155
+ return Promise . promisify ( ( callback ) => {
154
156
let notifications = [ ] ;
155
157
const projectMembers = _ . get ( project , 'members' , [ ] ) ;
156
158
@@ -185,8 +187,8 @@ const getProjectMembersNotifications = (eventConfig, project) => {
185
187
// only one per userId
186
188
notifications = _ . uniqBy ( notifications , 'userId' ) ;
187
189
188
- resolve ( notifications ) ;
189
- } ) ;
190
+ callback ( null , notifications ) ;
191
+ } ) ( ) ;
190
192
} ;
191
193
192
194
/**
@@ -254,6 +256,83 @@ const getNotificationsForTopicStarter = (eventConfig, topicId) => {
254
256
} ) ;
255
257
} ;
256
258
259
+ /**
260
+ * Filter members by project roles
261
+ *
262
+ * @params {Array} List of project roles
263
+ * @params {Array} List of project members
264
+ *
265
+ * @returns {Array } List of objects with user ids
266
+ */
267
+ const filterMembersByRoles = ( roles , members ) => {
268
+ let result = [ ] ;
269
+
270
+ roles . forEach ( projectRole => {
271
+ result = result . concat (
272
+ _ . filter ( members , PROJECT_ROLE_RULES [ projectRole ] )
273
+ . map ( projectMember => ( {
274
+ userId : projectMember . userId . toString ( ) ,
275
+ } ) )
276
+ ) ;
277
+ } ) ;
278
+
279
+ return result ;
280
+ } ;
281
+
282
+ /**
283
+ * Exclude private posts notification
284
+ *
285
+ * @param {Object } eventConfig event configuration
286
+ * @param {Object } project project details
287
+ * @param {Array } tags list of message tags
288
+ *
289
+ * @return {Promise } resolves to a list of notifications
290
+ */
291
+ const getExcludedPrivatePostNotifications = ( eventConfig , project , tags ) => {
292
+ // skip if message is not private or exclusion rule is not configured
293
+ if ( ! _ . includes ( tags , 'MESSAGES' ) || ! eventConfig . privatePostsForProjectRoles ) {
294
+ return Promise . resolve ( [ ] ) ;
295
+ }
296
+
297
+ const members = _ . get ( project , 'members' , [ ] ) ;
298
+ const notifications = filterMembersByRoles ( eventConfig . privatePostsForProjectRoles , members ) ;
299
+
300
+ return Promise . resolve ( notifications ) ;
301
+ } ;
302
+
303
+ /**
304
+ * Exclude notifications about posts inside draft phases
305
+ *
306
+ * @param {Object } eventConfig event configuration
307
+ * @param {Object } project project details
308
+ * @param {Array } tags list of message tags
309
+ *
310
+ * @return {Promise } resolves to a list of notifications
311
+ */
312
+ const getExcludeDraftPhasesNotifications = ( eventConfig , project , tags ) => {
313
+ // skip is no exclusion rule is configured
314
+ if ( ! eventConfig . draftPhasesForProjectRoles ) {
315
+ return Promise . resolve ( [ ] ) ;
316
+ }
317
+
318
+ const phaseId = helpers . extractPhaseId ( tags ) ;
319
+ // skip if it is not phase notification
320
+ if ( ! phaseId ) {
321
+ return Promise . resolve ( [ ] ) ;
322
+ }
323
+
324
+ // exclude all user with configured roles if phase is in draft state
325
+ return service . getPhase ( project . id , phaseId )
326
+ . then ( ( phase ) => {
327
+ if ( phase . status === 'draft' ) {
328
+ const members = _ . get ( project , 'members' , [ ] ) ;
329
+ const notifications = filterMembersByRoles ( eventConfig . draftPhasesForProjectRoles , members ) ;
330
+
331
+ return Promise . resolve ( notifications ) ;
332
+ }
333
+ } ) ;
334
+ } ;
335
+
257
336
/**
258
337
* Exclude notifications using exclude rules of the event config
259
338
*
@@ -281,12 +360,17 @@ const excludeNotifications = (logger, notifications, eventConfig, message, data)
281
360
// and after filter out such notifications from the notifications list
282
361
// TODO move this promise all together with `_.uniqBy` to one function
283
362
// and reuse it here and in `handler` function
363
+ const tags = _ . get ( message , 'tags' , [ ] ) ;
364
+
284
365
return Promise . all ( [
285
366
getNotificationsForTopicStarter ( excludeEventConfig , message . topicId ) ,
286
367
getNotificationsForUserId ( excludeEventConfig , message . userId ) ,
287
368
getNotificationsForMentionedUser ( logger , excludeEventConfig , message . postContent ) ,
288
369
getProjectMembersNotifications ( excludeEventConfig , project ) ,
289
370
getTopCoderMembersNotifications ( excludeEventConfig ) ,
371
+ // these are special exclude rules which are only working for excluding notifications but not including
372
+ getExcludedPrivatePostNotifications ( excludeEventConfig , project , tags ) ,
373
+ getExcludeDraftPhasesNotifications ( excludeEventConfig , project , tags ) ,
290
374
] ) . then ( ( notificationsPerSource ) => (
291
375
_ . uniqBy ( _ . flatten ( notificationsPerSource ) , 'userId' )
292
376
) ) . then ( ( excludedNotifications ) => {
@@ -332,10 +416,10 @@ const handler = (topic, message, logger, callback) => {
332
416
}
333
417
334
418
// get project details
335
- service . getProject ( projectId ) . then ( project => {
419
+ return service . getProject ( projectId ) . then ( project => {
336
420
let allNotifications = [ ] ;
337
421
338
- Promise . all ( [
422
+ return Promise . all ( [
339
423
// the order in this list defines the priority of notification for the SAME user
340
424
// upper in this list - higher priority
341
425
// NOTE: always add all handles here, they have to check by themselves:
@@ -357,7 +441,7 @@ const handler = (topic, message, logger, callback) => {
357
441
project,
358
442
} )
359
443
) ) . then ( ( notifications ) => {
360
- allNotifications = _ . filter ( notifications , notification => notification . userId !== `${ message . initiatorUserId } ` ) ;
444
+ allNotifications = _ . filter ( notifications , n => n . userId && n . userId !== `${ message . initiatorUserId } ` ) ;
361
445
362
446
if ( eventConfig . includeUsers && message [ eventConfig . includeUsers ] &&
363
447
message [ eventConfig . includeUsers ] . length > 0 ) {
0 commit comments