MessageHttpController.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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 { expressify } = require('../../util/promises')
  7. const DEFAULT_MESSAGE_LIMIT = 50
  8. const MAX_MESSAGE_LENGTH = 10 * 1024 // 10kb, about 1,500 words
  9. async function getGlobalMessages(req, res) {
  10. await _getMessages(ThreadManager.GLOBAL_THREAD, req, res)
  11. }
  12. async function sendGlobalMessage(req, res) {
  13. await _sendMessage(ThreadManager.GLOBAL_THREAD, req, res)
  14. }
  15. async function sendThreadMessage(req, res) {
  16. await _sendMessage(req.params.threadId, req, res)
  17. }
  18. async function getAllThreads(req, res) {
  19. const { projectId } = req.params
  20. logger.log({ projectId }, 'getting all threads')
  21. const rooms = await ThreadManager.findAllThreadRooms(projectId)
  22. const roomIds = rooms.map(r => r._id)
  23. const messages = await MessageManager.findAllMessagesInRooms(roomIds)
  24. const threads = MessageFormatter.groupMessagesByThreads(rooms, messages)
  25. res.json(threads)
  26. }
  27. async function resolveThread(req, res) {
  28. const { projectId, threadId } = req.params
  29. const { user_id: userId } = req.body
  30. logger.log({ userId, projectId, threadId }, 'marking thread as resolved')
  31. await ThreadManager.resolveThread(projectId, threadId, userId)
  32. res.sendStatus(204)
  33. }
  34. async function reopenThread(req, res) {
  35. const { projectId, threadId } = req.params
  36. logger.log({ projectId, threadId }, 'reopening thread')
  37. await ThreadManager.reopenThread(projectId, threadId)
  38. res.sendStatus(204)
  39. }
  40. async function deleteThread(req, res) {
  41. const { projectId, threadId } = req.params
  42. logger.log({ projectId, threadId }, 'deleting thread')
  43. const roomId = await ThreadManager.deleteThread(projectId, threadId)
  44. await MessageManager.deleteAllMessagesInRoom(roomId)
  45. res.sendStatus(204)
  46. }
  47. async function editMessage(req, res) {
  48. const { content, userId } = req.body
  49. const { projectId, threadId, messageId } = req.params
  50. logger.log({ projectId, threadId, messageId, content }, 'editing message')
  51. const room = await ThreadManager.findOrCreateThread(projectId, threadId)
  52. await MessageManager.updateMessage(
  53. room._id,
  54. messageId,
  55. userId,
  56. content,
  57. Date.now()
  58. )
  59. res.sendStatus(204)
  60. }
  61. async function deleteMessage(req, res) {
  62. const { projectId, threadId, messageId } = req.params
  63. logger.log({ projectId, threadId, messageId }, 'deleting message')
  64. const room = await ThreadManager.findOrCreateThread(projectId, threadId)
  65. await MessageManager.deleteMessage(room._id, messageId)
  66. res.sendStatus(204)
  67. }
  68. async function destroyProject(req, res) {
  69. const { projectId } = req.params
  70. logger.log({ projectId }, 'destroying project')
  71. const rooms = await ThreadManager.findAllThreadRoomsAndGlobalThread(projectId)
  72. const roomIds = rooms.map(r => r._id)
  73. logger.log({ projectId, roomIds }, 'deleting all messages in rooms')
  74. await MessageManager.deleteAllMessagesInRooms(roomIds)
  75. logger.log({ projectId }, 'deleting all threads in project')
  76. await ThreadManager.deleteAllThreadsInProject(projectId)
  77. res.sendStatus(204)
  78. }
  79. async function _sendMessage(clientThreadId, req, res) {
  80. const { user_id: userId, content } = req.body
  81. const { projectId } = req.params
  82. if (!ObjectId.isValid(userId)) {
  83. return res.status(400).send('Invalid userId')
  84. }
  85. if (!content) {
  86. return res.status(400).send('No content provided')
  87. }
  88. if (content.length > MAX_MESSAGE_LENGTH) {
  89. return res
  90. .status(400)
  91. .send(`Content too long (> ${MAX_MESSAGE_LENGTH} bytes)`)
  92. }
  93. logger.log(
  94. { clientThreadId, projectId, userId, content },
  95. 'new message received'
  96. )
  97. const thread = await ThreadManager.findOrCreateThread(
  98. projectId,
  99. clientThreadId
  100. )
  101. let message = await MessageManager.createMessage(
  102. thread._id,
  103. userId,
  104. content,
  105. Date.now()
  106. )
  107. message = MessageFormatter.formatMessageForClientSide(message)
  108. message.room_id = projectId
  109. res.status(201).send(message)
  110. }
  111. async function _getMessages(clientThreadId, req, res) {
  112. let before, limit
  113. const { projectId } = req.params
  114. if (req.query.before) {
  115. before = parseInt(req.query.before, 10)
  116. } else {
  117. before = null
  118. }
  119. if (req.query.limit) {
  120. limit = parseInt(req.query.limit, 10)
  121. } else {
  122. limit = DEFAULT_MESSAGE_LIMIT
  123. }
  124. logger.log(
  125. { limit, before, projectId, clientThreadId },
  126. 'get message request received'
  127. )
  128. const thread = await ThreadManager.findOrCreateThread(
  129. projectId,
  130. clientThreadId
  131. )
  132. const threadObjectId = thread._id
  133. logger.log(
  134. { limit, before, projectId, clientThreadId, threadObjectId },
  135. 'found or created thread'
  136. )
  137. let messages = await MessageManager.getMessages(threadObjectId, limit, before)
  138. messages = MessageFormatter.formatMessagesForClientSide(messages)
  139. logger.log({ projectId, messages }, 'got messages')
  140. res.status(200).send(messages)
  141. }
  142. module.exports = {
  143. getGlobalMessages: expressify(getGlobalMessages),
  144. sendGlobalMessage: expressify(sendGlobalMessage),
  145. sendThreadMessage: expressify(sendThreadMessage),
  146. getAllThreads: expressify(getAllThreads),
  147. resolveThread: expressify(resolveThread),
  148. reopenThread: expressify(reopenThread),
  149. deleteThread: expressify(deleteThread),
  150. editMessage: expressify(editMessage),
  151. deleteMessage: expressify(deleteMessage),
  152. destroyProject: expressify(destroyProject),
  153. }