Skip to content

Email templates rendering update #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Sep 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d625eee
- Enable email notifications for all event types.
architectt1 Jul 24, 2018
fd93a79
update email template rendering
gondzo Sep 3, 2018
0b30397
update config
gondzo Sep 3, 2018
2d8cd40
deploy feature branch
gondzo Sep 3, 2018
43d51d5
add template version parameter
gondzo Sep 3, 2018
5d91a73
Merge branch 'architectt1-feature/emailTemplatesClean' of https://git…
gondzo Sep 3, 2018
dd3428f
fix lint
gondzo Sep 3, 2018
ebf68db
fix missing fields
gondzo Sep 6, 2018
7ec6d52
email templates
gondzo Sep 6, 2018
5f5f859
Merge branch 'dev' into architectt1-feature/emailTemplatesClean
Sep 6, 2018
cabfa3d
Picking the CONNECT_URL from CIRCLE CI env variables
Sep 7, 2018
a166ecc
Added templates for project plan events
Sep 7, 2018
4e9dcd5
fixed syntax error in deploy script
Sep 7, 2018
743056c
fixed syntax error in deploy script
Sep 7, 2018
b6bcd5e
bundled event constant for new email template
Sep 11, 2018
13d172a
Fixed topic for phase progress update event
Sep 12, 2018
b8fc890
Logging error when we are not able to find email from member api. So …
Sep 12, 2018
1ad01ba
Some detailed error logging for determining the issue with stale kafk…
Sep 13, 2018
4e614d7
Updated project plan email template
Sep 13, 2018
402e67a
Handling missing members gracefully
Sep 13, 2018
0fd0062
Testing bundling per notification group
Sep 18, 2018
8c1d2c5
Trying bundling per event group
Sep 18, 2018
58e96c5
fix for reading correct settings
Sep 18, 2018
e4f1f5e
Github issue#2505, Default bundling to 24 hours for all users
Sep 19, 2018
bb09caf
debug log
Sep 19, 2018
075e3b6
Updated the plan modified event constant
Sep 19, 2018
eb5dbe4
Clean handling of cdderbot initiated messages, they would be ignored …
Sep 24, 2018
8f6e857
possible fix for silent kill of the notifications kafka consumer
Sep 24, 2018
a090b60
Handling bundle period settings per notification group.
Sep 26, 2018
1da730b
Supporting every other day schedule
Sep 26, 2018
56aa84a
Handling ‘’ empty string for bundlePeriod
Sep 27, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ workflows:
- "build-dev":
filters:
branches:
only: [dev]
only: [dev, architectt1-feature/emailTemplatesClean]
- "build-prod":
filters:
branches:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules
log.txt
.DS_Store
dist
src/emails/**/*.css
3 changes: 3 additions & 0 deletions connect/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
ADMINISTRATOR_ROLE_ID: 1,
// id of the BOT user which creates post with various events in discussions
TCWEBSERVICE_ID: process.env.TCWEBSERVICE_ID || '22838965',
CODERBOT_USER_ID: process.env.CODERBOT_USER_ID || 'CoderBot',

