mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[misc] migrate the app to the native mongo driver
health-check to follow in a separate commit
This commit is contained in:
parent
a4f1124215
commit
d77834ab55
6 changed files with 82 additions and 65 deletions
|
@ -15,6 +15,7 @@ const app = express()
|
||||||
const methodOverride = require('method-override')
|
const methodOverride = require('method-override')
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser')
|
||||||
const errorHandler = require('errorhandler')
|
const errorHandler = require('errorhandler')
|
||||||
|
const mongodb = require('./app/js/mongodb')
|
||||||
const controller = require('./app/js/NotificationsController')
|
const controller = require('./app/js/NotificationsController')
|
||||||
|
|
||||||
metrics.memory.monitor(logger)
|
metrics.memory.monitor(logger)
|
||||||
|
@ -62,9 +63,18 @@ const port =
|
||||||
Settings.internal != null ? Settings.internal.notifications : undefined,
|
Settings.internal != null ? Settings.internal.notifications : undefined,
|
||||||
(x1) => x1.port
|
(x1) => x1.port
|
||||||
) || 3042
|
) || 3042
|
||||||
app.listen(port, host, () =>
|
|
||||||
logger.info(`notifications starting up, listening on ${host}:${port}`)
|
mongodb
|
||||||
)
|
.waitForDb()
|
||||||
|
.then(() => {
|
||||||
|
app.listen(port, host, () =>
|
||||||
|
logger.info(`notifications starting up, listening on ${host}:${port}`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
logger.fatal({ err }, 'Cannot connect to mongo. Exiting.')
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
||||||
function __guard__(value, transform) {
|
function __guard__(value, transform) {
|
||||||
return typeof value !== 'undefined' && value !== null
|
return typeof value !== 'undefined' && value !== null
|
||||||
|
|
|
@ -12,13 +12,8 @@
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
let Notifications
|
let Notifications
|
||||||
const Settings = require('settings-sharelatex')
|
|
||||||
const logger = require('logger-sharelatex')
|
const logger = require('logger-sharelatex')
|
||||||
const mongojs = require('mongojs')
|
const { db, ObjectId } = require('./mongodb')
|
||||||
const db = mongojs(Settings.mongo != null ? Settings.mongo.url : undefined, [
|
|
||||||
'notifications'
|
|
||||||
])
|
|
||||||
const { ObjectId } = require('mongojs')
|
|
||||||
const metrics = require('metrics-sharelatex')
|
const metrics = require('metrics-sharelatex')
|
||||||
|
|
||||||
module.exports = Notifications = {
|
module.exports = Notifications = {
|
||||||
|
@ -30,9 +25,7 @@ module.exports = Notifications = {
|
||||||
user_id: ObjectId(user_id),
|
user_id: ObjectId(user_id),
|
||||||
templateKey: { $exists: true }
|
templateKey: { $exists: true }
|
||||||
}
|
}
|
||||||
return db.notifications.find(query, (err, notifications) =>
|
db.notifications.find(query).toArray(callback)
|
||||||
callback(err, notifications)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_countExistingNotifications(user_id, notification, callback) {
|
_countExistingNotifications(user_id, notification, callback) {
|
||||||
|
@ -85,7 +78,7 @@ module.exports = Notifications = {
|
||||||
return callback(err)
|
return callback(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return db.notifications.update(
|
db.notifications.updateOne(
|
||||||
{ user_id: doc.user_id, key: notification.key },
|
{ user_id: doc.user_id, key: notification.key },
|
||||||
{ $set: doc },
|
{ $set: doc },
|
||||||
{ upsert: true },
|
{ upsert: true },
|
||||||
|
@ -100,7 +93,7 @@ module.exports = Notifications = {
|
||||||
_id: ObjectId(notification_id)
|
_id: ObjectId(notification_id)
|
||||||
}
|
}
|
||||||
const updateOperation = { $unset: { templateKey: true, messageOpts: true } }
|
const updateOperation = { $unset: { templateKey: true, messageOpts: true } }
|
||||||
return db.notifications.update(searchOps, updateOperation, callback)
|
db.notifications.updateOne(searchOps, updateOperation, callback)
|
||||||
},
|
},
|
||||||
|
|
||||||
removeNotificationKey(user_id, notification_key, callback) {
|
removeNotificationKey(user_id, notification_key, callback) {
|
||||||
|
@ -109,19 +102,19 @@ module.exports = Notifications = {
|
||||||
key: notification_key
|
key: notification_key
|
||||||
}
|
}
|
||||||
const updateOperation = { $unset: { templateKey: true } }
|
const updateOperation = { $unset: { templateKey: true } }
|
||||||
return db.notifications.update(searchOps, updateOperation, callback)
|
db.notifications.updateOne(searchOps, updateOperation, callback)
|
||||||
},
|
},
|
||||||
|
|
||||||
removeNotificationByKeyOnly(notification_key, callback) {
|
removeNotificationByKeyOnly(notification_key, callback) {
|
||||||
const searchOps = { key: notification_key }
|
const searchOps = { key: notification_key }
|
||||||
const updateOperation = { $unset: { templateKey: true } }
|
const updateOperation = { $unset: { templateKey: true } }
|
||||||
return db.notifications.update(searchOps, updateOperation, callback)
|
db.notifications.updateOne(searchOps, updateOperation, callback)
|
||||||
},
|
},
|
||||||
|
|
||||||
// hard delete of doc, rather than removing the templateKey
|
// hard delete of doc, rather than removing the templateKey
|
||||||
deleteNotificationByKeyOnly(notification_key, callback) {
|
deleteNotificationByKeyOnly(notification_key, callback) {
|
||||||
const searchOps = { key: notification_key }
|
const searchOps = { key: notification_key }
|
||||||
return db.notifications.remove(searchOps, { justOne: true }, callback)
|
db.notifications.deleteOne(searchOps, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;['getUserNotifications', 'addNotification'].map((method) =>
|
;['getUserNotifications', 'addNotification'].map((method) =>
|
||||||
|
|
21
services/notifications/app/js/mongodb.js
Normal file
21
services/notifications/app/js/mongodb.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
const Settings = require('settings-sharelatex')
|
||||||
|
const { MongoClient, ObjectId } = require('mongodb')
|
||||||
|
|
||||||
|
const clientPromise = MongoClient.connect(Settings.mongo.url)
|
||||||
|
|
||||||
|
async function waitForDb() {
|
||||||
|
await clientPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = {}
|
||||||
|
waitForDb().then(async function () {
|
||||||
|
const internalDb = (await clientPromise).db()
|
||||||
|
|
||||||
|
db.notifications = internalDb.collection('notifications')
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
db,
|
||||||
|
ObjectId,
|
||||||
|
waitForDb
|
||||||
|
}
|
20
services/notifications/package-lock.json
generated
20
services/notifications/package-lock.json
generated
|
@ -1471,9 +1471,9 @@
|
||||||
"integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ="
|
"integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ="
|
||||||
},
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
|
||||||
"integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==",
|
"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"readable-stream": "^2.3.5",
|
"readable-stream": "^2.3.5",
|
||||||
"safe-buffer": "^5.1.1"
|
"safe-buffer": "^5.1.1"
|
||||||
|
@ -1542,9 +1542,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"bson": {
|
"bson": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz",
|
||||||
"integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q=="
|
"integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg=="
|
||||||
},
|
},
|
||||||
"buffer-equal-constant-time": {
|
"buffer-equal-constant-time": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -4507,12 +4507,12 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"mongodb": {
|
"mongodb": {
|
||||||
"version": "3.5.5",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.0.tgz",
|
||||||
"integrity": "sha512-GCjDxR3UOltDq00Zcpzql6dQo1sVry60OXJY3TDmFc2SWFY6c8Gn1Ardidc5jDirvJrx2GC3knGOImKphbSL3A==",
|
"integrity": "sha512-/XWWub1mHZVoqEsUppE0GV7u9kanLvHxho6EvBxQbShXTKYF9trhZC2NzbulRGeG7xMJHD8IOWRcdKx5LPjAjQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bl": "^2.2.0",
|
"bl": "^2.2.0",
|
||||||
"bson": "^1.1.1",
|
"bson": "^1.1.4",
|
||||||
"denque": "^1.4.1",
|
"denque": "^1.4.1",
|
||||||
"require_optional": "^1.0.1",
|
"require_optional": "^1.0.1",
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
"logger-sharelatex": "^2.2.0",
|
"logger-sharelatex": "^2.2.0",
|
||||||
"method-override": "^3.0.0",
|
"method-override": "^3.0.0",
|
||||||
"metrics-sharelatex": "^2.6.2",
|
"metrics-sharelatex": "^2.6.2",
|
||||||
|
"mongodb": "^3.6.0",
|
||||||
"mongojs": "^3.1.0",
|
"mongojs": "^3.1.0",
|
||||||
"node-statsd": "0.1.1",
|
"node-statsd": "0.1.1",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
|
|
|
@ -19,7 +19,7 @@ const should = chai.should()
|
||||||
const modulePath = '../../../app/js/Notifications.js'
|
const modulePath = '../../../app/js/Notifications.js'
|
||||||
const SandboxedModule = require('sandboxed-module')
|
const SandboxedModule = require('sandboxed-module')
|
||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const { ObjectId } = require('mongojs')
|
const { ObjectId } = require('mongodb')
|
||||||
|
|
||||||
const user_id = '51dc93e6fb625a261300003b'
|
const user_id = '51dc93e6fb625a261300003b'
|
||||||
const notification_id = 'fb625a26f09d'
|
const notification_id = 'fb625a26f09d'
|
||||||
|
@ -27,25 +27,19 @@ const notification_key = 'notification-key'
|
||||||
|
|
||||||
describe('Notifications Tests', function () {
|
describe('Notifications Tests', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
const self = this
|
this.findToArrayStub = sinon.stub()
|
||||||
this.findStub = sinon.stub()
|
this.findStub = sinon.stub().returns({ toArray: this.findToArrayStub })
|
||||||
this.insertStub = sinon.stub()
|
|
||||||
this.countStub = sinon.stub()
|
this.countStub = sinon.stub()
|
||||||
this.updateStub = sinon.stub()
|
this.updateOneStub = sinon.stub()
|
||||||
this.removeStub = sinon.stub()
|
this.deleteOneStub = sinon.stub()
|
||||||
this.mongojs = () => {
|
this.db = {
|
||||||
return {
|
notifications: {
|
||||||
notifications: {
|
find: this.findStub,
|
||||||
update: self.mongojsUpdate,
|
count: this.countStub,
|
||||||
find: this.findStub,
|
updateOne: this.updateOneStub,
|
||||||
insert: this.insertStub,
|
deleteOne: this.deleteOneStub
|
||||||
count: this.countStub,
|
|
||||||
update: this.updateStub,
|
|
||||||
remove: this.removeStub
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.mongojs.ObjectId = ObjectId
|
|
||||||
|
|
||||||
this.notifications = SandboxedModule.require(modulePath, {
|
this.notifications = SandboxedModule.require(modulePath, {
|
||||||
requires: {
|
requires: {
|
||||||
|
@ -54,7 +48,7 @@ describe('Notifications Tests', function () {
|
||||||
error() {}
|
error() {}
|
||||||
},
|
},
|
||||||
'settings-sharelatex': {},
|
'settings-sharelatex': {},
|
||||||
mongojs: this.mongojs,
|
'./mongodb': { db: this.db, ObjectId },
|
||||||
'metrics-sharelatex': { timeAsyncMethod: sinon.stub() }
|
'metrics-sharelatex': { timeAsyncMethod: sinon.stub() }
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
|
@ -73,7 +67,7 @@ describe('Notifications Tests', function () {
|
||||||
|
|
||||||
describe('getUserNotifications', function () {
|
describe('getUserNotifications', function () {
|
||||||
return it('should find all notifications and return i', function (done) {
|
return it('should find all notifications and return i', function (done) {
|
||||||
this.findStub.callsArgWith(1, null, this.stubbedNotificationArray)
|
this.findToArrayStub.callsArgWith(0, null, this.stubbedNotificationArray)
|
||||||
return this.notifications.getUserNotifications(
|
return this.notifications.getUserNotifications(
|
||||||
user_id,
|
user_id,
|
||||||
(err, notifications) => {
|
(err, notifications) => {
|
||||||
|
@ -106,7 +100,7 @@ describe('Notifications Tests', function () {
|
||||||
user_id: this.stubbedNotification.user_id,
|
user_id: this.stubbedNotification.user_id,
|
||||||
key: 'notification-key'
|
key: 'notification-key'
|
||||||
}
|
}
|
||||||
this.updateStub.yields()
|
this.updateOneStub.yields()
|
||||||
return this.countStub.yields(null, 0)
|
return this.countStub.yields(null, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -117,7 +111,7 @@ describe('Notifications Tests', function () {
|
||||||
(err) => {
|
(err) => {
|
||||||
expect(err).not.exists
|
expect(err).not.exists
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.updateStub,
|
this.updateOneStub,
|
||||||
this.expectedQuery,
|
this.expectedQuery,
|
||||||
{ $set: this.expectedDocument },
|
{ $set: this.expectedDocument },
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
|
@ -138,7 +132,7 @@ describe('Notifications Tests', function () {
|
||||||
this.stubbedNotification,
|
this.stubbedNotification,
|
||||||
(err) => {
|
(err) => {
|
||||||
expect(err).not.exists
|
expect(err).not.exists
|
||||||
sinon.assert.notCalled(this.updateStub)
|
sinon.assert.notCalled(this.updateOneStub)
|
||||||
return done()
|
return done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -152,7 +146,7 @@ describe('Notifications Tests', function () {
|
||||||
(err) => {
|
(err) => {
|
||||||
expect(err).not.exists
|
expect(err).not.exists
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.updateStub,
|
this.updateOneStub,
|
||||||
this.expectedQuery,
|
this.expectedQuery,
|
||||||
{ $set: this.expectedDocument },
|
{ $set: this.expectedDocument },
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
|
@ -192,7 +186,7 @@ describe('Notifications Tests', function () {
|
||||||
(err) => {
|
(err) => {
|
||||||
expect(err).not.exists
|
expect(err).not.exists
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.updateStub,
|
this.updateOneStub,
|
||||||
this.expectedQuery,
|
this.expectedQuery,
|
||||||
{ $set: this.expectedDocument },
|
{ $set: this.expectedDocument },
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
|
@ -227,7 +221,7 @@ describe('Notifications Tests', function () {
|
||||||
this.stubbedNotification,
|
this.stubbedNotification,
|
||||||
(err) => {
|
(err) => {
|
||||||
;(err instanceof Error).should.equal(true)
|
;(err instanceof Error).should.equal(true)
|
||||||
sinon.assert.notCalled(this.updateStub)
|
sinon.assert.notCalled(this.updateOneStub)
|
||||||
return done()
|
return done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -237,7 +231,7 @@ describe('Notifications Tests', function () {
|
||||||
|
|
||||||
describe('removeNotificationId', function () {
|
describe('removeNotificationId', function () {
|
||||||
return it('should mark the notification id as read', function (done) {
|
return it('should mark the notification id as read', function (done) {
|
||||||
this.updateStub.callsArgWith(2, null)
|
this.updateOneStub.callsArgWith(2, null)
|
||||||
|
|
||||||
return this.notifications.removeNotificationId(
|
return this.notifications.removeNotificationId(
|
||||||
user_id,
|
user_id,
|
||||||
|
@ -250,8 +244,8 @@ describe('Notifications Tests', function () {
|
||||||
const updateOperation = {
|
const updateOperation = {
|
||||||
$unset: { templateKey: true, messageOpts: true }
|
$unset: { templateKey: true, messageOpts: true }
|
||||||
}
|
}
|
||||||
assert.deepEqual(this.updateStub.args[0][0], searchOps)
|
assert.deepEqual(this.updateOneStub.args[0][0], searchOps)
|
||||||
assert.deepEqual(this.updateStub.args[0][1], updateOperation)
|
assert.deepEqual(this.updateOneStub.args[0][1], updateOperation)
|
||||||
return done()
|
return done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -260,7 +254,7 @@ describe('Notifications Tests', function () {
|
||||||
|
|
||||||
describe('removeNotificationKey', function () {
|
describe('removeNotificationKey', function () {
|
||||||
return it('should mark the notification key as read', function (done) {
|
return it('should mark the notification key as read', function (done) {
|
||||||
this.updateStub.callsArgWith(2, null)
|
this.updateOneStub.callsArgWith(2, null)
|
||||||
|
|
||||||
return this.notifications.removeNotificationKey(
|
return this.notifications.removeNotificationKey(
|
||||||
user_id,
|
user_id,
|
||||||
|
@ -273,8 +267,8 @@ describe('Notifications Tests', function () {
|
||||||
const updateOperation = {
|
const updateOperation = {
|
||||||
$unset: { templateKey: true }
|
$unset: { templateKey: true }
|
||||||
}
|
}
|
||||||
assert.deepEqual(this.updateStub.args[0][0], searchOps)
|
assert.deepEqual(this.updateOneStub.args[0][0], searchOps)
|
||||||
assert.deepEqual(this.updateStub.args[0][1], updateOperation)
|
assert.deepEqual(this.updateOneStub.args[0][1], updateOperation)
|
||||||
return done()
|
return done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -283,15 +277,15 @@ describe('Notifications Tests', function () {
|
||||||
|
|
||||||
describe('removeNotificationByKeyOnly', function () {
|
describe('removeNotificationByKeyOnly', function () {
|
||||||
return it('should mark the notification key as read', function (done) {
|
return it('should mark the notification key as read', function (done) {
|
||||||
this.updateStub.callsArgWith(2, null)
|
this.updateOneStub.callsArgWith(2, null)
|
||||||
|
|
||||||
return this.notifications.removeNotificationByKeyOnly(
|
return this.notifications.removeNotificationByKeyOnly(
|
||||||
notification_key,
|
notification_key,
|
||||||
(err) => {
|
(err) => {
|
||||||
const searchOps = { key: notification_key }
|
const searchOps = { key: notification_key }
|
||||||
const updateOperation = { $unset: { templateKey: true } }
|
const updateOperation = { $unset: { templateKey: true } }
|
||||||
assert.deepEqual(this.updateStub.args[0][0], searchOps)
|
assert.deepEqual(this.updateOneStub.args[0][0], searchOps)
|
||||||
assert.deepEqual(this.updateStub.args[0][1], updateOperation)
|
assert.deepEqual(this.updateOneStub.args[0][1], updateOperation)
|
||||||
return done()
|
return done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -300,15 +294,13 @@ describe('Notifications Tests', function () {
|
||||||
|
|
||||||
return describe('deleteNotificationByKeyOnly', function () {
|
return describe('deleteNotificationByKeyOnly', function () {
|
||||||
return it('should completely remove the notification', function (done) {
|
return it('should completely remove the notification', function (done) {
|
||||||
this.removeStub.callsArgWith(2, null)
|
this.deleteOneStub.callsArgWith(1, null)
|
||||||
|
|
||||||
return this.notifications.deleteNotificationByKeyOnly(
|
return this.notifications.deleteNotificationByKeyOnly(
|
||||||
notification_key,
|
notification_key,
|
||||||
(err) => {
|
(err) => {
|
||||||
const searchOps = { key: notification_key }
|
const searchOps = { key: notification_key }
|
||||||
const opts = { justOne: true }
|
assert.deepEqual(this.deleteOneStub.args[0][0], searchOps)
|
||||||
assert.deepEqual(this.removeStub.args[0][0], searchOps)
|
|
||||||
assert.deepEqual(this.removeStub.args[0][1], opts)
|
|
||||||
return done()
|
return done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue