Skip to content

Commit fde2680

Browse files
authored
Merge pull request #219 from topcoder-platform/dev
[PROD] Universal Notifications
2 parents ef48919 + 0b2e9ba commit fde2680

21 files changed

+934
-180
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ The following parameters can be set in config files or in env variables:
103103
- `REPLY_EMAIL_PREFIX`: prefix of the genereated reply email address
104104
- `REPLY_EMAIL_DOMAIN`: email domain
105105
- `DEFAULT_REPLY_EMAIL`: default reply to email address, for example no-reply@topcoder.com
106+
- **Slack api**
107+
- `SLACK_URL`: slack api url to post messages
108+
- `SLACK_BOT_TOKEN`: slack bot user OAuth token
109+
- `SLACK_NOTIFY`: slack notification switch, set to 'true' to enable slack notifications.
106110

107111
Note that the above two configuration are separate because the common notification server config
108112
will be deployed to a NPM package, the connect notification server will use that NPM package,

config/default.js

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ module.exports = {
2828
KAFKA_CLIENT_CERT_KEY: process.env.KAFKA_CLIENT_CERT_KEY ?
2929
process.env.KAFKA_CLIENT_CERT_KEY.replace('\\n', '\n') : null,
3030

31-
TC_API_V3_BASE_URL: process.env.TC_API_V3_BASE_URL || '',
31+
TC_API_V3_BASE_URL: process.env.TC_API_V3_BASE_URL || 'http://api.topcoder-dev.com/v3',
3232
TC_API_V4_BASE_URL: process.env.TC_API_V4_BASE_URL || '',
33-
TC_API_V5_BASE_URL: process.env.TC_API_V5_BASE_URL || '',
33+
TC_API_V5_BASE_URL: process.env.TC_API_V5_BASE_URL || 'https://api.topcoder-dev.com/v5',
3434
API_CONTEXT_PATH: process.env.API_CONTEXT_PATH || '/v5/notifications',
3535
TC_API_BASE_URL: process.env.TC_API_BASE_URL || '',
3636

@@ -47,7 +47,12 @@ module.exports = {
4747
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
4848
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET,
4949
AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL,
50-
50+
// Slack configuration.
51+
SLACK: {
52+
URL: process.env.SLACK_URL || 'https://slack.com/api/chat.postMessage',
53+
BOT_TOKEN: process.env.SLACK_BOT_TOKEN,
54+
NOTIFY: process.env.SLACK_NOTIFY === 'true',
55+
},
5156
KAFKA_CONSUMER_RULESETS: {
5257
// key is Kafka topic name, value is array of ruleset which have key as
5358
// handler function name defined in src/processors/index.js
@@ -115,19 +120,22 @@ module.exports = {
115120
// },
116121
// },
117122
// ],
118-
// */ // issue - https://github.com/topcoder-platform/community-app/issues/4108
123+
// */ // issue - https://github.com/topcoder-platform/community-app/issues/4108
119124
'admin.notification.broadcast': [{
120-
handleBulkNotification: {}
121-
}
122-
]
123-
//'notifications.community.challenge.created': ['handleChallengeCreated'],
124-
//'notifications.community.challenge.phasewarning': ['handleChallengePhaseWarning'],
125+
handleBulkNotification: {},
126+
},
127+
],
128+
'notifications.action.create': [{
129+
handleUniversalNotification: {},
130+
}],
131+
// 'notifications.community.challenge.created': ['handleChallengeCreated'],
132+
// 'notifications.community.challenge.phasewarning': ['handleChallengePhaseWarning'],
125133
},
126134

127135
// email notification service related variables
128136
ENV: process.env.ENV,
129137
ENABLE_EMAILS: process.env.ENABLE_EMAILS ? Boolean(process.env.ENABLE_EMAILS) : false,
130-
ENABLE_DEV_MODE: process.env.ENABLE_DEV_MODE ? Boolean(process.env.ENABLE_DEV_MODE) : true,
138+
ENABLE_DEV_MODE: process.env.ENABLE_DEV_MODE === 'true',
131139
DEV_MODE_EMAIL: process.env.DEV_MODE_EMAIL,
132140
DEFAULT_REPLY_EMAIL: process.env.DEFAULT_REPLY_EMAIL,
133141
ENABLE_HOOK_BULK_NOTIFICATION: process.env.ENABLE_HOOK_BULK_NOTIFICATION || false,

connect/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ module.exports = {
3636
DEFAULT_REPLY_EMAIL: process.env.DEFAULT_REPLY_EMAIL,
3737

3838
CONNECT_URL: process.env.CONNECT_URL || 'https://connect.topcoder-dev.com',
39-
ACCOUNTS_APP_URL: process.env.ACCOUNTS_APP_URL || "https://accounts-auth0.topcoder-dev.com",
39+
ACCOUNTS_APP_URL: process.env.ACCOUNTS_APP_URL || 'https://accounts-auth0.topcoder-dev.com',
4040
TC_CDN_URL: process.env.TC_CDN_URL,
4141
};

constants.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ module.exports = {
33
SEARCH_USERS_PAGE_SIZE: 5,
44

55
SETTINGS_EMAIL_SERVICE_ID: 'email',
6+
SETTINGS_WEB_SERVICE_ID: 'web',
7+
SETTINGS_SLACK_SERVICE_ID: 'slack',
68
ACTIVE_USER_STATUSES: ['ACTIVE'],
79

810
BUS_API_EVENT: {
911
EMAIL: {
1012
GENERAL: 'connect.notification.email.project.notifications.generic',
13+
UNIVERSAL: 'external.action.email',
1114
},
1215
},
1316
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"info": {
3+
"_postman_id": "ad14efc8-1fed-4914-8273-330754500801",
4+
"name": "TC-NOTIFICATIONS",
5+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6+
},
7+
"item": [
8+
{
9+
"name": "list notifications",
10+
"request": {
11+
"method": "GET",
12+
"header": [
13+
{
14+
"key": "Authorization",
15+
"value": "Bearer {{TOKEN}}",
16+
"type": "text"
17+
}
18+
],
19+
"url": {
20+
"raw": "{{URL}}/list?limit=100",
21+
"host": [
22+
"{{URL}}"
23+
],
24+
"path": [
25+
"list"
26+
],
27+
"query": [
28+
{
29+
"key": "limit",
30+
"value": "100"
31+
}
32+
]
33+
}
34+
},
35+
"response": []
36+
}
37+
]
38+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"id": "9d9c9e1b-6004-4bbe-9a98-55ad3a5838d7",
3+
"name": "tc-notifications",
4+
"values": [
5+
{
6+
"key": "URL",
7+
"value": "http://localhost:3000/v5/notifications",
8+
"enabled": true
9+
},
10+
{
11+
"key": "TOKEN",
12+
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjIxNDc0ODM2NDgsInVzZXJJZCI6IjQwMTUyODU2IiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.PKv0QrMCPf0-ZPjv4PGWT7eXne54m7i9YX9eq-fceMU",
13+
"enabled": true
14+
}
15+
],
16+
"_postman_variable_scope": "environment",
17+
"_postman_exported_at": "2021-07-24T21:01:35.787Z",
18+
"_postman_exported_using": "Postman/8.8.0"
19+
}

local/Verification.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Deployment & Verification Guide
2+
3+
> This guide is prepared for Linux OS, npm install command fails for Windows.
4+
> Please switch to Node.js version 8.x before proceed.
5+
6+
1. I prepared a docker-compose file for local deployment. It will start the following services:
7+
* postgres
8+
* zookeeper
9+
* kafka
10+
* bus-api
11+
2. Run following commands to start dependency services:
12+
```bash
13+
cd local
14+
docker-compose build --no-cache
15+
docker-compose up -d
16+
```
17+
3. After services have started successfully, set environment variables for notifications api:
18+
```sh
19+
# you need to provide the values for the next variables
20+
export AUTH0_CLIENT_ID
21+
export AUTH0_CLIENT_SECRET
22+
export SLACK_BOT_TOKEN
23+
24+
# for other variables can uses these ones
25+
export AUTH0_URL='https://topcoder-dev.auth0.com/oauth/token'
26+
export AUTH0_AUDIENCE='https://m2m.topcoder-dev.com/'
27+
export AUTH0_AUDIENCE_UBAHN='https://u-bahn.topcoder.com'
28+
export AUTH_SECRET='mysecret'
29+
export VALID_ISSUERS='["https://api.topcoder-dev.com", "https://api.topcoder.com", "https://topcoder-dev.auth0.com/", "https://auth.topcoder-dev.com/"]'
30+
export DATABASE_URL='postgres://postgres:postgres@localhost:5432/postgres'
31+
export PORT=4000
32+
export TC_API_V5_BASE_URL='http://localhost:8002/v5'
33+
export KAFKA_URL='localhost:9092'
34+
export KAFKA_GROUP_ID='tc-notifications'
35+
export SLACK_NOTIFY='true'
36+
export ENABLE_DEV_MODE='false'
37+
```
38+
39+
4. Run command `npm install`
40+
5. Run command `npm run reset:db` to initialize tables.
41+
6. Run command `npm run startConsumer` to start kafka consumer.
42+
7. Wait to see following logs:
43+
```bash
44+
2021-07-24T15:11:01.512Z INFO no-kafka-client Joined group tc-notifications generationId 1 as no-kafka-client-2689c63f-9850-448a-a3f0-11d2ec8e49ce
45+
2021-07-24T15:11:01.512Z INFO no-kafka-client Elected as group leader
46+
2021-07-24T15:11:01.583Z DEBUG no-kafka-client Subscribed to notifications.autopilot.events:0 offset 0 leader localhost:9092
47+
2021-07-24T15:11:01.583Z DEBUG no-kafka-client Subscribed to challenge.notification.events:0 offset 0 leader localhost:9092
48+
2021-07-24T15:11:01.584Z DEBUG no-kafka-client Subscribed to notification.action.create:0 offset 0 leader localhost:9092
49+
2021-07-24T15:11:01.584Z DEBUG no-kafka-client Subscribed to admin.notification.broadcast:0 offset 0 leader localhost:9092
50+
```
51+
8. Now, we will prepare terminals to be used later for verifying api.
52+
* 1 terminal to watch kafka topic for email notifications.
53+
* 1 terminal to query Notifications table for web notifications.
54+
* Slack app, web or mobile application.
55+
9. Open a new terminal for watching kafka topic `external.action.email`
56+
```bash
57+
docker exec notification-kafka /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic external.action.email
58+
```
59+
10. **Alternative-1:** Open a new terminal for postgres. It will be used to check if notifications are getting created.
60+
```bash
61+
docker exec -it notification-postgres psql -U postgres
62+
\c postgres
63+
SELECT * FROM "Notifications";
64+
```
65+
**Alternative-2:** Start notifications api and use postman to list notifications. Open a new terminal and change PORT to 3000
66+
```bash
67+
. ./environment.sh
68+
export PORT=3000
69+
npm run startAPI
70+
```
71+
Open postman and use following collection and environment:
72+
* collection: docs/tc-notifications.postman_collection.json
73+
* environment: docs/tc-notifications.postman_environment.json
74+
75+
Existing postman collections are outdated and need to be converted to version 2.0.0. So, I had to create a new collection.
76+
77+
11. To verify slack messages, you can use following workspace and user credentials. Token for posting messages to slack was already shared inside environment variables and has been set at step 3.
78+
`https://tc-notifications.slack.com/`
79+
username: `tc.notification.slack@gmail.com`
80+
password: `@Topcoder123`
81+
82+
83+
12. Now we can start testing. Open a new terminal for producing kafka messages for the topic `notification.action.create`
84+
```bash
85+
docker exec -it notification-kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic notification.action.create
86+
```
87+
13. You can copy and paste the following messages to the terminal we opened for producing kafka messages.
88+
send messages successfully
89+
```json
90+
{"topic":"notification.action.create","originator":"tc-direct","timestamp":"2018-02-16T00:00:00","mime-type":"application\/json","payload":[{"serviceId":"email","type":"taas.notification.request-submitted","details":{"from":"example@example.com","recipients":[{"userId":123,"email":"test1@test.com"},{"userId":456,"email":"test2@test.com"}],"cc":[{"userId":789,"email":"test3@test.com"},{"userId":987,"email":"test4@test.com"}],"data":{"subject":"...","body":"...","field1":"...","field2":"...","filedN":"..."},"sendgridTemplateId":"...","version":"v3"}},{"serviceId":"slack","type":"taas.notification.request-submitted","details":{"channel":"general","text":"test message"}},{"serviceId":"web","type":"taas.notification.request-submitted","details":{"userId":40152856,"contents":{},"version":1}}]}
91+
```
92+
email: fail (invalid email), web: success, slack: success
93+
```json
94+
{"topic":"notification.action.create","originator":"tc-direct","timestamp":"2018-02-16T00:00:00","mime-type":"application\/json","payload":[{"serviceId":"email","type":"taas.notification.request-submitted","details":{"from":"example.com","recipients":[{"userId":123,"email":"test1@test.com"},{"userId":456,"email":"test2@test.com"}],"cc":[{"userId":789,"email":"test3@test.com"},{"userId":987,"email":"test4@test.com"}],"data":{"subject":"...","body":"...","field1":"...","field2":"...","filedN":"..."},"sendgridTemplateId":"...","version":"v3"}},{"serviceId":"slack","type":"taas.notification.request-submitted","details":{"channel":"random","text":"test message"}},{"serviceId":"web","type":"taas.notification.request-submitted","details":{"userId":40152856,"contents":{},"version":1}}]}
95+
```

local/docker-compose.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
version: "3"
2+
services:
3+
postgres:
4+
container_name: notification-postgres
5+
image: postgres:11.8
6+
environment:
7+
POSTGRES_USER: postgres
8+
POSTGRES_PASSWORD: postgres
9+
ports:
10+
- 5432:5432
11+
12+
zookeeper:
13+
image: wurstmeister/zookeeper
14+
container_name: notification-zookeeper
15+
ports:
16+
- 2181:2181
17+
18+
kafka:
19+
image: wurstmeister/kafka
20+
container_name: notification-kafka
21+
depends_on:
22+
- zookeeper
23+
ports:
24+
- 9092:9092
25+
environment:
26+
KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9093,OUTSIDE://localhost:9092
27+
KAFKA_LISTENERS: INSIDE://kafka:9093,OUTSIDE://0.0.0.0:9092
28+
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
29+
KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
30+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
31+
KAFKA_CREATE_TOPICS: "challenge.notification.events:1:1,notifications.autopilot.events:1:1,admin.notification.broadcast:1:1,notifications.action.create:1:1,external.action.email:1:1"
32+
33+
tc-bus-api:
34+
container_name: tc-bus-api
35+
build:
36+
context: ./generic-tc-service
37+
args:
38+
NODE_VERSION: 8.11.3
39+
GIT_URL: https://github.com/topcoder-platform/tc-bus-api
40+
GIT_BRANCH: dev
41+
BYPASS_TOKEN_VALIDATION: 1
42+
command: start
43+
ports:
44+
- 8002:8002
45+
depends_on:
46+
- kafka
47+
environment:
48+
- PORT=8002
49+
- KAFKA_URL=kafka:9093
50+
- JWT_TOKEN_SECRET=secret
51+
- VALID_ISSUERS="[\"https:\/\/topcoder-newauth.auth0.com\/\",\"https:\/\/api.topcoder-dev.com\",\"https:\/\/topcoder-dev.auth0.com\/\"]"
52+
- AUTH0_URL
53+
- AUTH0_AUDIENCE
54+
- AUTH0_CLIENT_ID
55+
- AUTH0_CLIENT_SECRET
56+
- AUTH0_PROXY_SERVER_URL

local/generic-tc-service/Dockerfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
ARG NODE_VERSION=12.16.3
2+
3+
FROM node:$NODE_VERSION
4+
ARG GIT_URL
5+
ARG GIT_BRANCH
6+
ARG BYPASS_TOKEN_VALIDATION
7+
8+
RUN git clone $GIT_URL /opt/app
9+
WORKDIR /opt/app
10+
RUN git checkout -b node-branch origin/$GIT_BRANCH
11+
12+
RUN npm install
13+
RUN if [ $BYPASS_TOKEN_VALIDATION -eq 1 ]; then sed -i '/decodedToken = jwt.decode/a \ callback(undefined, decodedToken.payload); return;' node_modules/tc-core-library-js/lib/auth/verifier.js; fi
14+
COPY docker-entrypoint.sh /opt/
15+
ENTRYPOINT ["/opt/docker-entrypoint.sh"]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
3+
HOST_DOMAIN="host.docker.internal"
4+
ping -q -c1 $HOST_DOMAIN > /dev/null 2>&1
5+
if [ $? -ne 0 ]; then
6+
HOST_IP=$(ip route | awk 'NR==1 {print $3}')
7+
echo -e "$HOST_IP\t$HOST_DOMAIN" >> /etc/hosts
8+
fi
9+
10+
cd /opt/app/ && npm run $1

0 commit comments

Comments
 (0)