diff --git a/services/notifications/app.js b/services/notifications/app.js index 5f37198675..4d5a91ab8d 100644 --- a/services/notifications/app.js +++ b/services/notifications/app.js @@ -56,12 +56,12 @@ app.get('*', (req, res) => res.sendStatus(404)) const host = __guard__( Settings.internal != null ? Settings.internal.notifications : undefined, - (x) => x.host + x => x.host ) || 'localhost' const port = __guard__( Settings.internal != null ? Settings.internal.notifications : undefined, - (x1) => x1.port + x1 => x1.port ) || 3042 mongodb @@ -71,7 +71,7 @@ mongodb logger.info(`notifications starting up, listening on ${host}:${port}`) ) }) - .catch((err) => { + .catch(err => { logger.fatal({ err }, 'Cannot connect to mongo. Exiting.') process.exit(1) }) diff --git a/services/notifications/app/js/HealthCheckController.js b/services/notifications/app/js/HealthCheckController.js index 64c9f5433d..ffd58192c2 100644 --- a/services/notifications/app/js/HealthCheckController.js +++ b/services/notifications/app/js/HealthCheckController.js @@ -22,13 +22,13 @@ const logger = require('logger-sharelatex') module.exports = { check(callback) { const user_id = ObjectId() - const cleanupNotifications = (callback) => + const cleanupNotifications = callback => db.notifications.remove({ user_id }, callback) let notification_key = `smoke-test-notification-${ObjectId()}` - const getOpts = (endPath) => ({ + const getOpts = endPath => ({ url: `http://localhost:${port}/user/${user_id}${endPath}`, - timeout: 5000 + timeout: 5000, }) logger.log( { user_id, opts: getOpts(), key: notification_key, user_id }, @@ -41,7 +41,7 @@ module.exports = { key: notification_key, messageOpts: '', templateKey: 'f4g5', - user_id + user_id, } return request.post(opts, cb) }, @@ -59,7 +59,7 @@ module.exports = { } const hasNotification = _.some( body, - (notification) => + notification => notification.key === notification_key && notification.user_id === user_id.toString() ) @@ -73,7 +73,7 @@ module.exports = { return cb('notification not found in response') } }) - } + }, ] return async.series(jobs, function (err, body) { if (err != null) { @@ -112,5 +112,5 @@ module.exports = { }) } }) - } + }, } diff --git a/services/notifications/app/js/Notifications.js b/services/notifications/app/js/Notifications.js index 3f0a3167a8..d6d18868aa 100644 --- a/services/notifications/app/js/Notifications.js +++ b/services/notifications/app/js/Notifications.js @@ -23,7 +23,7 @@ module.exports = Notifications = { } const query = { user_id: ObjectId(user_id), - templateKey: { $exists: true } + templateKey: { $exists: true }, } db.notifications.find(query).toArray(callback) }, @@ -34,7 +34,7 @@ module.exports = Notifications = { } const query = { user_id: ObjectId(user_id), - key: notification.key + key: notification.key, } return db.notifications.count(query, function (err, count) { if (err != null) { @@ -45,52 +45,53 @@ module.exports = Notifications = { }, addNotification(user_id, notification, callback) { - return this._countExistingNotifications(user_id, notification, function ( - err, - count - ) { - if (err != null) { - return callback(err) - } - if (count !== 0 && !notification.forceCreate) { - return callback() - } - const doc = { - user_id: ObjectId(user_id), - key: notification.key, - messageOpts: notification.messageOpts, - templateKey: notification.templateKey - } - // TTL index on the optional `expires` field, which should arrive as an iso date-string, corresponding to - // a datetime in the future when the document should be automatically removed. - // in Mongo, TTL indexes only work on date fields, and ignore the document when that field is missing - // see `README.md` for instruction on creating TTL index - if (notification.expires != null) { - try { - doc.expires = new Date(notification.expires) - const _testValue = doc.expires.toISOString() - } catch (error) { - err = error - logger.error( - { user_id, expires: notification.expires }, - 'error converting `expires` field to Date' - ) + return this._countExistingNotifications( + user_id, + notification, + function (err, count) { + if (err != null) { return callback(err) } + if (count !== 0 && !notification.forceCreate) { + return callback() + } + const doc = { + user_id: ObjectId(user_id), + key: notification.key, + messageOpts: notification.messageOpts, + templateKey: notification.templateKey, + } + // TTL index on the optional `expires` field, which should arrive as an iso date-string, corresponding to + // a datetime in the future when the document should be automatically removed. + // in Mongo, TTL indexes only work on date fields, and ignore the document when that field is missing + // see `README.md` for instruction on creating TTL index + if (notification.expires != null) { + try { + doc.expires = new Date(notification.expires) + const _testValue = doc.expires.toISOString() + } catch (error) { + err = error + logger.error( + { user_id, expires: notification.expires }, + 'error converting `expires` field to Date' + ) + return callback(err) + } + } + db.notifications.updateOne( + { user_id: doc.user_id, key: notification.key }, + { $set: doc }, + { upsert: true }, + callback + ) } - db.notifications.updateOne( - { user_id: doc.user_id, key: notification.key }, - { $set: doc }, - { upsert: true }, - callback - ) - }) + ) }, removeNotificationId(user_id, notification_id, callback) { const searchOps = { user_id: ObjectId(user_id), - _id: ObjectId(notification_id) + _id: ObjectId(notification_id), } const updateOperation = { $unset: { templateKey: true, messageOpts: true } } db.notifications.updateOne(searchOps, updateOperation, callback) @@ -99,7 +100,7 @@ module.exports = Notifications = { removeNotificationKey(user_id, notification_key, callback) { const searchOps = { user_id: ObjectId(user_id), - key: notification_key + key: notification_key, } const updateOperation = { $unset: { templateKey: true } } db.notifications.updateOne(searchOps, updateOperation, callback) @@ -115,8 +116,8 @@ module.exports = Notifications = { deleteNotificationByKeyOnly(notification_key, callback) { const searchOps = { key: notification_key } db.notifications.deleteOne(searchOps, callback) - } + }, } -;['getUserNotifications', 'addNotification'].map((method) => +;['getUserNotifications', 'addNotification'].map(method => metrics.timeAsyncMethod(Notifications, method, 'mongo.Notifications', logger) ) diff --git a/services/notifications/app/js/NotificationsController.js b/services/notifications/app/js/NotificationsController.js index 0d1ff7b6f4..5cd55c252c 100644 --- a/services/notifications/app/js/NotificationsController.js +++ b/services/notifications/app/js/NotificationsController.js @@ -50,7 +50,7 @@ module.exports = { logger.log( { user_id: req.params.user_id, - notification_id: req.params.notification_id + notification_id: req.params.notification_id, }, 'mark id notification as read' ) @@ -83,5 +83,5 @@ module.exports = { notification_key, (err, notifications) => res.sendStatus(200) ) - } + }, } diff --git a/services/notifications/app/js/mongodb.js b/services/notifications/app/js/mongodb.js index e43331e27d..d277a06aa4 100644 --- a/services/notifications/app/js/mongodb.js +++ b/services/notifications/app/js/mongodb.js @@ -24,5 +24,5 @@ async function setupDb() { module.exports = { db, ObjectId, - waitForDb + waitForDb, } diff --git a/services/notifications/config/settings.defaults.js b/services/notifications/config/settings.defaults.js index db91ba7672..19c00f5fea 100644 --- a/services/notifications/config/settings.defaults.js +++ b/services/notifications/config/settings.defaults.js @@ -2,17 +2,17 @@ module.exports = { internal: { notifications: { port: 3042, - host: process.env.LISTEN_ADDRESS || 'localhost' - } + host: process.env.LISTEN_ADDRESS || 'localhost', + }, }, mongo: { options: { useUnifiedTopology: - (process.env.MONGO_USE_UNIFIED_TOPOLOGY || 'true') === 'true' + (process.env.MONGO_USE_UNIFIED_TOPOLOGY || 'true') === 'true', }, url: process.env.MONGO_CONNECTION_STRING || - `mongodb://${process.env.MONGO_HOST || 'localhost'}/sharelatex` - } + `mongodb://${process.env.MONGO_HOST || 'localhost'}/sharelatex`, + }, } diff --git a/services/notifications/test/setup.js b/services/notifications/test/setup.js index 9ebe599cea..17e1782172 100644 --- a/services/notifications/test/setup.js +++ b/services/notifications/test/setup.js @@ -14,8 +14,8 @@ SandboxedModule.configure({ warn() {}, err() {}, error() {}, - fatal() {} - } + fatal() {}, + }, }, - globals: { Buffer, JSON, console, process } + globals: { Buffer, JSON, console, process }, }) diff --git a/services/notifications/test/unit/js/NotificationsControllerTest.js b/services/notifications/test/unit/js/NotificationsControllerTest.js index e63b83b9fb..f359eb6954 100644 --- a/services/notifications/test/unit/js/NotificationsControllerTest.js +++ b/services/notifications/test/unit/js/NotificationsControllerTest.js @@ -27,17 +27,17 @@ describe('Notifications Controller', function () { requires: { './Notifications': this.notifications, '@overleaf/metrics': { - inc: sinon.stub() - } - } + inc: sinon.stub(), + }, + }, }) return (this.stubbedNotification = [ { key: notification_key, messageOpts: 'some info', - templateKey: 'template-key' - } + templateKey: 'template-key', + }, ]) }) @@ -48,17 +48,17 @@ describe('Notifications Controller', function () { .callsArgWith(1, null, this.stubbedNotification) const req = { params: { - user_id - } + user_id, + }, } return this.controller.getUserNotifications(req, { - json: (result) => { + json: result => { result.should.equal(this.stubbedNotification) this.notifications.getUserNotifications .calledWith(user_id) .should.equal(true) return done() - } + }, }) }) }) @@ -68,18 +68,18 @@ describe('Notifications Controller', function () { this.notifications.addNotification = sinon.stub().callsArgWith(2) const req = { params: { - user_id + user_id, }, - body: this.stubbedNotification + body: this.stubbedNotification, } return this.controller.addNotification(req, { - sendStatus: (code) => { + sendStatus: code => { this.notifications.addNotification .calledWith(user_id, this.stubbedNotification) .should.equal(true) code.should.equal(200) return done() - } + }, }) }) }) @@ -90,17 +90,17 @@ describe('Notifications Controller', function () { const req = { params: { user_id, - notification_id - } + notification_id, + }, } return this.controller.removeNotificationId(req, { - sendStatus: (code) => { + sendStatus: code => { this.notifications.removeNotificationId .calledWith(user_id, notification_id) .should.equal(true) code.should.equal(200) return done() - } + }, }) }) }) @@ -110,18 +110,18 @@ describe('Notifications Controller', function () { this.notifications.removeNotificationKey = sinon.stub().callsArgWith(2) const req = { params: { - user_id + user_id, }, - body: { key: notification_key } + body: { key: notification_key }, } return this.controller.removeNotificationKey(req, { - sendStatus: (code) => { + sendStatus: code => { this.notifications.removeNotificationKey .calledWith(user_id, notification_key) .should.equal(true) code.should.equal(200) return done() - } + }, }) }) }) @@ -133,17 +133,17 @@ describe('Notifications Controller', function () { .callsArgWith(1) const req = { params: { - key: notification_key - } + key: notification_key, + }, } return this.controller.removeNotificationByKeyOnly(req, { - sendStatus: (code) => { + sendStatus: code => { this.notifications.removeNotificationByKeyOnly .calledWith(notification_key) .should.equal(true) code.should.equal(200) return done() - } + }, }) }) }) diff --git a/services/notifications/test/unit/js/NotificationsTests.js b/services/notifications/test/unit/js/NotificationsTests.js index 45c3b5fb06..63179b4d7f 100644 --- a/services/notifications/test/unit/js/NotificationsTests.js +++ b/services/notifications/test/unit/js/NotificationsTests.js @@ -35,23 +35,23 @@ describe('Notifications Tests', function () { find: this.findStub, count: this.countStub, updateOne: this.updateOneStub, - deleteOne: this.deleteOneStub - } + deleteOne: this.deleteOneStub, + }, } this.notifications = SandboxedModule.require(modulePath, { requires: { '@overleaf/settings': {}, './mongodb': { db: this.db, ObjectId }, - '@overleaf/metrics': { timeAsyncMethod: sinon.stub() } - } + '@overleaf/metrics': { timeAsyncMethod: sinon.stub() }, + }, }) this.stubbedNotification = { user_id: ObjectId(user_id), key: 'notification-key', messageOpts: 'some info', - templateKey: 'template-key' + templateKey: 'template-key', } return (this.stubbedNotificationArray = [this.stubbedNotification]) }) @@ -65,7 +65,7 @@ describe('Notifications Tests', function () { notifications.should.equal(this.stubbedNotificationArray) assert.deepEqual(this.findStub.args[0][0], { user_id: ObjectId(user_id), - templateKey: { $exists: true } + templateKey: { $exists: true }, }) return done() } @@ -79,17 +79,17 @@ describe('Notifications Tests', function () { user_id: ObjectId(user_id), key: 'notification-key', messageOpts: 'some info', - templateKey: 'template-key' + templateKey: 'template-key', } this.expectedDocument = { user_id: this.stubbedNotification.user_id, key: 'notification-key', messageOpts: 'some info', - templateKey: 'template-key' + templateKey: 'template-key', } this.expectedQuery = { user_id: this.stubbedNotification.user_id, - key: 'notification-key' + key: 'notification-key', } this.updateOneStub.yields() return this.countStub.yields(null, 0) @@ -99,7 +99,7 @@ describe('Notifications Tests', function () { return this.notifications.addNotification( user_id, this.stubbedNotification, - (err) => { + err => { expect(err).not.to.exist sinon.assert.calledWith( this.updateOneStub, @@ -121,7 +121,7 @@ describe('Notifications Tests', function () { return this.notifications.addNotification( user_id, this.stubbedNotification, - (err) => { + err => { expect(err).not.to.exist sinon.assert.notCalled(this.updateOneStub) return done() @@ -134,7 +134,7 @@ describe('Notifications Tests', function () { return this.notifications.addNotification( user_id, this.stubbedNotification, - (err) => { + err => { expect(err).not.to.exist sinon.assert.calledWith( this.updateOneStub, @@ -155,18 +155,18 @@ describe('Notifications Tests', function () { key: 'notification-key', messageOpts: 'some info', templateKey: 'template-key', - expires: '2922-02-13T09:32:56.289Z' + expires: '2922-02-13T09:32:56.289Z', } this.expectedDocument = { user_id: this.stubbedNotification.user_id, key: 'notification-key', messageOpts: 'some info', templateKey: 'template-key', - expires: new Date(this.stubbedNotification.expires) + expires: new Date(this.stubbedNotification.expires), } return (this.expectedQuery = { user_id: this.stubbedNotification.user_id, - key: 'notification-key' + key: 'notification-key', }) }) @@ -174,7 +174,7 @@ describe('Notifications Tests', function () { return this.notifications.addNotification( user_id, this.stubbedNotification, - (err) => { + err => { expect(err).not.to.exist sinon.assert.calledWith( this.updateOneStub, @@ -195,14 +195,14 @@ describe('Notifications Tests', function () { key: 'notification-key', messageOpts: 'some info', templateKey: 'template-key', - expires: 'WAT' + expires: 'WAT', } return (this.expectedDocument = { user_id: this.stubbedNotification.user_id, key: 'notification-key', messageOpts: 'some info', templateKey: 'template-key', - expires: new Date(this.stubbedNotification.expires) + expires: new Date(this.stubbedNotification.expires), }) }) @@ -210,7 +210,7 @@ describe('Notifications Tests', function () { return this.notifications.addNotification( user_id, this.stubbedNotification, - (err) => { + err => { ;(err instanceof Error).should.equal(true) sinon.assert.notCalled(this.updateOneStub) return done() @@ -227,13 +227,13 @@ describe('Notifications Tests', function () { return this.notifications.removeNotificationId( user_id, notification_id, - (err) => { + err => { const searchOps = { user_id: ObjectId(user_id), - _id: ObjectId(notification_id) + _id: ObjectId(notification_id), } const updateOperation = { - $unset: { templateKey: true, messageOpts: true } + $unset: { templateKey: true, messageOpts: true }, } assert.deepEqual(this.updateOneStub.args[0][0], searchOps) assert.deepEqual(this.updateOneStub.args[0][1], updateOperation) @@ -250,13 +250,13 @@ describe('Notifications Tests', function () { return this.notifications.removeNotificationKey( user_id, notification_key, - (err) => { + err => { const searchOps = { user_id: ObjectId(user_id), - key: notification_key + key: notification_key, } const updateOperation = { - $unset: { templateKey: true } + $unset: { templateKey: true }, } assert.deepEqual(this.updateOneStub.args[0][0], searchOps) assert.deepEqual(this.updateOneStub.args[0][1], updateOperation) @@ -272,7 +272,7 @@ describe('Notifications Tests', function () { return this.notifications.removeNotificationByKeyOnly( notification_key, - (err) => { + err => { const searchOps = { key: notification_key } const updateOperation = { $unset: { templateKey: true } } assert.deepEqual(this.updateOneStub.args[0][0], searchOps) @@ -289,7 +289,7 @@ describe('Notifications Tests', function () { return this.notifications.deleteNotificationByKeyOnly( notification_key, - (err) => { + err => { const searchOps = { key: notification_key } assert.deepEqual(this.deleteOneStub.args[0][0], searchOps) return done()