Skip to content

Commit 0ded256

Browse files
author
sachin-maheshwari
authored
Merge pull request #184 from topcoder-platform/dev
Community Notifications Changes (prod)
2 parents f5b4fc7 + 899da23 commit 0ded256

File tree

7 files changed

+101
-36
lines changed

7 files changed

+101
-36
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ workflows:
102102
context : org-global
103103
filters:
104104
branches:
105-
only: [dev, 'hotfix/V5-API-Standards', 'v5-upgrade', 'feature/bulk-notification']
105+
only: [dev, 'bug/rate-limit']
106106
- "build-prod":
107107
context : org-global
108108
filters:

config/default.js

+29-14
Original file line numberDiff line numberDiff line change
@@ -70,35 +70,50 @@ module.exports = {
7070
{
7171
phaseTypeName: 'Checkpoint Screening',
7272
state: 'START',
73-
roles: ['Copilot', 'Reviewer'],
73+
roles: ['Primary Screener'],
7474
notification:
7575
{
7676
id: 0, /** challengeid or projectid */
7777
name: '', /** challenge name */
7878
group: 'challenge',
79-
title: 'Challenge checkpoint review.',
79+
title: 'Checkpoint Screening phase is now open. You may now begin screening checkpoint submissions.',
8080
},
8181
},
82-
},
83-
],
84-
'submission.notification.create': [
85-
{
86-
handleSubmission:
82+
}, {
83+
handleAutoPilot:
8784
{
88-
resource: 'submission',
89-
roles: ['Copilot', 'Reviewer'],
90-
selfOnly: true /** Submitter only */,
85+
phaseTypeName: 'Checkpoint Review',
86+
state: 'START',
87+
roles: ['Copilot'],
9188
notification:
9289
{
9390
id: 0, /** challengeid or projectid */
9491
name: '', /** challenge name */
95-
group: 'submission',
96-
title: 'A new submission is uploaded.',
92+
group: 'challenge',
93+
title: 'Checkpoint Review is now open. You may now begin reviewing checkpoint submissions.',
9794
},
9895
},
9996
},
10097
],
101-
'admin.notification.broadcast' : [{
98+
// /** 'submission.notification.create': [
99+
// {
100+
// handleSubmission:
101+
// {
102+
// resource: 'submission',
103+
// roles: ['Copilot', 'Reviewer'],
104+
// selfOnly: true /** Submitter only */,
105+
// notification:
106+
// {
107+
// id: 0, /** challengeid or projectid */
108+
// name: '', /** challenge name */
109+
// group: 'submission',
110+
// title: 'A new submission is uploaded.',
111+
// },
112+
// },
113+
// },
114+
// ],
115+
// */ // issue - https://github.com/topcoder-platform/community-app/issues/4108
116+
'admin.notification.broadcast': [{
102117
handleBulkNotification: {}
103118
}
104119
]
@@ -112,5 +127,5 @@ module.exports = {
112127
ENABLE_DEV_MODE: process.env.ENABLE_DEV_MODE ? Boolean(process.env.ENABLE_DEV_MODE) : true,
113128
DEV_MODE_EMAIL: process.env.DEV_MODE_EMAIL,
114129
DEFAULT_REPLY_EMAIL: process.env.DEFAULT_REPLY_EMAIL,
115-
ENABLE_HOOK_BULK_NOTIFICATION : process.env.ENABLE_HOOK_BULK_NOTIFICATION || false,
130+
ENABLE_HOOK_BULK_NOTIFICATION: process.env.ENABLE_HOOK_BULK_NOTIFICATION || false,
116131
};

connect/constants.js

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ module.exports = {
1010

1111
// email service id for settings
1212
SETTINGS_EMAIL_SERVICE_ID: 'email',
13-
SETTINGS_EMAIL_BUNDLING_SERVICE_ID: 'emailBundling',
1413
ACTIVE_USER_STATUSES: ['ACTIVE'],
1514

1615
BUS_API_EVENT: {

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@
5656
"tc-core-library-js": "appirio-tech/tc-core-library-js.git#v2.6.2",
5757
"topcoder-healthcheck-dropin": "^1.0.3",
5858
"urijs": "^1.19.1",
59-
"winston": "^2.2.0"
59+
"winston": "^2.2.0",
60+
"node-cache": "^5.1.0"
6061
},
6162
"engines": {
6263
"node": "6.x"

src/common/broadcastAPIHelper.js

+52-14
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ const _ = require('lodash')
66
const config = require('config')
77
const request = require('superagent')
88
const logger = require('./logger')
9-
const m2mAuth = require('tc-core-library-js').auth.m2m;
10-
const m2m = m2mAuth(config);
9+
const m2mAuth = require('tc-core-library-js').auth.m2m
10+
const NodeCache = require('node-cache')
11+
12+
const m2m = m2mAuth(config)
13+
const cache = new NodeCache()
1114

1215
const logPrefix = "BroadcastAPI: "
16+
const cachedTimeInSeconds = 300 //300 seconds
1317

1418
/**
1519
* Helper Function - get m2m token
@@ -27,6 +31,11 @@ async function getMemberInfo(userId) {
2731
"/members/_search/?" +
2832
`query=userId%3A${userId}` +
2933
`&limit=1`
34+
if (cachedMemberInfo = cache.get(url)) {
35+
return new Promise((resolve, reject) => {
36+
resolve(cachedMemberInfo)
37+
})
38+
}
3039
return new Promise(async function (resolve, reject) {
3140
let memberInfo = []
3241
logger.info(`calling member api ${url} `)
@@ -37,6 +46,7 @@ async function getMemberInfo(userId) {
3746
}
3847
memberInfo = _.get(res, 'body.result.content')
3948
logger.info(`BCA Memeber API: Feteched ${memberInfo.length} record(s) from member api`)
49+
cache.set(url, memberInfo, cachedTimeInSeconds)
4050
resolve(memberInfo)
4151
} catch (err) {
4252
reject(new Error(`BCA Memeber API: Failed to get member ` +
@@ -102,12 +112,16 @@ async function callApi(url, machineToken) {
102112

103113
/**
104114
* Helper function - check Skills and Tracks condition
115+
*
116+
* @param {Integer} userId
117+
* @param {Object} bulkMessage
118+
* @param {Object} m memberInfo
119+
*
105120
*/
106-
async function checkUserSkillsAndTracks(userId, bulkMessage) {
121+
async function checkUserSkillsAndTracks(userId, bulkMessage, m) {
107122
try {
108123
const skills = _.get(bulkMessage, 'recipients.skills')
109124
const tracks = _.get(bulkMessage, 'recipients.tracks')
110-
const m = await getMemberInfo(userId)
111125
let skillMatch, trackMatch = false // default
112126
if (skills && skills.length > 0) {
113127
const ms = _.get(m[0], "skills") // get member skills
@@ -159,25 +173,43 @@ async function checkUserSkillsAndTracks(userId, bulkMessage) {
159173
/**
160174
* Helper function - check group condition
161175
*/
162-
async function checkUserGroup(userId, bulkMessage) {
176+
async function checkUserGroup(userId, bulkMessage, userGroupInfo) {
163177
try {
178+
const excludeGroupSign = '!'
164179
const groups = _.get(bulkMessage, 'recipients.groups')
180+
165181
let flag = false // default
166-
const userGroupInfo = await getUserGroup(userId)
167-
if (groups.length > 0) {
182+
let excludeGroups = []
183+
let includeGroups = []
184+
185+
_.map(groups, (g) => {
186+
if (_.startsWith(g, excludeGroupSign)) {
187+
excludeGroups.push(g)
188+
} else {
189+
includeGroups.push(g)
190+
}
191+
})
192+
193+
if (includeGroups.length > 0) {
168194
_.map(userGroupInfo, (o) => {
169195
// particular group only condition
170-
flag = (_.indexOf(groups, _.get(o, "name")) >= 0) ? true : flag
196+
flag = (_.indexOf(includeGroups, _.get(o, "name")) >= 0) ? true : flag
171197
})
172-
} else { // no group condition means its for `public` no private group
198+
}
199+
if (excludeGroups.length > 0) {
173200
flag = true // default allow for all
174201
_.map(userGroupInfo, (o) => {
175-
// not allow if user is part of any private group
176-
flag = (_.get(o, "privateGroup")) ? false : flag
202+
// not allow if user is part of any private group i.e. excludeGroups
203+
flag = (_.indexOf(excludeGroups, (excludeGroupSign + _.get(o, "name"))) >= 0) ? false : flag
177204
})
178205
logger.info(`public group condition for userId ${userId}` +
179206
` and BC messageId ${bulkMessage.id}, the result is: ${flag}`)
180207
}
208+
209+
if (groups.length === 0) {
210+
flag = true // no restriction
211+
}
212+
181213
return flag
182214
} catch (e) {
183215
throw new Error(`checkUserGroup(): ${e}`)
@@ -189,12 +221,16 @@ async function checkUserGroup(userId, bulkMessage) {
189221
*
190222
* @param {Integer} userId
191223
* @param {Object} bulkMessage
224+
* @param {Object} memberInfo
225+
* @param {Object} userGroupInfo
226+
*
227+
* @return Promise
192228
*/
193-
async function checkBroadcastMessageForUser(userId, bulkMessage) {
229+
async function checkBroadcastMessageForUser(userId, bulkMessage, memberInfo, userGroupInfo) {
194230
return new Promise(function (resolve, reject) {
195231
Promise.all([
196-
checkUserSkillsAndTracks(userId, bulkMessage),
197-
checkUserGroup(userId, bulkMessage),
232+
checkUserSkillsAndTracks(userId, bulkMessage, memberInfo),
233+
checkUserGroup(userId, bulkMessage, userGroupInfo),
198234
]).then((results) => {
199235
let flag = true // TODO need to be sure about default value
200236
_.map(results, (r) => {
@@ -214,4 +250,6 @@ async function checkBroadcastMessageForUser(userId, bulkMessage) {
214250

215251
module.exports = {
216252
checkBroadcastMessageForUser,
253+
getMemberInfo,
254+
getUserGroup,
217255
}

src/common/tcApiHelper.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ function filterChallengeUsers(usersInfo, filterOnRoles = [], filterOnUsers = [])
288288
}
289289
});
290290
logger.info(`Total roles available in this challenge are: ${rolesAvailable.join(',')}`);
291-
return users;
291+
return _.uniqBy(users, 'userId');
292292
}
293293

294294
/**

src/hooks/hookBulkMessage.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,17 @@ async function syncBulkMessageForUser(userId) {
6565
" LEFT OUTER JOIN (SELECT id as refid, bulk_message_id " +
6666
" FROM bulk_message_user_refs AS bmur WHERE bmur.user_id=$1)" +
6767
" AS b ON a.id=b.bulk_message_id WHERE b.refid IS NULL"
68+
let memberInfo = []
69+
let userGroupInfo = []
6870
models.sequelize.query(q, { bind: [userId] })
69-
.then(function (res) {
70-
Promise.all(res[0].map((r) => isBroadCastMessageForUser(userId, r)))
71+
.then(async function (res) {
72+
try {
73+
memberInfo = await api.getMemberInfo(userId)
74+
userGroupInfo = await api.getUserGroup(userId)
75+
} catch (e) {
76+
reject(`${logPrefix} Failed to get member/group info: ${e}`)
77+
}
78+
Promise.all(res[0].map((r) => isBroadCastMessageForUser(userId, r, memberInfo, userGroupInfo)))
7179
.then((results) => {
7280
Promise.all(results.map((o) => {
7381
if (o.result) {
@@ -94,9 +102,13 @@ async function syncBulkMessageForUser(userId) {
94102
* Check if current user in broadcast recipent group
95103
* @param {Integer} userId
96104
* @param {Object} bulkMessage
105+
* @param {Object} memberInfo
106+
* @param {Object} userGroupInfo
107+
*
108+
* @retun promise
97109
*/
98-
async function isBroadCastMessageForUser(userId, bulkMessage) {
99-
return api.checkBroadcastMessageForUser(userId, bulkMessage)
110+
async function isBroadCastMessageForUser(userId, bulkMessage, memberInfo, userGroupInfo) {
111+
return api.checkBroadcastMessageForUser(userId, bulkMessage, memberInfo, userGroupInfo)
100112
}
101113

102114
/**

0 commit comments

Comments
 (0)