MessageHttpController.js 6.7 KB

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