Skip to content

Commit 966cd34

Browse files
author
vikasrohit
authored
Merge pull request #29 from topcoder-platform/dev
[Production deployment] - Email notifications for connect events
2 parents fb0b1d4 + 80b6257 commit 966cd34

File tree

14 files changed

+722
-398
lines changed

14 files changed

+722
-398
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ workflows:
8282
- "build-dev":
8383
filters:
8484
branches:
85-
only: dev
85+
only: [dev, 'feature/discourseMigration']
8686
- "build-prod":
8787
filters:
8888
branches:

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ The following parameters can be set in config files or in env variables:
2828
- KAFKA_CLIENT_CERT_KEY: Kafka connection private key, optional;
2929
if not provided, then SSL connection is not used, direct insecure connection is used;
3030
if provided, it can be either path to private key file or private key content
31-
31+
- BUS_API_BASE_URL: Bus API url
32+
- BUS_API_AUTH_TOKEN: Bus API auth token
33+
- REPLY_EMAIL_PREFIX: prefix of the genereated reply email address
34+
- REPLY_EMAIL_DOMAIN: email domain
35+
- DEFAULT_REPLY_EMAIL: default reply to email address, for example [email protected]
36+
- MENTION_EMAIL: recipient email used for email.project.post.mention event
3237

3338
Configuration for the connect notification server is at `connect/config.js`.
3439
The following parameters can be set in config files or in env variables:

config/default.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,20 @@ module.exports = {
2727
KAFKA_CLIENT_CERT: process.env.KAFKA_CLIENT_CERT ? process.env.KAFKA_CLIENT_CERT.replace('\\n', '\n') : null,
2828
KAFKA_CLIENT_CERT_KEY: process.env.KAFKA_CLIENT_CERT_KEY ?
2929
process.env.KAFKA_CLIENT_CERT_KEY.replace('\\n', '\n') : null,
30-
API_CONTEXT_PATH: process.env.API_CONTEXT_PATH || '/v5/notifications',
30+
31+
BUS_API_AUTH_TOKEN: process.env.BUS_API_AUTH_TOKEN,
32+
MENTION_EMAIL: process.env.MENTION_EMAIL,
33+
REPLY_EMAIL_PREFIX: process.env.REPLY_EMAIL_PREFIX,
34+
REPLY_EMAIL_DOMAIN: process.env.REPLY_EMAIL_DOMAIN,
35+
36+
TC_ADMIN_TOKEN: process.env.TC_ADMIN_TOKEN,
37+
TC_API_BASE_URL: process.env.TC_API_BASE_URL || 'https://api.topcoder-dev.com',
38+
TC_API_V3_BASE_URL: process.env.TC_API_V3_BASE_URL || 'https://api.topcoder-dev.com/v3',
39+
TC_API_V4_BASE_URL: process.env.TC_API_V4_BASE_URL || 'https://api.topcoder-dev.com/v4',
40+
TC_API_V5_BASE_URL: process.env.TC_API_V5_BASE_URL || 'https://api.topcoder-dev.com/v5',
41+
MESSAGE_API_BASE_URL: process.env.MESSAGE_API_BASE_URL || 'https://api.topcoder-dev.com/v4',
42+
ENABLE_EMAILS: process.env.ENABLE_EMAILS || true,
43+
ENABLE_DEV_MODE: process.env.ENABLE_DEV_MODE || true,
44+
DEV_MODE_EMAIL: process.env.DEV_MODE_EMAIL,
45+
API_CONTEXT_PATH: process.env.API_CONTEXT_PATH || '/v5/notifications',
3146
};

