@@ -22,6 +22,7 @@ const PROJECT_ROLE_OWNER = require('./events-config').PROJECT_ROLE_OWNER;
22
22
* @return {Promise } resolves to a list of notifications
23
23
*/
24
24
const getTopCoderMembersNotifications = ( eventConfig ) => {
25
+ // if event doesn't have to be notified to topcoder member, just ignore
25
26
if ( ! eventConfig . topcoderRoles ) {
26
27
return Promise . resolve ( [ ] ) ;
27
28
}
@@ -51,6 +52,49 @@ const getTopCoderMembersNotifications = (eventConfig) => {
51
52
} ) ;
52
53
} ;
53
54
55
+ /**
56
+ * Get notifications for mentioned users
57
+ *
58
+ * @param {Object } eventConfig event configuration
59
+ * @param {Object } message content
60
+ *
61
+ * @return {Promise } resolves to a list of notifications
62
+ */
63
+ const getNotificationsForMentionedUser = ( eventConfig , content ) => {
64
+ if ( ! eventConfig . toMentionedUsers ) {
65
+ return Promise . resolve ( [ ] ) ;
66
+ }
67
+
68
+ let notifications = [ ] ;
69
+ const regexUserHandle = / t i t l e = \" @ ( [ a - z A - Z 0 - 9 - _ .{ } \[ \] ] + ) \" / g;
70
+ let handles = [ ] ;
71
+ let matches = regexUserHandle . exec ( content ) ;
72
+ console . log ( content )
73
+ while ( matches ) {
74
+ let handle = matches [ 1 ] . toString ( ) ;
75
+ notifications . push ( {
76
+ userHandle : handle ,
77
+ newType : 'notifications.connect.project.post.mention' ,
78
+ contents : {
79
+ toUserHandle : true ,
80
+ } ,
81
+ } ) ;
82
+ matches = regexUserHandle . exec ( content ) ;
83
+ handles . push ( handle ) ;
84
+ }
85
+ // only one per userHandle
86
+ notifications = _ . uniqBy ( notifications , 'userHandle' ) ;
87
+
88
+ return new Promise ( ( resolve ) => {
89
+ service . getUsersByHandle ( handles ) . then ( ( users ) => {
90
+ _ . map ( notifications , ( notification ) => {
91
+ notification . userId = _ . find ( users , { handle :notification . userHandle } ) . userId ;
92
+ } ) ;
93
+ resolve ( notifications ) ;
94
+ } )
95
+ } ) ;
96
+ } ;
97
+
54
98
/**
55
99
* Get project members notifications
56
100
*
@@ -59,8 +103,13 @@ const getTopCoderMembersNotifications = (eventConfig) => {
59
103
*
60
104
* @return {Promise } resolves to a list of notifications
61
105
*/
62
- const getProjectMembersNotifications = ( eventConfig , project ) => (
63
- new Promise ( ( resolve ) => {
106
+ const getProjectMembersNotifications = ( eventConfig , project ) => {
107
+ // if event doesn't have to be notified to project member, just ignore
108
+ if ( ! eventConfig . projectRoles ) {
109
+ return Promise . resolve ( [ ] ) ;
110
+ }
111
+
112
+ return new Promise ( ( resolve ) => {
64
113
let notifications = [ ] ;
65
114
const projectMembers = _ . get ( project , 'members' , [ ] ) ;
66
115
@@ -96,8 +145,8 @@ const getProjectMembersNotifications = (eventConfig, project) => (
96
145
notifications = _ . uniqBy ( notifications , 'userId' ) ;
97
146
98
147
resolve ( notifications ) ;
99
- } )
100
- ) ;
148
+ } ) ;
149
+ } ;
101
150
102
151
/**
103
152
* Get notifications for users obtained from userId
@@ -147,12 +196,64 @@ const getNotificationsForTopicStarter = (eventConfig, topicId) => {
147
196
return Promise . reject ( new Error ( 'Missing topicId in the event message.' ) ) ;
148
197
}
149
198
150
- return service . getTopic ( topicId ) . then ( ( topic ) => ( {
151
- userId : topic . userId . toString ( ) ,
152
- contents : {
153
- toTopicStarter : true ,
154
- } ,
155
- } ) ) ;
199
+ return service . getTopic ( topicId ) . then ( ( topic ) => {
200
+ const userId = topic . userId . toString ( ) ;
201
+
202
+ // special case: if topic created by CoderBot, don't send notification to him
203
+ if ( userId === 'CoderBot' ) {
204
+ return [ ] ;
205
+ }
206
+
207
+ return [ {
208
+ userId,
209
+ contents : {
210
+ toTopicStarter : true ,
211
+ } ,
212
+ } ] ;
213
+ } ) ;
214
+ } ;
215
+
216
+ /**
217
+ * Exclude notifications using exclude rules of the event config
218
+ *
219
+ * @param {Array } notifications notifications list
220
+ * @param {Object } eventConfig event configuration
221
+ * @param {Object } message message
222
+ * @param {Object } data any additional data which is retrieved once
223
+ *
224
+ * @returns {Promise } resolves to the list of filtered notifications
225
+ */
226
+ const excludeNotifications = ( notifications , eventConfig , message , data ) => {
227
+ // if there are no rules to exclude notifications, just return all of them untouched
228
+ if ( ! eventConfig . exclude ) {
229
+ return Promise . resolve ( notifications ) ;
230
+ }
231
+
232
+ const { project } = data ;
233
+ // create event config using rules to exclude notifications
234
+ const excludeEventConfig = Object . assign ( {
235
+ type : eventConfig . type ,
236
+ } , eventConfig . exclude ) ;
237
+
238
+ // get notifications using rules for exclude notifications
239
+ // and after filter out such notifications from the notifications list
240
+ // TODO move this promise all together with `_.uniqBy` to one function
241
+ // and reuse it here and in `handler` function
242
+ return Promise . all ( [
243
+ getNotificationsForTopicStarter ( excludeEventConfig , message . topicId ) ,
244
+ getNotificationsForUserId ( excludeEventConfig , message . userId ) ,
245
+ getProjectMembersNotifications ( excludeEventConfig , project ) ,
246
+ getTopCoderMembersNotifications ( excludeEventConfig ) ,
247
+ ] ) . then ( ( notificationsPerSource ) => (
248
+ _ . uniqBy ( _ . flatten ( notificationsPerSource ) , 'userId' )
249
+ ) ) . then ( ( excludedNotifications ) => {
250
+ const excludedUserIds = _ . map ( excludedNotifications , 'userId' ) ;
251
+ const filteredNotifications = notifications . filter ( ( notification ) => (
252
+ ! _ . includes ( excludedUserIds , notification . userId )
253
+ ) ) ;
254
+
255
+ return filteredNotifications ;
256
+ } ) ;
156
257
} ;
157
258
158
259
// set configuration for the server, see ../config/default.js for available config parameters
@@ -194,18 +295,23 @@ const handler = (topic, message, callback) => {
194
295
// - check that event has everything required or throw error
195
296
getNotificationsForTopicStarter ( eventConfig , message . topicId ) ,
196
297
getNotificationsForUserId ( eventConfig , message . userId ) ,
298
+ message . postContent ? getNotificationsForMentionedUser ( eventConfig , message . postContent ) : Promise . resolve ( [ ] ) ,
197
299
getProjectMembersNotifications ( eventConfig , project ) ,
198
300
getTopCoderMembersNotifications ( eventConfig ) ,
199
301
] ) . then ( ( notificationsPerSource ) => (
200
302
// first found notification for one user will be send, the rest ignored
201
303
// NOTE all userId has to be string
202
304
_ . uniqBy ( _ . flatten ( notificationsPerSource ) , 'userId' )
305
+ ) ) . then ( ( notifications ) => (
306
+ excludeNotifications ( notifications , eventConfig , message , {
307
+ project,
308
+ } )
203
309
) ) . then ( ( notifications ) => {
204
- allNotifications = notifications ;
310
+ allNotifications = _ . filter ( notifications , notification => notification . userId != message . initiatorUserId ) ;
205
311
206
312
// now let's retrieve some additional data
207
313
208
- // if message has userId such messages will likely need userHandle
314
+ // if message has userId such messages will likely need userHandle and user full name
209
315
// so let's get it
210
316
if ( message . userId ) {
211
317
const ids = [ message . userId ] ;
@@ -214,10 +320,12 @@ const handler = (topic, message, callback) => {
214
320
return [ ] ;
215
321
} ) . then ( ( users ) => {
216
322
_ . map ( allNotifications , ( notification ) => {
323
+ notification . version = eventConfig . version ;
217
324
notification . contents . projectName = project . name ;
218
325
// if found a user then add user handle
219
326
if ( users . length ) {
220
327
notification . contents . userHandle = users [ 0 ] . handle ;
328
+ notification . contents . userFullName = `${ users [ 0 ] . firstName } ${ users [ 0 ] . lastName } ` ;
221
329
}
222
330
} ) ;
223
331
callback ( null , allNotifications ) ;
0 commit comments