diff --git a/services/chat/app/js/Features/Messages/MessageFormatter.js b/services/chat/app/js/Features/Messages/MessageFormatter.js index d928b29ccc..fe230f5587 100644 --- a/services/chat/app/js/Features/Messages/MessageFormatter.js +++ b/services/chat/app/js/Features/Messages/MessageFormatter.js @@ -11,66 +11,70 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let MessageFormatter; -module.exports = (MessageFormatter = { - formatMessageForClientSide(message) { - if (message._id != null) { - message.id = message._id.toString(); - delete message._id; - } - const formattedMessage = { - id: message.id, - content: message.content, - timestamp: message.timestamp, - user_id: message.user_id - }; - if (message.edited_at != null) { - formattedMessage.edited_at = message.edited_at; - } - return formattedMessage; - }, +let MessageFormatter +module.exports = MessageFormatter = { + formatMessageForClientSide(message) { + if (message._id != null) { + message.id = message._id.toString() + delete message._id + } + const formattedMessage = { + id: message.id, + content: message.content, + timestamp: message.timestamp, + user_id: message.user_id + } + if (message.edited_at != null) { + formattedMessage.edited_at = message.edited_at + } + return formattedMessage + }, - formatMessagesForClientSide(messages) { - return (Array.from(messages).map((message) => this.formatMessageForClientSide(message))); - }, - - groupMessagesByThreads(rooms, messages) { - let room, thread; - const rooms_by_id = {}; - for (room of Array.from(rooms)) { - rooms_by_id[room._id.toString()] = room; - } + formatMessagesForClientSide(messages) { + return Array.from(messages).map(message => + this.formatMessageForClientSide(message) + ) + }, - const threads = {}; - const getThread = function(room) { - const thread_id = room.thread_id.toString(); - if (threads[thread_id] != null) { - return threads[thread_id]; - } else { - const thread = { messages: [] }; - if (room.resolved != null) { - thread.resolved = true; - thread.resolved_at = room.resolved.ts; - thread.resolved_by_user_id = room.resolved.user_id; - } - threads[thread_id] = thread; - return thread; - } - }; - - for (let message of Array.from(messages)) { - room = rooms_by_id[message.room_id.toString()]; - if (room != null) { - thread = getThread(room); - thread.messages.push(MessageFormatter.formatMessageForClientSide(message)); - } - } - - for (let thread_id in threads) { - thread = threads[thread_id]; - thread.messages.sort((a,b) => a.timestamp - b.timestamp); - } - - return threads; - } -}); \ No newline at end of file + groupMessagesByThreads(rooms, messages) { + let room, thread + const rooms_by_id = {} + for (room of Array.from(rooms)) { + rooms_by_id[room._id.toString()] = room + } + + const threads = {} + const getThread = function(room) { + const thread_id = room.thread_id.toString() + if (threads[thread_id] != null) { + return threads[thread_id] + } else { + const thread = { messages: [] } + if (room.resolved != null) { + thread.resolved = true + thread.resolved_at = room.resolved.ts + thread.resolved_by_user_id = room.resolved.user_id + } + threads[thread_id] = thread + return thread + } + } + + for (let message of Array.from(messages)) { + room = rooms_by_id[message.room_id.toString()] + if (room != null) { + thread = getThread(room) + thread.messages.push( + MessageFormatter.formatMessageForClientSide(message) + ) + } + } + + for (let thread_id in threads) { + thread = threads[thread_id] + thread.messages.sort((a, b) => a.timestamp - b.timestamp) + } + + return threads + } +} diff --git a/services/chat/app/js/Features/Messages/MessageHttpController.js b/services/chat/app/js/Features/Messages/MessageHttpController.js index f913c594d8..cac289c494 100644 --- a/services/chat/app/js/Features/Messages/MessageHttpController.js +++ b/services/chat/app/js/Features/Messages/MessageHttpController.js @@ -11,148 +11,248 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let MessageHttpController; -const logger = require("logger-sharelatex"); -const metrics = require("metrics-sharelatex"); -const MessageManager = require("./MessageManager"); -const MessageFormatter = require("./MessageFormatter"); -const ThreadManager = require("../Threads/ThreadManager"); -const {ObjectId} = require("../../mongojs"); +let MessageHttpController +const logger = require('logger-sharelatex') +const metrics = require('metrics-sharelatex') +const MessageManager = require('./MessageManager') +const MessageFormatter = require('./MessageFormatter') +const ThreadManager = require('../Threads/ThreadManager') +const { ObjectId } = require('../../mongojs') -module.exports = (MessageHttpController = { - DEFAULT_MESSAGE_LIMIT: 50, - MAX_MESSAGE_LENGTH: 10 * 1024, // 10kb, about 1,500 words - - getGlobalMessages(req, res, next) { - return MessageHttpController._getMessages(ThreadManager.GLOBAL_THREAD, req, res, next); - }, +module.exports = MessageHttpController = { + DEFAULT_MESSAGE_LIMIT: 50, + MAX_MESSAGE_LENGTH: 10 * 1024, // 10kb, about 1,500 words - sendGlobalMessage(req, res, next) { - return MessageHttpController._sendMessage(ThreadManager.GLOBAL_THREAD, req, res, next); - }, - - sendThreadMessage(req, res, next) { - return MessageHttpController._sendMessage(req.params.thread_id, req, res, next); - }, - - getAllThreads(req, res, next) { - const {project_id} = req.params; - logger.log({project_id}, "getting all threads"); - return ThreadManager.findAllThreadRooms(project_id, function(error, rooms) { - if (error != null) { return next(error); } - const room_ids = rooms.map(r => r._id); - return MessageManager.findAllMessagesInRooms(room_ids, function(error, messages) { - if (error != null) { return next(error); } - const threads = MessageFormatter.groupMessagesByThreads(rooms, messages); - return res.json(threads); - }); - }); - }, - - resolveThread(req, res, next) { - const {project_id, thread_id} = req.params; - const {user_id} = req.body; - logger.log({user_id, project_id, thread_id}, "marking thread as resolved"); - return ThreadManager.resolveThread(project_id, thread_id, user_id, function(error) { - if (error != null) { return next(error); } - return res.send(204); - }); - }, // No content + getGlobalMessages(req, res, next) { + return MessageHttpController._getMessages( + ThreadManager.GLOBAL_THREAD, + req, + res, + next + ) + }, - reopenThread(req, res, next) { - const {project_id, thread_id} = req.params; - logger.log({project_id, thread_id}, "reopening thread"); - return ThreadManager.reopenThread(project_id, thread_id, function(error) { - if (error != null) { return next(error); } - return res.send(204); - }); - }, // No content - - deleteThread(req, res, next) { - const {project_id, thread_id} = req.params; - logger.log({project_id, thread_id}, "deleting thread"); - return ThreadManager.deleteThread(project_id, thread_id, function(error, room_id) { - if (error != null) { return next(error); } - return MessageManager.deleteAllMessagesInRoom(room_id, function(error) { - if (error != null) { return next(error); } - return res.send(204); - }); - }); - }, // No content - - editMessage(req, res, next) { - const {content} = req != null ? req.body : undefined; - const {project_id, thread_id, message_id} = req.params; - logger.log({project_id, thread_id, message_id, content}, "editing message"); - return ThreadManager.findOrCreateThread(project_id, thread_id, function(error, room) { - if (error != null) { return next(error); } - return MessageManager.updateMessage(room._id, message_id, content, Date.now(), function(error) { - if (error != null) { return next(error); } - return res.send(204); - }); - }); - }, + sendGlobalMessage(req, res, next) { + return MessageHttpController._sendMessage( + ThreadManager.GLOBAL_THREAD, + req, + res, + next + ) + }, - deleteMessage(req, res, next) { - const {project_id, thread_id, message_id} = req.params; - logger.log({project_id, thread_id, message_id}, "deleting message"); - return ThreadManager.findOrCreateThread(project_id, thread_id, function(error, room) { - if (error != null) { return next(error); } - return MessageManager.deleteMessage(room._id, message_id, function(error, message) { - if (error != null) { return next(error); } - return res.send(204); - }); - }); - }, + sendThreadMessage(req, res, next) { + return MessageHttpController._sendMessage( + req.params.thread_id, + req, + res, + next + ) + }, - _sendMessage(client_thread_id, req, res, next) { - const {user_id, content} = req != null ? req.body : undefined; - const {project_id} = req.params; - if (!ObjectId.isValid(user_id)) { - return res.send(400, "Invalid user_id"); - } - if ((content == null)) { - return res.send(400, "No content provided"); - } - if (content.length > this.MAX_MESSAGE_LENGTH) { - return res.send(400, `Content too long (> ${this.MAX_MESSAGE_LENGTH} bytes)`); - } - logger.log({client_thread_id, project_id, user_id, content}, "new message received"); - return ThreadManager.findOrCreateThread(project_id, client_thread_id, function(error, thread) { - if (error != null) { return next(error); } - return MessageManager.createMessage(thread._id, user_id, content, Date.now(), function(error, message) { - if (error != null) { return next(error); } - message = MessageFormatter.formatMessageForClientSide(message); - message.room_id = project_id; - return res.send(201, message); - }); - }); - }, + getAllThreads(req, res, next) { + const { project_id } = req.params + logger.log({ project_id }, 'getting all threads') + return ThreadManager.findAllThreadRooms(project_id, function(error, rooms) { + if (error != null) { + return next(error) + } + const room_ids = rooms.map(r => r._id) + return MessageManager.findAllMessagesInRooms(room_ids, function( + error, + messages + ) { + if (error != null) { + return next(error) + } + const threads = MessageFormatter.groupMessagesByThreads(rooms, messages) + return res.json(threads) + }) + }) + }, - _getMessages(client_thread_id, req, res, next) { - let before, limit; - const {project_id} = req.params; - if ((req.query != null ? req.query.before : undefined) != null) { - before = parseInt(req.query.before, 10); - } else { - before = null; - } - if ((req.query != null ? req.query.limit : undefined) != null) { - limit = parseInt(req.query.limit, 10); - } else { - limit = MessageHttpController.DEFAULT_MESSAGE_LIMIT; - } - logger.log({limit, before, project_id, client_thread_id}, "get message request received"); - return ThreadManager.findOrCreateThread(project_id, client_thread_id, function(error, thread) { - if (error != null) { return next(error); } - const thread_object_id = thread._id; - logger.log({limit, before, project_id, client_thread_id, thread_object_id}, "found or created thread"); - return MessageManager.getMessages(thread_object_id, limit, before, function(error, messages) { - if (error != null) { return next(error); } - messages = MessageFormatter.formatMessagesForClientSide(messages); - logger.log({project_id, messages}, "got messages"); - return res.send(200, messages); - }); - }); - } -}); + resolveThread(req, res, next) { + const { project_id, thread_id } = req.params + const { user_id } = req.body + logger.log({ user_id, project_id, thread_id }, 'marking thread as resolved') + return ThreadManager.resolveThread(project_id, thread_id, user_id, function( + error + ) { + if (error != null) { + return next(error) + } + return res.send(204) + }) + }, // No content + + reopenThread(req, res, next) { + const { project_id, thread_id } = req.params + logger.log({ project_id, thread_id }, 'reopening thread') + return ThreadManager.reopenThread(project_id, thread_id, function(error) { + if (error != null) { + return next(error) + } + return res.send(204) + }) + }, // No content + + deleteThread(req, res, next) { + const { project_id, thread_id } = req.params + logger.log({ project_id, thread_id }, 'deleting thread') + return ThreadManager.deleteThread(project_id, thread_id, function( + error, + room_id + ) { + if (error != null) { + return next(error) + } + return MessageManager.deleteAllMessagesInRoom(room_id, function(error) { + if (error != null) { + return next(error) + } + return res.send(204) + }) + }) + }, // No content + + editMessage(req, res, next) { + const { content } = req != null ? req.body : undefined + const { project_id, thread_id, message_id } = req.params + logger.log( + { project_id, thread_id, message_id, content }, + 'editing message' + ) + return ThreadManager.findOrCreateThread(project_id, thread_id, function( + error, + room + ) { + if (error != null) { + return next(error) + } + return MessageManager.updateMessage( + room._id, + message_id, + content, + Date.now(), + function(error) { + if (error != null) { + return next(error) + } + return res.send(204) + } + ) + }) + }, + + deleteMessage(req, res, next) { + const { project_id, thread_id, message_id } = req.params + logger.log({ project_id, thread_id, message_id }, 'deleting message') + return ThreadManager.findOrCreateThread(project_id, thread_id, function( + error, + room + ) { + if (error != null) { + return next(error) + } + return MessageManager.deleteMessage(room._id, message_id, function( + error, + message + ) { + if (error != null) { + return next(error) + } + return res.send(204) + }) + }) + }, + + _sendMessage(client_thread_id, req, res, next) { + const { user_id, content } = req != null ? req.body : undefined + const { project_id } = req.params + if (!ObjectId.isValid(user_id)) { + return res.send(400, 'Invalid user_id') + } + if (content == null) { + return res.send(400, 'No content provided') + } + if (content.length > this.MAX_MESSAGE_LENGTH) { + return res.send( + 400, + `Content too long (> ${this.MAX_MESSAGE_LENGTH} bytes)` + ) + } + logger.log( + { client_thread_id, project_id, user_id, content }, + 'new message received' + ) + return ThreadManager.findOrCreateThread( + project_id, + client_thread_id, + function(error, thread) { + if (error != null) { + return next(error) + } + return MessageManager.createMessage( + thread._id, + user_id, + content, + Date.now(), + function(error, message) { + if (error != null) { + return next(error) + } + message = MessageFormatter.formatMessageForClientSide(message) + message.room_id = project_id + return res.send(201, message) + } + ) + } + ) + }, + + _getMessages(client_thread_id, req, res, next) { + let before, limit + const { project_id } = req.params + if ((req.query != null ? req.query.before : undefined) != null) { + before = parseInt(req.query.before, 10) + } else { + before = null + } + if ((req.query != null ? req.query.limit : undefined) != null) { + limit = parseInt(req.query.limit, 10) + } else { + limit = MessageHttpController.DEFAULT_MESSAGE_LIMIT + } + logger.log( + { limit, before, project_id, client_thread_id }, + 'get message request received' + ) + return ThreadManager.findOrCreateThread( + project_id, + client_thread_id, + function(error, thread) { + if (error != null) { + return next(error) + } + const thread_object_id = thread._id + logger.log( + { limit, before, project_id, client_thread_id, thread_object_id }, + 'found or created thread' + ) + return MessageManager.getMessages( + thread_object_id, + limit, + before, + function(error, messages) { + if (error != null) { + return next(error) + } + messages = MessageFormatter.formatMessagesForClientSide(messages) + logger.log({ project_id, messages }, 'got messages') + return res.send(200, messages) + } + ) + } + ) + } +} diff --git a/services/chat/app/js/Features/Messages/MessageManager.js b/services/chat/app/js/Features/Messages/MessageManager.js index 3bc542a20b..0344aed97d 100644 --- a/services/chat/app/js/Features/Messages/MessageManager.js +++ b/services/chat/app/js/Features/Messages/MessageManager.js @@ -12,101 +12,135 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let MessageManager; -const mongojs = require("../../mongojs"); -const { db } = mongojs; -const { ObjectId } = mongojs; -const async = require("async"); -const metrics = require('metrics-sharelatex'); -const logger = require('logger-sharelatex'); +let MessageManager +const mongojs = require('../../mongojs') +const { db } = mongojs +const { ObjectId } = mongojs +const async = require('async') +const metrics = require('metrics-sharelatex') +const logger = require('logger-sharelatex') -module.exports = (MessageManager = { - createMessage(room_id, user_id, content, timestamp, callback) { - if (callback == null) { callback = function(error, message) {}; } - let newMessageOpts = { - content, - room_id, - user_id, - timestamp - }; - newMessageOpts = this._ensureIdsAreObjectIds(newMessageOpts); - return db.messages.save(newMessageOpts, callback); - }, +module.exports = MessageManager = { + createMessage(room_id, user_id, content, timestamp, callback) { + if (callback == null) { + callback = function(error, message) {} + } + let newMessageOpts = { + content, + room_id, + user_id, + timestamp + } + newMessageOpts = this._ensureIdsAreObjectIds(newMessageOpts) + return db.messages.save(newMessageOpts, callback) + }, - getMessages(room_id, limit, before, callback) { - if (callback == null) { callback = function(error, messages) {}; } - let query = - {room_id}; - if (before != null) { - query.timestamp = { $lt: before }; - } - query = this._ensureIdsAreObjectIds(query); - const cursor = db.messages.find(query).sort({ timestamp: -1 }).limit(limit); - return cursor.toArray(callback); - }, - - findAllMessagesInRooms(room_ids, callback) { - if (callback == null) { callback = function(error, messages) {}; } - return db.messages.find({ - room_id: { $in: room_ids } - }, callback); - }, + getMessages(room_id, limit, before, callback) { + if (callback == null) { + callback = function(error, messages) {} + } + let query = { room_id } + if (before != null) { + query.timestamp = { $lt: before } + } + query = this._ensureIdsAreObjectIds(query) + const cursor = db.messages + .find(query) + .sort({ timestamp: -1 }) + .limit(limit) + return cursor.toArray(callback) + }, - deleteAllMessagesInRoom(room_id, callback) { - if (callback == null) { callback = function(error) {}; } - return db.messages.remove({ - room_id - }, callback); - }, - - updateMessage(room_id, message_id, content, timestamp, callback) { - if (callback == null) { callback = function(error, message) {}; } - const query = this._ensureIdsAreObjectIds({ - _id: message_id, - room_id - }); - return db.messages.update(query, { - $set: { - content, - edited_at: timestamp - } - }, function(error) { - if (error != null) { return callback(error); } - return callback(); - }); - }, + findAllMessagesInRooms(room_ids, callback) { + if (callback == null) { + callback = function(error, messages) {} + } + return db.messages.find( + { + room_id: { $in: room_ids } + }, + callback + ) + }, - deleteMessage(room_id, message_id, callback) { - if (callback == null) { callback = function(error) {}; } - const query = this._ensureIdsAreObjectIds({ - _id: message_id, - room_id - }); - return db.messages.remove(query, function(error) { - if (error != null) { return callback(error); } - return callback(); - }); - }, + deleteAllMessagesInRoom(room_id, callback) { + if (callback == null) { + callback = function(error) {} + } + return db.messages.remove( + { + room_id + }, + callback + ) + }, - _ensureIdsAreObjectIds(query) { - if ((query.user_id != null) && !(query.user_id instanceof ObjectId)) { - query.user_id = ObjectId(query.user_id); - } - if ((query.room_id != null) && !(query.room_id instanceof ObjectId)) { - query.room_id = ObjectId(query.room_id); - } - if ((query._id != null) && !(query._id instanceof ObjectId)) { - query._id = ObjectId(query._id); - } - return query; - } -}); + updateMessage(room_id, message_id, content, timestamp, callback) { + if (callback == null) { + callback = function(error, message) {} + } + const query = this._ensureIdsAreObjectIds({ + _id: message_id, + room_id + }) + return db.messages.update( + query, + { + $set: { + content, + edited_at: timestamp + } + }, + function(error) { + if (error != null) { + return callback(error) + } + return callback() + } + ) + }, + deleteMessage(room_id, message_id, callback) { + if (callback == null) { + callback = function(error) {} + } + const query = this._ensureIdsAreObjectIds({ + _id: message_id, + room_id + }) + return db.messages.remove(query, function(error) { + if (error != null) { + return callback(error) + } + return callback() + }) + }, -[ - 'createMessage', - 'getMessages', - 'findAllMessagesInRooms', - 'updateMessage', - 'deleteMessage' -].map(method => metrics.timeAsyncMethod(MessageManager, method, 'mongo.MessageManager', logger)); + _ensureIdsAreObjectIds(query) { + if (query.user_id != null && !(query.user_id instanceof ObjectId)) { + query.user_id = ObjectId(query.user_id) + } + if (query.room_id != null && !(query.room_id instanceof ObjectId)) { + query.room_id = ObjectId(query.room_id) + } + if (query._id != null && !(query._id instanceof ObjectId)) { + query._id = ObjectId(query._id) + } + return query + } +} + +;[ + 'createMessage', + 'getMessages', + 'findAllMessagesInRooms', + 'updateMessage', + 'deleteMessage' +].map(method => + metrics.timeAsyncMethod( + MessageManager, + method, + 'mongo.MessageManager', + logger + ) +) diff --git a/services/chat/app/js/Features/Threads/ThreadManager.js b/services/chat/app/js/Features/Threads/ThreadManager.js index 60a408bb4d..880f814eb3 100644 --- a/services/chat/app/js/Features/Threads/ThreadManager.js +++ b/services/chat/app/js/Features/Threads/ThreadManager.js @@ -11,110 +11,149 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let ThreadManager; -const mongojs = require("../../mongojs"); -const { db } = mongojs; -const { ObjectId } = mongojs; -const logger = require('logger-sharelatex'); -const metrics = require('metrics-sharelatex'); +let ThreadManager +const mongojs = require('../../mongojs') +const { db } = mongojs +const { ObjectId } = mongojs +const logger = require('logger-sharelatex') +const metrics = require('metrics-sharelatex') -module.exports = (ThreadManager = { - GLOBAL_THREAD: "GLOBAL", +module.exports = ThreadManager = { + GLOBAL_THREAD: 'GLOBAL', - findOrCreateThread(project_id, thread_id, callback) { - let query, update; - if (callback == null) { callback = function(error, thread) {}; } - project_id = ObjectId(project_id.toString()); - if (thread_id !== ThreadManager.GLOBAL_THREAD) { - thread_id = ObjectId(thread_id.toString()); - } + findOrCreateThread(project_id, thread_id, callback) { + let query, update + if (callback == null) { + callback = function(error, thread) {} + } + project_id = ObjectId(project_id.toString()) + if (thread_id !== ThreadManager.GLOBAL_THREAD) { + thread_id = ObjectId(thread_id.toString()) + } - if (thread_id === ThreadManager.GLOBAL_THREAD) { - query = { - project_id, - thread_id: { $exists: false } - }; - update = { - project_id - }; - } else { - query = { - project_id, - thread_id - }; - update = { - project_id, - thread_id - }; - } - - return db.rooms.update(query, update, { upsert: true }, function(error) { - if (error != null) { return callback(error); } - return db.rooms.find(query, function(error, rooms) { - if (rooms == null) { rooms = []; } - if (error != null) { return callback(error); } - return callback(null, rooms[0]); - }); - }); - }, - - findAllThreadRooms(project_id, callback) { - if (callback == null) { callback = function(error, rooms) {}; } - return db.rooms.find({ - project_id: ObjectId(project_id.toString()), - thread_id: { $exists: true } - }, { - thread_id: 1, - resolved: 1 - }, callback); - }, - - resolveThread(project_id, thread_id, user_id, callback) { - if (callback == null) { callback = function(error) {}; } - return db.rooms.update({ - project_id: ObjectId(project_id.toString()), - thread_id: ObjectId(thread_id.toString()) - }, { - $set: { - resolved: { - user_id, - ts: new Date() - } - } - }, callback); - }, - - reopenThread(project_id, thread_id, callback) { - if (callback == null) { callback = function(error) {}; } - return db.rooms.update({ - project_id: ObjectId(project_id.toString()), - thread_id: ObjectId(thread_id.toString()) - }, { - $unset: { - resolved: true - } - }, callback); - }, + if (thread_id === ThreadManager.GLOBAL_THREAD) { + query = { + project_id, + thread_id: { $exists: false } + } + update = { + project_id + } + } else { + query = { + project_id, + thread_id + } + update = { + project_id, + thread_id + } + } - deleteThread(project_id, thread_id, callback) { - if (callback == null) { callback = function(error, room_id) {}; } - return this.findOrCreateThread(project_id, thread_id, function(error, room) { - if (error != null) { return callback(error); } - return db.rooms.remove({ - _id: room._id - }, function(error) { - if (error != null) { return callback(error); } - return callback(null, room._id); - }); - }); - } -}); + return db.rooms.update(query, update, { upsert: true }, function(error) { + if (error != null) { + return callback(error) + } + return db.rooms.find(query, function(error, rooms) { + if (rooms == null) { + rooms = [] + } + if (error != null) { + return callback(error) + } + return callback(null, rooms[0]) + }) + }) + }, + findAllThreadRooms(project_id, callback) { + if (callback == null) { + callback = function(error, rooms) {} + } + return db.rooms.find( + { + project_id: ObjectId(project_id.toString()), + thread_id: { $exists: true } + }, + { + thread_id: 1, + resolved: 1 + }, + callback + ) + }, -[ - 'findOrCreateThread', - 'findAllThreadRooms', - 'resolveThread', - 'reopenThread', - 'deleteThread', -].map(method => metrics.timeAsyncMethod(ThreadManager, method, 'mongo.ThreadManager', logger)); + resolveThread(project_id, thread_id, user_id, callback) { + if (callback == null) { + callback = function(error) {} + } + return db.rooms.update( + { + project_id: ObjectId(project_id.toString()), + thread_id: ObjectId(thread_id.toString()) + }, + { + $set: { + resolved: { + user_id, + ts: new Date() + } + } + }, + callback + ) + }, + + reopenThread(project_id, thread_id, callback) { + if (callback == null) { + callback = function(error) {} + } + return db.rooms.update( + { + project_id: ObjectId(project_id.toString()), + thread_id: ObjectId(thread_id.toString()) + }, + { + $unset: { + resolved: true + } + }, + callback + ) + }, + + deleteThread(project_id, thread_id, callback) { + if (callback == null) { + callback = function(error, room_id) {} + } + return this.findOrCreateThread(project_id, thread_id, function( + error, + room + ) { + if (error != null) { + return callback(error) + } + return db.rooms.remove( + { + _id: room._id + }, + function(error) { + if (error != null) { + return callback(error) + } + return callback(null, room._id) + } + ) + }) + } +} + +;[ + 'findOrCreateThread', + 'findAllThreadRooms', + 'resolveThread', + 'reopenThread', + 'deleteThread' +].map(method => + metrics.timeAsyncMethod(ThreadManager, method, 'mongo.ThreadManager', logger) +) diff --git a/services/chat/app/js/mongojs.js b/services/chat/app/js/mongojs.js index 4182b6f8c0..f73f6fc93f 100644 --- a/services/chat/app/js/mongojs.js +++ b/services/chat/app/js/mongojs.js @@ -1,9 +1,9 @@ // TODO: This file was created by bulk-decaffeinate. // Sanity-check the conversion and remove this comment. -const Settings = require("settings-sharelatex"); -const mongojs = require("mongojs"); -const db = mongojs(Settings.mongo.url, ["rooms", "messages"]); +const Settings = require('settings-sharelatex') +const mongojs = require('mongojs') +const db = mongojs(Settings.mongo.url, ['rooms', 'messages']) module.exports = { - db, - ObjectId: mongojs.ObjectId -}; + db, + ObjectId: mongojs.ObjectId +} diff --git a/services/chat/app/js/router.js b/services/chat/app/js/router.js index 5a9f85b47a..b7e2164532 100644 --- a/services/chat/app/js/router.js +++ b/services/chat/app/js/router.js @@ -10,48 +10,75 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let Router; -const MessageHttpController = require('./Features/Messages/MessageHttpController'); -const {ObjectId} = require("./mongojs"); +let Router +const MessageHttpController = require('./Features/Messages/MessageHttpController') +const { ObjectId } = require('./mongojs') -module.exports = (Router = { - route(app) { - app.param('project_id', function(req, res, next, project_id) { - if (ObjectId.isValid(project_id)) { - return next(); - } else { - return res.send(400, "Invalid project_id"); - } - }); +module.exports = Router = { + route(app) { + app.param('project_id', function(req, res, next, project_id) { + if (ObjectId.isValid(project_id)) { + return next() + } else { + return res.send(400, 'Invalid project_id') + } + }) - app.param('thread_id', function(req, res, next, thread_id) { - if (ObjectId.isValid(thread_id)) { - return next(); - } else { - return res.send(400, "Invalid thread_id"); - } - }); + app.param('thread_id', function(req, res, next, thread_id) { + if (ObjectId.isValid(thread_id)) { + return next() + } else { + return res.send(400, 'Invalid thread_id') + } + }) - // These are for backwards compatibility - app.get("/room/:project_id/messages", MessageHttpController.getGlobalMessages); - app.post("/room/:project_id/messages", MessageHttpController.sendGlobalMessage); + // These are for backwards compatibility + app.get( + '/room/:project_id/messages', + MessageHttpController.getGlobalMessages + ) + app.post( + '/room/:project_id/messages', + MessageHttpController.sendGlobalMessage + ) - app.get("/project/:project_id/messages", MessageHttpController.getGlobalMessages); - app.post("/project/:project_id/messages", MessageHttpController.sendGlobalMessage); + app.get( + '/project/:project_id/messages', + MessageHttpController.getGlobalMessages + ) + app.post( + '/project/:project_id/messages', + MessageHttpController.sendGlobalMessage + ) - app.post("/project/:project_id/thread/:thread_id/messages", MessageHttpController.sendThreadMessage); - app.get("/project/:project_id/threads", MessageHttpController.getAllThreads); + app.post( + '/project/:project_id/thread/:thread_id/messages', + MessageHttpController.sendThreadMessage + ) + app.get('/project/:project_id/threads', MessageHttpController.getAllThreads) - app.post("/project/:project_id/thread/:thread_id/messages/:message_id/edit", MessageHttpController.editMessage); - app.del("/project/:project_id/thread/:thread_id/messages/:message_id", MessageHttpController.deleteMessage); + app.post( + '/project/:project_id/thread/:thread_id/messages/:message_id/edit', + MessageHttpController.editMessage + ) + app.del( + '/project/:project_id/thread/:thread_id/messages/:message_id', + MessageHttpController.deleteMessage + ) - app.post("/project/:project_id/thread/:thread_id/resolve", MessageHttpController.resolveThread); - app.post("/project/:project_id/thread/:thread_id/reopen", MessageHttpController.reopenThread); - app.del("/project/:project_id/thread/:thread_id", MessageHttpController.deleteThread); + app.post( + '/project/:project_id/thread/:thread_id/resolve', + MessageHttpController.resolveThread + ) + app.post( + '/project/:project_id/thread/:thread_id/reopen', + MessageHttpController.reopenThread + ) + app.del( + '/project/:project_id/thread/:thread_id', + MessageHttpController.deleteThread + ) - return app.get("/status", (req, res, next) => res.send("chat is alive")); - } -}); - - - + return app.get('/status', (req, res, next) => res.send('chat is alive')) + } +} diff --git a/services/chat/app/js/server.js b/services/chat/app/js/server.js index 7e795833e3..161cf76c33 100644 --- a/services/chat/app/js/server.js +++ b/services/chat/app/js/server.js @@ -8,46 +8,43 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const logger = require('logger-sharelatex'); -logger.initialize("chat-sharelatex"); -const metrics = require("metrics-sharelatex"); -metrics.initialize("chat"); -const Path = require("path"); -const express = require("express"); -const app = express(); -const server = require("http").createServer(app); -const Router = require("./router"); +const logger = require('logger-sharelatex') +logger.initialize('chat-sharelatex') +const metrics = require('metrics-sharelatex') +metrics.initialize('chat') +const Path = require('path') +const express = require('express') +const app = express() +const server = require('http').createServer(app) +const Router = require('./router') -app.use(express.bodyParser()); -app.use(metrics.http.monitor(logger)); +app.use(express.bodyParser()) +app.use(metrics.http.monitor(logger)) -if ((app.get('env')) === 'development') { - console.log("Development Enviroment"); - app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); +if (app.get('env') === 'development') { + console.log('Development Enviroment') + app.use(express.errorHandler({ dumpExceptions: true, showStack: true })) } -if ((app.get('env')) === 'production') { - console.log("Production Enviroment"); - app.use(express.logger()); - app.use(express.errorHandler()); +if (app.get('env') === 'production') { + console.log('Production Enviroment') + app.use(express.logger()) + app.use(express.errorHandler()) } - -const profiler = require("v8-profiler"); -app.get("/profile", function(req, res) { - const time = parseInt(req.query.time || "1000"); - profiler.startProfiling("test"); - return setTimeout(function() { - const profile = profiler.stopProfiling("test"); - return res.json(profile); - } - , time); -}); -Router.route(app); +const profiler = require('v8-profiler') +app.get('/profile', function(req, res) { + const time = parseInt(req.query.time || '1000') + profiler.startProfiling('test') + return setTimeout(function() { + const profile = profiler.stopProfiling('test') + return res.json(profile) + }, time) +}) + +Router.route(app) module.exports = { - server, - app -}; - - + server, + app +}