@@ -9,6 +9,7 @@ const config = require('./config');
99const notificationServer = require ( '../index' ) ;
1010const _ = require ( 'lodash' ) ;
1111const service = require ( './service' ) ;
12+ const helpers = require ( './helpers' ) ;
1213const { BUS_API_EVENT } = require ( './constants' ) ;
1314const EVENTS = require ( './events-config' ) . EVENTS ;
1415const PROJECT_ROLE_RULES = require ( './events-config' ) . PROJECT_ROLE_RULES ;
@@ -85,27 +86,28 @@ const getNotificationsForMentionedUser = (logger, eventConfig, content) => {
8586 // only one per userHandle
8687 notifications = _ . uniqBy ( notifications , 'userHandle' ) ;
8788
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 } ` ) ;
10197 }
102- //resolves with empty notification which essentially means we are unable to send notification to mentioned user
103- resolve ( [ ] ) ;
10498 } ) ;
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+ }
109111} ;
110112
111113/**
@@ -150,7 +152,7 @@ const getProjectMembersNotifications = (eventConfig, project) => {
150152 return Promise . resolve ( [ ] ) ;
151153 }
152154
153- return new Promise ( ( resolve ) => {
155+ return Promise . promisify ( ( callback ) => {
154156 let notifications = [ ] ;
155157 const projectMembers = _ . get ( project , 'members' , [ ] ) ;
156158
@@ -185,8 +187,8 @@ const getProjectMembersNotifications = (eventConfig, project) => {
185187 // only one per userId
186188 notifications = _ . uniqBy ( notifications , 'userId' ) ;
187189
188- resolve ( notifications ) ;
189- } ) ;
190+ callback ( null , notifications ) ;
191+ } ) ( ) ;
190192} ;
191193
192194/**
@@ -254,6 +256,83 @@ const getNotificationsForTopicStarter = (eventConfig, topicId) => {
254256 } ) ;
255257} ;
256258
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+
257336/**
258337 * Exclude notifications using exclude rules of the event config
259338 *
@@ -281,12 +360,17 @@ const excludeNotifications = (logger, notifications, eventConfig, message, data)
281360 // and after filter out such notifications from the notifications list
282361 // TODO move this promise all together with `_.uniqBy` to one function
283362 // and reuse it here and in `handler` function
363+ const tags = _ . get ( message , 'tags' , [ ] ) ;
364+
284365 return Promise . all ( [
285366 getNotificationsForTopicStarter ( excludeEventConfig , message . topicId ) ,
286367 getNotificationsForUserId ( excludeEventConfig , message . userId ) ,
287368 getNotificationsForMentionedUser ( logger , excludeEventConfig , message . postContent ) ,
288369 getProjectMembersNotifications ( excludeEventConfig , project ) ,
289370 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 ) ,
290374 ] ) . then ( ( notificationsPerSource ) => (
291375 _ . uniqBy ( _ . flatten ( notificationsPerSource ) , 'userId' )
292376 ) ) . then ( ( excludedNotifications ) => {
@@ -332,10 +416,10 @@ const handler = (topic, message, logger, callback) => {
332416 }
333417
334418 // get project details
335- service . getProject ( projectId ) . then ( project => {
419+ return service . getProject ( projectId ) . then ( project => {
336420 let allNotifications = [ ] ;
337421
338- Promise . all ( [
422+ return Promise . all ( [
339423 // the order in this list defines the priority of notification for the SAME user
340424 // upper in this list - higher priority
341425 // NOTE: always add all handles here, they have to check by themselves:
@@ -357,7 +441,7 @@ const handler = (topic, message, logger, callback) => {
357441 project,
358442 } )
359443 ) ) . then ( ( notifications ) => {
360- allNotifications = _ . filter ( notifications , notification => notification . userId !== `${ message . initiatorUserId } ` ) ;
444+ allNotifications = _ . filter ( notifications , n => n . userId && n . userId !== `${ message . initiatorUserId } ` ) ;
361445
362446 if ( eventConfig . includeUsers && message [ eventConfig . includeUsers ] &&
363447 message [ eventConfig . includeUsers ] . length > 0 ) {
0 commit comments