MessageHttpController.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. const logger = require('@overleaf/logger')
  2. const MessageManager = require('./MessageManager')
  3. const MessageFormatter = require('./MessageFormatter')
  4. const ThreadManager = require('../Threads/ThreadManager')
  5. const { ObjectId } = require('../../mongodb')
  6. const DEFAULT_MESSAGE_LIMIT = 50
  7. const MAX_MESSAGE_LENGTH = 10 * 1024 // 10kb, about 1,500 words
  8. function getGlobalMessages(req, res, next) {
  9. _getMessages(ThreadManager.GLOBAL_THREAD, req, res, next)
  10. }
  11. function sendGlobalMessage(req, res, next) {
  12. _sendMessage(ThreadManager.GLOBAL_THREAD, req, res, next)
  13. }
  14. function sendThreadMessage(req, res, next) {
  15. _sendMessage(req.params.threadId, req, res, next)
  16. }
  17. function getAllThreads(req, res, next) {
  18. const { projectId } = req.params
  19. logger.log({ projectId }, 'getting all threads')
  20. ThreadManager.findAllThreadRooms(projectId, function (error, rooms) {
  21. if (error) {
  22. return next(error)
  23. }
  24. const roomIds = rooms.map(r => r._id)
  25. MessageManager.findAllMessagesInRooms(roomIds, function (error, messages) {
  26. if (error) {
  27. return next(error)
  28. }
  29. const threads = MessageFormatter.groupMessagesByThreads(rooms, messages)
  30. res.json(threads)
  31. })
  32. })
  33. }
  34. function resolveThread(req, res, next) {
  35. const { projectId, threadId } = req.params
  36. const { user_id: userId } = req.body
  37. logger.log({ userId, projectId, threadId }, 'marking thread as resolved')
  38. ThreadManager.resolveThread(projectId, threadId, userId, function (error) {
  39. if (error) {
  40. return next(error)
  41. }
  42. res.sendStatus(204)
  43. })
  44. }
  45. function reopenThread(req, res, next) {
  46. const { projectId, threadId } = req.params
  47. logger.log({ projectId, threadId }, 'reopening thread')
  48. ThreadManager.reopenThread(projectId, threadId, function (error) {
  49. if (error) {
  50. return next(error)
  51. }
  52. res.sendStatus(204)
  53. })
  54. }
  55. function deleteThread(req, res, next) {
  56. const { projectId, threadId } = req.params
  57. logger.log({ projectId, threadId }, 'deleting thread')
  58. ThreadManager.deleteThread(projectId, threadId, function (error, roomId) {
  59. if (error) {
  60. return next(error)
  61. }
  62. MessageManager.deleteAllMessagesInRoom(roomId, function (error) {
  63. if (error) {
  64. return next(error)
  65. }
  66. res.sendStatus(204)
  67. })
  68. })
  69. }
  70. function editMessage(req, res, next) {
  71. const { content } = req.body
  72. const { projectId, threadId, messageId } = req.params
  73. logger.log({ projectId, threadId, messageId, content }, 'editing message')
  74. ThreadManager.findOrCreateThread(projectId, threadId, function (error, room) {
  75. if (error) {
  76. return next(error)
  77. }
  78. MessageManager.updateMessage(
  79. room._id,
  80. messageId,
  81. content,
  82. Date.now(),
  83. function (error) {
  84. if (error) {
  85. return next(error)
  86. }
  87. res.sendStatus(204)
  88. }
  89. )
  90. })
  91. }
  92. function deleteMessage(req, res, next) {
  93. const { projectId, threadId, messageId } = req.params
  94. logger.log({ projectId, threadId, messageId }, 'deleting message')
  95. ThreadManager.findOrCreateThread(projectId, threadId, function (error, room) {
  96. if (error) {
  97. return next(error)
  98. }
  99. MessageManager.deleteMessage(
  100. room._id,
  101. messageId,
  102. function (error, message) {
  103. if (error) {
  104. return next(error)
  105. }
  106. res.sendStatus(204)
  107. }
  108. )
  109. })
  110. }
  111. function _sendMessage(clientThreadId, req, res, next) {
  112. const { user_id: userId, content } = req.body
  113. const { projectId } = req.params
  114. if (!ObjectId.isValid(userId)) {
  115. return res.status(400).send('Invalid userId')
  116. }
  117. if (!content) {
  118. return res.status(400).send('No content provided')
  119. }
  120. if (content.length > MAX_MESSAGE_LENGTH) {
  121. return res
  122. .status(400)
  123. .send(`Content too long (> ${MAX_MESSAGE_LENGTH} bytes)`)
  124. }
  125. logger.log(
  126. { clientThreadId, projectId, userId, content },
  127. 'new message received'
  128. )
  129. ThreadManager.findOrCreateThread(
  130. projectId,
  131. clientThreadId,
  132. function (error, thread) {
  133. if (error) {
  134. return next(error)
  135. }
  136. MessageManager.createMessage(
  137. thread._id,
  138. userId,
  139. content,
  140. Date.now(),
  141. function (error, message) {
  142. if (error) {
  143. return next(error)
  144. }
  145. message = MessageFormatter.formatMessageForClientSide(message)
  146. message.room_id = projectId
  147. res.status(201).send(message)
  148. }
  149. )
  150. }
  151. )
  152. }
  153. function _getMessages(clientThreadId, req, res, next) {
  154. let before, limit
  155. const { projectId } = req.params
  156. if (req.query.before) {
  157. before = parseInt(req.query.before, 10)
  158. } else {
  159. before = null
  160. }
  161. if (req.query.limit) {
  162. limit = parseInt(req.query.limit, 10)
  163. } else {
  164. limit = DEFAULT_MESSAGE_LIMIT
  165. }
  166. logger.log(
  167. { limit, before, projectId, clientThreadId },
  168. 'get message request received'
  169. )
  170. ThreadManager.findOrCreateThread(
  171. projectId,
  172. clientThreadId,
  173. function (error, thread) {
  174. if (error) {
  175. return next(error)
  176. }
  177. const threadObjectId = thread._id
  178. logger.log(
  179. { limit, before, projectId, clientThreadId, threadObjectId },
  180. 'found or created thread'
  181. )
  182. MessageManager.getMessages(
  183. threadObjectId,
  184. limit,
  185. before,
  186. function (error, messages) {
  187. if (error) {
  188. return next(error)
  189. }
  190. messages = MessageFormatter.formatMessagesForClientSide(messages)
  191. logger.log({ projectId, messages }, 'got messages')
  192. res.status(200).send(messages)
  193. }
  194. )
  195. }
  196. )
  197. }
  198. module.exports = {
  199. getGlobalMessages,
  200. sendGlobalMessage,
  201. sendThreadMessage,
  202. getAllThreads,
  203. resolveThread,
  204. reopenThread,
  205. deleteThread,
  206. editMessage,
  207. deleteMessage,
  208. }