MessageHttpController.js 5.2 KB

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