connect/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
module.exports = {
66
TC_API_V3_BASE_URL: process.env.TC_API_V3_BASE_URL || 'https://api.topcoder-dev.com/v3',
77
TC_API_V4_BASE_URL: process.env.TC_API_V4_BASE_URL || 'https://api.topcoder-dev.com/v4',
8+
MESSAGE_API_BASE_URL: process.env.MESSAGE_API_BASE_URL || 'https://api.topcoder-dev.com/v4',
89
// eslint-disable-next-line max-len
910
TC_ADMIN_TOKEN: process.env.TC_ADMIN_TOKEN,
1011

connect/connectNotificationServer.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ const getNotificationsForMentionedUser = (eventConfig, content) => {
6666
}
6767

6868
let notifications = [];
69+
// eslint-disable-next-line
6970
const regexUserHandle = /title=\"@([a-zA-Z0-9-_.{}\[\]]+)\"/g;
70-
let handles=[];
71-
let matches = regexUserHandle.exec(content);
72-
console.log(content)
71+
const handles = [];
72+
let matches = regexUserHandle.exec(content);
7373
while (matches) {
74-
let handle = matches[1].toString();
74+
const handle = matches[1].toString();
7575
notifications.push({
7676
userHandle: handle,
7777
newType: 'notifications.connect.project.post.mention',
@@ -85,13 +85,13 @@ const getNotificationsForMentionedUser = (eventConfig, content) => {
8585
// only one per userHandle
8686
notifications = _.uniqBy(notifications, 'userHandle');
8787

88-
return new Promise((resolve)=>{
89-
service.getUsersByHandle(handles).then((users)=>{
90-
_.map(notifications,(notification)=>{
91-
notification.userId = _.find(users,{handle:notification.userHandle}).userId;
88+
return new Promise((resolve) => {
89+
service.getUsersByHandle(handles).then((users) => {
90+
_.map(notifications, (notification) => {
91+
notification.userId = _.find(users, { handle: notification.userHandle }).userId.toString();
9292
});
9393
resolve(notifications);
94-
})
94+
});
9595
});
9696
};
9797

@@ -307,7 +307,7 @@ const handler = (topic, message, callback) => {
307307
project,
308308
})
309309
)).then((notifications) => {
310-
allNotifications = _.filter(notifications,notification=>notification.userId!=message.initiatorUserId);
310+
allNotifications = _.filter(notifications, notification => notification.userId !== message.initiatorUserId);
311311

312312
// now let's retrieve some additional data
313313

@@ -326,6 +326,7 @@ const handler = (topic, message, callback) => {
326326
if (users.length) {
327327
notification.contents.userHandle = users[0].handle;
328328
notification.contents.userFullName = `${users[0].firstName} ${users[0].lastName}`;
329+
notification.contents.userEmail = users[0].email;
329330
}
330331
});
331332
callback(null, allNotifications);

connect/service.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const getRoleMembers = (roleId) => request
6969
const getUsersById = (ids) => {
7070
const query = _.map(ids, (id) => 'userId:' + id).join(' OR ');
7171
return request
72-
.get(`${config.TC_API_V3_BASE_URL}/members/_search?fields=userId,handle,firstName,lastName&query=${query}`)
72+
.get(`${config.TC_API_V3_BASE_URL}/members/_search?fields=userId,email,handle,firstName,lastName&query=${query}`)
7373
.set('accept', 'application/json')
7474
.set('authorization', `Bearer ${config.TC_ADMIN_TOKEN}`)
7575
.then((res) => {
@@ -78,7 +78,6 @@ const getUsersById = (ids) => {
7878
}
7979

8080
const users = _.get(res, 'body.result.content');
81-
8281
return users;
8382
}).catch((err) => {
8483
const errorDetails = _.get(err, 'response.body.result.content.message');
@@ -126,8 +125,8 @@ const getUsersByHandle = (handles) => {
126125
*
127126
* @return {Promise} promise resolved to topic details
128127
*/
129-
const getTopic = (topicId) => request
130-
.get(`${config.TC_API_V4_BASE_URL}/topics/${topicId}`)
128+
const getTopic = (topicId, logger) => request
129+
.get(`${config.MESSAGE_API_BASE_URL}/topics/${topicId}/read`)
131130
.set('accept', 'application/json')
132131
.set('authorization', `Bearer ${config.TC_ADMIN_TOKEN}`)
133132
.then((res) => {
@@ -137,14 +136,16 @@ const getTopic = (topicId) => request
137136

138137
return _.get(res, 'body.result.content');
139138
}).catch((err) => {
139+
if (logger) {
140+
logger.error(err, `Error while calling ${config.MESSAGE_API_BASE_URL}/topics/${topicId}/read`);
141+
}
140142
const errorDetails = _.get(err, 'response.body.result.content.message');
141143
throw new Error(
142144
`Failed to get topic details of topic id: ${topicId}.` +
143145
(errorDetails ? ' Server response: ' + errorDetails : '')
144146
);
145147
});
146148

147-
148149
module.exports = {
149150
getProject,
150151
getRoleMembers,

deploy.sh

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,19 @@ TC_ADMIN_TOKEN=$(eval "echo \$${ENV}_TC_ADMIN_TOKEN")
4545
LOG_LEVEL=$(eval "echo \$${ENV}_LOG_LEVEL")
4646
PORT=$(eval "echo \$${ENV}_PORT")
4747

48+
# email notifications config
49+
ENABLE_EMAILS=$(eval "echo \$${ENV}_ENABLE_EMAILS")
50+
BUS_API_AUTH_TOKEN=$(eval "echo \$${ENV}_BUS_API_AUTH_TOKEN")
51+
MENTION_EMAIL=$(eval "echo \$${ENV}_MENTION_EMAIL")
52+
REPLY_EMAIL_PREFIX=$(eval "echo \$${ENV}_REPLY_EMAIL_PREFIX")
53+
REPLY_EMAIL_DOMAIN=$(eval "echo \$${ENV}_REPLY_EMAIL_DOMAIN")
54+
ENABLE_DEV_MODE=$(eval "echo \$${ENV}_ENABLE_DEV_MODE")
55+
DEV_MODE_EMAIL=$(eval "echo \$${ENV}_DEV_MODE_EMAIL")
56+
4857
TC_API_V3_BASE_URL=$(eval "echo \$${ENV}_TC_API_V3_BASE_URL")
4958
TC_API_V4_BASE_URL=$(eval "echo \$${ENV}_TC_API_V4_BASE_URL")
59+
TC_API_V5_BASE_URL=$(eval "echo \$${ENV}_TC_API_V5_BASE_URL")
60+
MESSAGE_API_BASE_URL=$(eval "echo \$${ENV}_MESSAGE_API_BASE_URL")
5061

5162
DB_USER=$(eval "echo \$${ENV}_DB_USER")
5263
DB_PASSWORD=$(eval "echo \$${ENV}_DB_PASSWORD")
@@ -159,10 +170,46 @@ make_task_def(){
159170
"name": "TC_API_V4_BASE_URL",
160171
"value": "%s"
161172
},
173+
{
174+
"name": "TC_API_V5_BASE_URL",
175+
"value": "%s"
176+
},
177+
{
178+
"name": "MESSAGE_API_BASE_URL",
179+
"value": "%s"
180+
},
162181
{
163182
"name": "TC_ADMIN_TOKEN",
164183
"value": "%s"
165184
},
185+
{
186+
"name": "ENABLE_EMAILS",
187+
"value": "%s"
188+
},
189+
{
190+
"name": "MENTION_EMAIL",
191+
"value": "%s"
192+
},
193+
{
194+
"name": "REPLY_EMAIL_PREFIX",
195+
"value": "%s"
196+
},
197+
{
198+
"name": "REPLY_EMAIL_DOMAIN",
199+
"value": "%s"
200+
},
201+
{
202+
"name": "ENABLE_DEV_MODE",
203+
"value": "%s"
204+
},
205+
{
206+
"name": "DEV_MODE_EMAIL",
207+
"value": "%s"
208+
},
209+
{
210+
"name": "BUS_API_AUTH_TOKEN",
211+
"value": "%s"
212+
},
166213
{
167214
"name": "LOG_LEVEL",
168215
"value": "%s"
@@ -198,7 +245,7 @@ make_task_def(){
198245
}
199246
]'
200247

201-
task_def=$(printf "$task_template" $AWS_ECS_CONTAINER_NAME $AWS_ACCOUNT_ID $AWS_REGION $AWS_REPOSITORY $TAG $ENV "$KAFKA_CLIENT_CERT" "$KAFKA_CLIENT_CERT_KEY" $KAFKA_GROUP_ID "$KAFKA_TOPIC_IGNORE_PREFIX" $KAFKA_URL $DATABASE_URL $AUTHSECRET "$AUTHDOMAIN" "$JWKSURI" $TC_API_BASE_URL $TC_API_V3_BASE_URL $TC_API_V4_BASE_URL $TC_ADMIN_TOKEN $LOG_LEVEL $VALID_ISSUERS $PORT "$API_CONTEXT_PATH" $AWS_ECS_CLUSTER $AWS_REGION $AWS_ECS_CLUSTER $ENV)
248+
task_def=$(printf "$task_template" $AWS_ECS_CONTAINER_NAME $AWS_ACCOUNT_ID $AWS_REGION $AWS_REPOSITORY $TAG $ENV "$KAFKA_CLIENT_CERT" "$KAFKA_CLIENT_CERT_KEY" $KAFKA_GROUP_ID "$KAFKA_TOPIC_IGNORE_PREFIX" $KAFKA_URL $DATABASE_URL $AUTHSECRET "$AUTHDOMAIN" "$JWKSURI" $TC_API_BASE_URL $TC_API_V3_BASE_URL $TC_API_V4_BASE_URL $TC_API_V5_BASE_URL $MESSAGE_API_BASE_URL $TC_ADMIN_TOKEN $ENABLE_EMAILS $MENTION_EMAIL $REPLY_EMAIL_PREFIX $REPLY_EMAIL_DOMAIN $ENABLE_DEV_MODE $DEV_MODE_EMAIL $BUS_API_AUTH_TOKEN $LOG_LEVEL $VALID_ISSUERS $PORT "$API_CONTEXT_PATH" $AWS_ECS_CLUSTER $AWS_REGION $AWS_ECS_CLUSTER $ENV)
202249
}
203250

204251
register_definition() {

0 commit comments

Comments
 (0)