// Configuration for generating machine to machine auth0 token.
// The token will be used for calling another internal API.
Expand All @@ -39,4 +40,6 @@ module.exports = {
REPLY_EMAIL_DOMAIN: process.env.REPLY_EMAIL_DOMAIN,
REPLY_EMAIL_FROM: process.env.REPLY_EMAIL_FROM,
DEFAULT_REPLY_EMAIL: process.env.DEFAULT_REPLY_EMAIL,

CONNECT_URL: process.env.CONNECT_URL || 'https://connect.topcoder-dev.com',
};
21 changes: 15 additions & 6 deletions connect/connectNotificationServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const getNotificationsForMentionedUser = (eventConfig, content) => {
const handle = matches[1] ? matches[1].toString() : matches[2].toString();
notifications.push({
userHandle: handle,
newType: BUS_API_EVENT.CONNECT.MENTIONED_IN_POST,
newType: BUS_API_EVENT.CONNECT.POST.MENTION,
contents: {
toUserHandle: true,
},
Expand All @@ -85,12 +85,13 @@ const getNotificationsForMentionedUser = (eventConfig, content) => {
// only one per userHandle
notifications = _.uniqBy(notifications, 'userHandle');

return new Promise((resolve) => {
return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
const handles = _.map(notifications, 'userHandle');
if (handles.length > 0) {
service.getUsersByHandle(handles).then((users) => {
_.forEach(notifications, (notification) => {
notification.userId = _.find(users, { handle: notification.userHandle }).userId.toString();
const mentionedUser = _.find(users, { handle: notification.userHandle });
notification.userId = mentionedUser ? mentionedUser.userId.toString() : notification.userHandle;
});
resolve(notifications);
});
Expand Down Expand Up @@ -271,8 +272,9 @@ notificationServer.setConfig({ LOG_LEVEL: 'debug' });
// it is defined as: function(topic, message, callback),
// the topic is topic name,
// the message is JSON event message,
// logger object used to log in parent thread
// the callback is function(error, userIds), where userIds is an array of user ids to receive notifications
const handler = (topic, message, callback) => {
const handler = (topic, message, logger, callback) => {
const projectId = message.projectId;
if (!projectId) {
return callback(new Error('Missing projectId in the event message.'));
Expand All @@ -285,7 +287,9 @@ const handler = (topic, message, callback) => {

// filter out `notifications.connect.project.topic.created` events send by bot
// because they create too much clutter and duplicate info
if (topic === BUS_API_EVENT.CONNECT.TOPIC_CREATED && message.userId.toString() === config.TCWEBSERVICE_ID) {
const botIds = [config.TCWEBSERVICE_ID, config.CODERBOT_USER_ID];
if (topic === BUS_API_EVENT.CONNECT.TOPIC.CREATED && botIds.contains(message.userId.toString())) {
logger.info(`Ignoring, to avoid noise, Bot topic ${topic}`);
return callback(null, []);
}

Expand Down Expand Up @@ -328,11 +332,13 @@ const handler = (topic, message, callback) => {
_.map(allNotifications, (notification) => {
notification.version = eventConfig.version;
notification.contents.projectName = project.name;
notification.contents.timestamp = (new Date()).toISOString();
// if found a user then add user handle
if (users.length) {
notification.contents.userHandle = users[0].handle;
notification.contents.userFullName = `${users[0].firstName} ${users[0].lastName}`;
notification.contents.userEmail = users[0].email;
notification.contents.photoURL = users[0].photoURL;
}
});
callback(null, allNotifications);
Expand All @@ -358,7 +364,10 @@ if (config.ENABLE_EMAILS) {
notificationServer
.initDatabase()
.then(() => notificationServer.start())
.catch((e) => console.log(e)); // eslint-disable-line no-console
.catch((e) => {
console.log(e); // eslint-disable-line no-console
notificationServer.logger.error('Notification server errored out');
});

// if no need to init database, then directly start the server:
// notificationServer.start();
58 changes: 48 additions & 10 deletions connect/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,64 @@ module.exports = {
every10minutes: '*/10 * * * *',
hourly: '0 * * * *',
daily: '0 7 * * *', // every day at 7am
everyOtherDay: '0 7 */2 * *', // every other day at 7 am
weekly: '0 7 * * 6', // every Saturday at 7am
},

// email service id for settings
SETTINGS_EMAIL_SERVICE_ID: 'email',
SETTINGS_EMAIL_BUNDLING_SERVICE_ID: 'emailBundling',

BUS_API_EVENT: {
CONNECT: {
TOPIC_CREATED: 'notifications.connect.project.topic.created',
TOPIC_DELETED: 'notifications.connect.project.topic.deleted',
POST_CREATED: 'notifications.connect.project.post.created',
POST_UPDATED: 'notifications.connect.project.post.edited',
POST_DELETED: 'notifications.connect.project.post.deleted',
MENTIONED_IN_POST: 'notifications.connect.project.post.mention',
POST: {
UPDATED: 'notifications.connect.project.post.edited',
CREATED: 'notifications.connect.project.post.created',
DELETED: 'notifications.connect.project.post.deleted',
MENTION: 'notifications.connect.project.post.mention',
},
MEMBER: {
JOINED: 'notifications.connect.project.member.joined',
LEFT: 'notifications.connect.project.member.left',
REMOVED: 'notifications.connect.project.member.removed',
MANAGER_JOINED: 'notifications.connect.project.member.managerJoined',
COPILOT_JOINED: 'notifications.connect.project.member.copilotJoined',
ASSIGNED_AS_OWNER: 'notifications.connect.project.member.assignedAsOwner',
},
PROJECT: {
ACTIVE: 'notifications.connect.project.active',
APPROVED: 'notifications.connect.project.approved',
CANCELED: 'notifications.connect.project.canceled',
COMPLETED: 'notifications.connect.project.completed',
CREATED: 'notifications.connect.project.created',
FILE_UPLOADED: 'notifications.connect.project.fileUploaded',
LINK_CREATED: 'notifications.connect.project.linkCreated',
PAUSED: 'notifications.connect.project.paused',
SUBMITTED_FOR_REVIEW: 'notifications.connect.project.submittedForReview',
SPECIFICATION_MODIFIED: 'notifications.connect.project.specificationModified',
},
PROJECT_PLAN: {
READY: 'notifications.connect.project.planReady',
MODIFIED: 'notifications.connect.project.plan.updated',
PROGRESS_UPDATED: 'notifications.connect.project.progressModified',
PHASE_ACTIVATED: 'notifications.connect.project.phase.transition.active',
PHASE_COMPLETED: 'notifications.connect.project.phase.transition.completed',
PHASE_PAYMENT_UPDATED: 'notifications.connect.project.phase.update.payment',
PHASE_PROGRESS_UPDATED: 'notifications.connect.project.phase.update.progress',
PHASE_SCOPE_UPDATED: 'notifications.connect.project.phase.update.scope',
MILESTONE_ACTIVATED: 'notifications.connect.project.phase.milestone.transition.active',
MILESTONE_COMPLETED: 'notifications.connect.project.phase.milestone.transition.completed',
WAITING_FOR_CUSTOMER_INPUT: 'notifications.connect.project.phase.milestone.waiting.customer',
},
TOPIC: {
CREATED: 'notifications.connect.project.topic.created',
DELETED: 'notifications.connect.project.topic.deleted',
},
},
EMAIL: {
TOPIC_CREATED: 'notifications.action.email.connect.project.topic.created',
POST_CREATED: 'notifications.action.email.connect.project.post.created',
MENTIONED_IN_POST: 'notifications.action.email.connect.project.post.mention',
BUNDLED: 'notifications.action.email.connect.project.bundled',
// TODO: after a proper named email topic is created, this is being used as the email event's topic
GENERAL: 'notifications.action.email.connect.project.notifications.generic',
BUNDLED: 'notifications.action.email.connect.project.notifications.bundled',
},
},
};
Loading