MessageHttpController.js 6.2 KB

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