Skip to content

Support release for Connect Production release 2.4.8 #79

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 9 commits into from
Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# TOPCODER NOTIFICATIONS SERIES - NOTIFICATIONS SERVER

# TOPCODER NOTIFICATIONS

## Description
This repository hosts the API and processors for enabling notifications in various topcoder apps. Currently it is limited to provide this facility to the [Connect](https://github.com/appirio-tech/connect-app) application. Theoretcially, it is a generic framework and application which could be used for sending and consuming notificaitons by any other topcoder app. In very simple words to send notifications using this application:

1. Send an event to bus
2. Listen that event in tc-notifications
3. There is a config in tc-notifications for each event it want to listen and we can specify rules who are the target users to whom we should send notifications for this event
4. By default it saves all notifications which are generated after parsing the rules specified in step 3 and these are the treated web notifications which we show in the app directly
5. Then there is option to add notification handlers where we get all these notifications one by one and we can process them further for more channels e.g. we send notification emails for each of notification generated
6. When one wants to show the notifications, we use the notifications api (hosted inside the tc-notifications itself as separate service) to fetch notifications, mark notifications read or unread etc.

tc-notifications (as a standard nodejs app) provides generic framework around notifications, it does not have config (used in step 3 of previous list) for specific apps. So, to have config for specific apps, we have to start the notification consumers per app e.g. for connect, we have a folder [`connect`](https://github.com/topcoder-platform/tc-notifications/blob/dev/connect) which hosts start script to start notification consumers with connect specific configuration ([`events-config.js`](https://github.com/topcoder-platform/tc-notifications/blob/dev/connect/events-config.js)). It also adds email notification service which sends emails for notifications as per notification settings (coming from common framework laid by tc-notifications) for the user.

### Steps needed to enable other apps to use the notifications are:
1. Have a separate start up script (in a new folder at the root of the repo) for the concerned app. I would call this as notification consumer/processor.
2. Write [`events-config.js`](https://github.com/topcoder-platform/tc-notifications/blob/dev/connect/events-config.js) (name is not important, we have to read this file in the start up script written in step 1) for app specific notifications
3. Write additional notification services (eg. if you want to send email or slack or any other notification) and add them to startup script
4. Specify a node script in package.json to launch the start up script written in step 1
5. Either add deployment for this new notification consumer/processor in existing deployment script (if you want to host the processor as separate service in the same ECS cluster) or write a new script if you want to keep the deployment separate.

## Dependencies
- nodejs https://nodejs.org/en/ (v6+)
Expand Down
16 changes: 11 additions & 5 deletions connect/connectNotificationServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,9 @@ const handler = (topic, message, logger, callback) => {

// if message has userId such messages will likely need userHandle and user full name
// so let's get it
const ids = [message.initiatorUserId];
if (message.userId) {
const ids = [message.userId];
ids.push(message.userId);
return service.getUsersById(ids);
}
return [];
Expand All @@ -335,10 +336,15 @@ const handler = (topic, message, logger, callback) => {
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;
const affectedUser = _.find(users, u => u.userId === message.userId);
const initiatorUser = _.find(users, u => u.userId === message.initiatorUserId);
if (affectedUser) {
notification.contents.userHandle = affectedUser.handle;
notification.contents.userFullName = `${affectedUser.firstName} ${affectedUser.lastName}`;
notification.contents.userEmail = affectedUser.email;
notification.contents.photoURL = affectedUser.photoURL;
}
notification.contents.initiatorUser = initiatorUser;
}
});
callback(null, allNotifications);
Expand Down
2 changes: 2 additions & 0 deletions connect/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ module.exports = {
MANAGER_JOINED: 'notifications.connect.project.member.managerJoined',
COPILOT_JOINED: 'notifications.connect.project.member.copilotJoined',
ASSIGNED_AS_OWNER: 'notifications.connect.project.member.assignedAsOwner',
INVITE_CREATED: 'notifications.connect.project.member.invite.created',
INVITE_UPDATED: 'notifications.connect.project.member.invite.updated',
},
PROJECT: {
ACTIVE: 'notifications.connect.project.active',
Expand Down
5 changes: 5 additions & 0 deletions connect/events-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ const EVENTS = [
}, {
type: BUS_API_EVENT.CONNECT.MEMBER.MANAGER_JOINED,
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER],
}, {
type: BUS_API_EVENT.CONNECT.MEMBER.INVITE_CREATED,
projectRoles: [],
toUserHandle: true,
},

// Project activity
Expand Down Expand Up @@ -255,6 +259,7 @@ const EVENT_BUNDLES = {
BUS_API_EVENT.CONNECT.MEMBER.LEFT,
BUS_API_EVENT.CONNECT.MEMBER.MANAGER_JOINED,
BUS_API_EVENT.CONNECT.MEMBER.REMOVED,
BUS_API_EVENT.CONNECT.MEMBER.INVITE_CREATED,
],
},
PROJECT_PLAN: {
Expand Down
14 changes: 14 additions & 0 deletions connect/notificationServices/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ function handler(topicName, messageJSON, notification) {
authorFullName: notification.contents.userFullName,
photoURL: notification.contents.photoURL,
type: notificationType,
emailToAffectedUser: notification.contents.userEmail === userEmail,
},
recipients,
version:"v3",
Expand Down Expand Up @@ -291,6 +292,19 @@ function handler(topicName, messageJSON, notification) {
bundlePeriod = bundlePeriod && bundlePeriod.trim().length > 0 ? bundlePeriod : null;
// if bundling is not explicitly set and the event is not a messaging event, assume bundling enabled
if (!bundlePeriod && !messagingEvent) {
// finds the event category for the notification type
let eventBundleCategory = _.findKey(EVENT_BUNDLES, b => b.types && b.types.indexOf(notificationType) !== -1);
if (eventBundleCategory) {
const eventBundle = EVENT_BUNDLES[eventBundleCategory];
// if we find the event category for the notification, use the bundle settings from the first event
if (eventBundle && eventBundle.types && eventBundle.types.length) {
const firstEvtInBundle = eventBundle.types[0];
const firstEvtBundleSettingPath = `notifications['${firstEvtInBundle}'].${SETTINGS_EMAIL_SERVICE_ID}.bundlePeriod`
let firstEvtBundlePeriod = _.get(settings, firstEvtBundleSettingPath);
bundlePeriod = firstEvtBundlePeriod
logger.debug('Assuming bundle period of first event in the event category=>', bundlePeriod);
}
}
// if bundle period is not set, assume it to be daily for default case
bundlePeriod = !bundlePeriod ? 'daily' : bundlePeriod;
}
Expand Down
69 changes: 69 additions & 0 deletions emails/src/partials/invites.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{{#if [EMAIL_INVITES]}}

<link rel="stylesheet" type="text/css" href="../styles/main.scss">

<tr class="post-head">
<td class="main-td">
<table class="main-child">
<tr>
<td class="empty-child-one"></td>
<td class="comment-box"><img src="https://image.ibb.co/etWM7J/comment.jpg" alt="IMG"></td>
<td class="empty-child-two"></td>
<td>
<strong>{{title}}</a>.
</td>
</tr>
</table>
</td>
</tr>
<tr class="empty-20">
<td class="main-td">
<table class="main-child">
<tr><td></td></tr>
</table>
</td>
</tr>


<tr class="post-details">
<td class="main-td">
<table class="main-child">
<tr>
<td class="empty-child-one"></td>
<td>You are invited to join the <strong>{{projectName}}</strong> on Topcoder Connect. To join the project, please register for a Topcoder account using <strong>Register</strong> button below.</td>
</tr>
</table>
</td>
</tr>


<tr class="empty-50">
<td class="main-td">
<table class="main-child">
<tr><td></td></tr>
</table>
</td>
</tr>
<tr class="button-row button-one">
<td class="main-td">
<table class="main-child">
<tr>
<td class="empty-child-one"></td>
<td class="second-child" align="center">
<a href="{{@root.accountsAppURL}}/connect/registration?retUrl={{@root.connectURL}}/projects/{{projectId}}">
Register
</a>
</td>
<td class="empty-child-one"></td>
</tr>
</table>
</td>
</tr>
<tr class="empty-20">
<td class="main-td">
<table class="main-child">
<tr><td></td></tr>
</table>
</td>
</tr>
{{/if}}
9 changes: 8 additions & 1 deletion emails/src/partials/project-team.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,21 @@
<strong>{{userFullName}}</strong> joined the project as Manager
{{/if}}
{{#if [notifications.connect.project.member.removed]}}
<strong>{{userFullName}}</strong> left the project
{{#if [emailToAffectedUser]}}
You are removed from the project
{{else}}
<strong>{{userFullName}}</strong> left the project
{{/if}}
{{/if}}
{{#if [notifications.connect.project.member.left]}}
<strong>{{userFullName}}</strong> left the project
{{/if}}
{{#if [notifications.connect.project.member.joined]}}
<strong>{{userFullName}}</strong> joined the project
{{/if}}
{{#if [notifications.connect.project.member.invite.created]}}
Hi <strong>{{userFullName}}</strong>, you are invited to join the project {{projectName}}. Please click on the button ("View project on Connect") below to join.
{{/if}}
</td>
</tr>
</table>
Expand Down