Kaynağa Gözat

Merge pull request #6996 from overleaf/tm-expired-project-chat

Add endpoints to chat for deleting expired project chat data

GitOrigin-RevId: e4eb7c7a79472bb116b2095a76c870e204590288
Thomas 4 yıl önce
ebeveyn
işleme
4cc888ce2f

+ 13 - 0
services/chat/app/js/Features/Messages/MessageHttpController.js

@@ -70,6 +70,18 @@ async function deleteMessage(req, res) {
   res.sendStatus(204)
 }
 
+async function destroyProject(req, res) {
+  const { projectId } = req.params
+  logger.log({ projectId }, 'destroying project')
+  const rooms = await ThreadManager.findAllThreadRoomsAndGlobalThread(projectId)
+  const roomIds = rooms.map(r => r._id)
+  logger.log({ projectId, roomIds }, 'deleting all messages in rooms')
+  await MessageManager.deleteAllMessagesInRooms(roomIds)
+  logger.log({ projectId }, 'deleting all threads in project')
+  await ThreadManager.deleteAllThreadsInProject(projectId)
+  res.sendStatus(204)
+}
+
 async function _sendMessage(clientThreadId, req, res) {
   const { user_id: userId, content } = req.body
   const { projectId } = req.params
@@ -145,4 +157,5 @@ module.exports = {
   deleteThread: expressify(deleteThread),
   editMessage: expressify(editMessage),
   deleteMessage: expressify(deleteMessage),
+  destroyProject: expressify(destroyProject),
 }

+ 7 - 0
services/chat/app/js/Features/Messages/MessageManager.js

@@ -39,6 +39,12 @@ async function deleteAllMessagesInRoom(roomId) {
   })
 }
 
+async function deleteAllMessagesInRooms(roomIds) {
+  await db.messages.deleteMany({
+    room_id: { $in: roomIds },
+  })
+}
+
 async function updateMessage(roomId, messageId, content, timestamp) {
   const query = _ensureIdsAreObjectIds({
     _id: messageId,
@@ -78,6 +84,7 @@ module.exports = MessageManager = {
   getMessages,
   findAllMessagesInRooms,
   deleteAllMessagesInRoom,
+  deleteAllMessagesInRooms,
   updateMessage,
   deleteMessage,
 }

+ 22 - 0
services/chat/app/js/Features/Threads/ThreadManager.js

@@ -54,6 +54,20 @@ async function findAllThreadRooms(projectId) {
     .toArray()
 }
 
+async function findAllThreadRoomsAndGlobalThread(projectId) {
+  return db.rooms
+    .find(
+      {
+        project_id: ObjectId(projectId.toString()),
+      },
+      {
+        thread_id: 1,
+        resolved: 1,
+      }
+    )
+    .toArray()
+}
+
 async function resolveThread(projectId, threadId, userId) {
   await db.rooms.updateOne(
     {
@@ -93,13 +107,21 @@ async function deleteThread(projectId, threadId) {
   return room._id
 }
 
+async function deleteAllThreadsInProject(projectId) {
+  await db.rooms.deleteMany({
+    project_id: ObjectId(projectId.toString()),
+  })
+}
+
 module.exports = ThreadManager = {
   GLOBAL_THREAD,
   findOrCreateThread,
   findAllThreadRooms,
+  findAllThreadRoomsAndGlobalThread,
   resolveThread,
   reopenThread,
   deleteThread,
+  deleteAllThreadsInProject,
 }
 ;[
   'findOrCreateThread',

+ 2 - 0
services/chat/app/js/router.js

@@ -66,6 +66,8 @@ module.exports = {
       MessageHttpController.deleteThread
     )
 
+    app.delete('/project/:projectId', MessageHttpController.destroyProject)
+
     app.get('/status', (req, res, next) => res.send('chat is alive'))
   },
 }

+ 67 - 0
services/chat/test/acceptance/js/DestroyingAProjectTests.js

@@ -0,0 +1,67 @@
+const { ObjectId } = require('../../../app/js/mongodb')
+const { expect } = require('chai')
+
+const ChatClient = require('./helpers/ChatClient')
+const ChatApp = require('./helpers/ChatApp')
+
+const db = ChatApp.db
+
+async function getMessage(messageId) {
+  return await db.messages.findOne({
+    _id: ObjectId(messageId),
+  })
+}
+
+describe('Destroying a project', async function () {
+  const projectId = ObjectId().toString()
+  const userId = ObjectId().toString()
+  before(async function () {
+    await ChatApp.ensureRunning()
+  })
+
+  describe('with a project that has threads and messages', async function () {
+    const threadId = ObjectId().toString()
+    before(async function () {
+      const { response } = await ChatClient.sendMessage(
+        projectId,
+        threadId,
+        userId,
+        'destroyed thread message'
+      )
+      expect(response.statusCode).to.equal(201)
+      this.threadMessageId = response.body.id
+      const { response: response2 } = await ChatClient.sendGlobalMessage(
+        projectId,
+        userId,
+        'destroyed global message'
+      )
+      expect(response2.statusCode).to.equal(201)
+      this.globalThreadMessageId = response2.body.id
+
+      const threadRooms = await db.rooms
+        .find({ project_id: ObjectId(projectId) })
+        .toArray()
+      expect(threadRooms.length).to.equal(2)
+      const threadMessage = await getMessage(this.threadMessageId)
+      expect(threadMessage).to.exist
+      const globalThreadMessage = await getMessage(this.globalThreadMessageId)
+      expect(globalThreadMessage).to.exist
+
+      const { response: responseDestroy } = await ChatClient.destroyProject(
+        projectId
+      )
+      expect(responseDestroy.statusCode).to.equal(204)
+    })
+
+    it('should remove the messages and threads from the database', async function () {
+      const threadRooms = await db.rooms
+        .find({ project_id: ObjectId(projectId) })
+        .toArray()
+      expect(threadRooms.length).to.equal(0)
+      const threadMessage = await getMessage(this.threadMessageId)
+      expect(threadMessage).to.be.null
+      const globalThreadMessage = await getMessage(this.globalThreadMessageId)
+      expect(globalThreadMessage).to.be.null
+    })
+  })
+})

+ 2 - 1
services/chat/test/acceptance/js/helpers/ChatApp.js

@@ -1,4 +1,4 @@
-const { waitForDb } = require('../../../../app/js/mongodb')
+const { db, waitForDb } = require('../../../../app/js/mongodb')
 const app = require('../../../../app')
 
 let serverPromise = null
@@ -23,5 +23,6 @@ async function ensureRunning() {
 }
 
 module.exports = {
+  db,
   ensureRunning,
 }

+ 8 - 0
services/chat/test/acceptance/js/helpers/ChatClient.js

@@ -93,6 +93,13 @@ async function deleteMessage(projectId, threadId, messageId) {
   })
 }
 
+async function destroyProject(projectId) {
+  return asyncRequest({
+    method: 'delete',
+    url: `/project/${projectId}`,
+  })
+}
+
 module.exports = {
   sendGlobalMessage,
   getGlobalMessages,
@@ -103,4 +110,5 @@ module.exports = {
   deleteThread,
   editMessage,
   deleteMessage,
+  destroyProject,
 }