Skip to content

Commit e325322

Browse files
authored
Merge pull request #21 from topcoder-platform/dev
Release to prod
2 parents 0252eb9 + 81c868d commit e325322

File tree

10 files changed

+105
-4
lines changed

10 files changed

+105
-4
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# TOPCODER NOTIFICATIONS SERIES - NOTIFICATIONS SERVER
1+
# TOPCODER NOTIFICATIONS SERIES - NOTIFICATIONS SERVER
22

33

44
## Dependencies
55
- nodejs https://nodejs.org/en/ (v6+)
66
- Heroku Toolbelt https://toolbelt.heroku.com
77
- git
88
- PostgreSQL 9.5
9-
9+
1010

1111
## Configuration
1212
Configuration for the notification server is at `config/default.js`.
@@ -125,5 +125,5 @@ In case it expires, you may get a new token in this way:
125125
## Swagger
126126

127127
Swagger API definition is provided at `docs/swagger_api.yaml`,
128-
you may check it at `http://editor.swagger.io`.
128+
you may check it at `http://editor.swagger.io`.
129129

connect/events-config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ const EVENTS = [
6161
type: 'notifications.connect.project.approved',
6262
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER],
6363
topcoderRoles: [ROLE_CONNECT_COPILOT, ROLE_ADMINISTRATOR],
64+
}, {
65+
type: 'notifications.connect.project.active',
66+
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER],
67+
topcoderRoles: [ROLE_ADMINISTRATOR],
6468
}, {
6569
type: 'notifications.connect.project.paused',
6670
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER],
@@ -111,6 +115,12 @@ const EVENTS = [
111115
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER, PROJECT_ROLE_MEMBER],
112116
toTopicStarter: true,
113117
toMentionedUsers: true,
118+
}, {
119+
type: 'notifications.connect.project.post.edited',
120+
version: 2,
121+
projectRoles: [PROJECT_ROLE_OWNER, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER, PROJECT_ROLE_MEMBER],
122+
toTopicStarter: true,
123+
toMentionedUsers: true,
114124
}, {
115125
type: 'notifications.connect.project.post.mention',
116126
},

docs/swagger_api.yaml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ paths:
7070
read:
7171
type: boolean
7272
description: read flag
73+
seen:
74+
type: boolean
75+
description: seen flag
7376
contents:
7477
type: object
7578
description: the event message in JSON format
@@ -152,6 +155,42 @@ paths:
152155
description: "Internal server error."
153156
schema:
154157
$ref: "#/definitions/Error"
158+
/notifications/{id}/seen:
159+
put:
160+
description:
161+
mark notification(s) as seen, id can be single id or '-' separated ids
162+
security:
163+
- jwt: []
164+
parameters:
165+
- in: path
166+
name: id
167+
description: notification id
168+
required: true
169+
type: integer
170+
format: int64
171+
responses:
172+
200:
173+
description: OK, the notification(s) are marked as seen
174+
400:
175+
description: "Invalid input"
176+
schema:
177+
$ref: "#/definitions/Error"
178+
401:
179+
description: "authentication failed"
180+
schema:
181+
$ref: "#/definitions/Error"
182+
403:
183+
description: "Action not allowed."
184+
schema:
185+
$ref: "#/definitions/Error"
186+
404:
187+
description: "Notification is not found"
188+
schema:
189+
$ref: "#/definitions/Error"
190+
500:
191+
description: "Internal server error."
192+
schema:
193+
$ref: "#/definitions/Error"
155194
/notificationsettings:
156195
get:
157196
description:

migrations/v1.2.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE public."Notifications"
2+
ADD COLUMN seen boolean;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"pg": "^7.3.0",
3333
"sequelize": "^4.21.0",
3434
"superagent": "^3.8.0",
35-
"tc-core-library-js": "gondzo/tc-core-library-js.git#dev",
35+
"tc-core-library-js": "appirio-tech/tc-core-library-js.git#v2.2",
3636
"winston": "^2.2.0"
3737
},
3838
"engines": {

src/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ function startKafkaConsumer(handlers) {
5656
version: notification.version || null,
5757
contents: _.extend({}, messageJSON, notification.contents),
5858
read: false,
59+
seen: false,
5960
}))))
6061
// commit offset
6162
.then(() => consumer.commitOffset({ topic, partition, offset: m.offset }))

src/controllers/NotificationController.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ function* markAllRead(req, res) {
3434
res.end();
3535
}
3636

37+
/**
38+
* Mark a notification as seen.
39+
* @param req the request
40+
* @param res the response
41+
*/
42+
function* markAsSeen(req, res) {
43+
yield NotificationService.markAsSeen(req.params.id, req.user.userId);
44+
res.end();
45+
}
46+
3747
/**
3848
* Get notification settings.
3949
* @param req the request
@@ -58,6 +68,7 @@ module.exports = {
5868
listNotifications,
5969
markAsRead,
6070
markAllRead,
71+
markAsSeen,
6172
getSettings,
6273
updateSettings,
6374
};

src/models/Notification.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = (sequelize, DataTypes) => sequelize.define('Notification', {
1616
type: { type: DataTypes.STRING, allowNull: false },
1717
contents: { type: DataTypes.JSONB, allowNull: false },
1818
read: { type: DataTypes.BOOLEAN, allowNull: false },
19+
seen: { type: DataTypes.BOOLEAN, allowNull: true },
1920
version: { type: DataTypes.SMALLINT, allowNull: true },
2021
}, {});
2122

src/routes.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ module.exports = {
1919
method: 'markAllRead',
2020
},
2121
},
22+
'/notifications/:id/seen': {
23+
put: {
24+
controller: 'NotificationController',
25+
method: 'markAsSeen',
26+
},
27+
},
2228
'/notificationsettings': {
2329
get: {
2430
controller: 'NotificationController',

src/services/NotificationService.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,36 @@ markAllRead.schema = {
174174
userId: Joi.number().required(),
175175
};
176176

177+
/**
178+
* Mark notification(s) as seen.
179+
* @param {Number} id the notification id or '-' separated ids
180+
* @param {Number} userId the user id
181+
*/
182+
function* markAsSeen(id, userId) {
183+
const ids = _.map(id.split('-'), (str) => {
184+
const idInt = Number(str);
185+
if (!_.isInteger(idInt)) {
186+
throw new errors.BadRequestError(`Notification id should be integer: ${str}`);
187+
}
188+
return idInt;
189+
});
190+
const entities = yield models.Notification.findAll({ where: { id: { $in: ids }, seen: { $not: true } } });
191+
if (!entities || entities.length === 0) {
192+
throw new errors.NotFoundError(`Cannot find un-seen Notification where id = ${id}`);
193+
}
194+
_.each(entities, (entity) => {
195+
if (Number(entity.userId) !== userId) {
196+
throw new errors.ForbiddenError(`Cannot access Notification where id = ${entity.id}`);
197+
}
198+
});
199+
yield models.Notification.update({ seen: true }, { where: { id: { $in: ids }, seen: { $not: true } } });
200+
}
201+
202+
markAsSeen.schema = {
203+
id: Joi.string().required(),
204+
userId: Joi.number().required(),
205+
};
206+
177207
updateSettings.schema = {
178208
data: Joi.array().min(1).items(Joi.object().keys({
179209
topic: Joi.string().required(),
@@ -188,6 +218,7 @@ module.exports = {
188218
listNotifications,
189219
markAsRead,
190220
markAllRead,
221+
markAsSeen,
191222
getSettings,
192223
updateSettings,
193224
};

0 commit comments

Comments
 (0)