Просмотр исходного кода

[dsmp] Add endpoint to retrieve a single message from chat (#28242)

* [dsmp] Add endpoint to retrieve a single message from chat

* use user:null in case is deleted

GitOrigin-RevId: f42360c2e05cfe93fa11230ac3cc311bdb044c1d
Domagoj Kriskovic 1 год назад
Родитель
Сommit
ff0e725935

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

@@ -42,6 +42,10 @@ export async function getGlobalMessages(context) {
   return await callMessageHttpController(context, _getGlobalMessages)
 }
 
+export async function getGlobalMessage(context) {
+  return await callMessageHttpController(context, _getGlobalMessage)
+}
+
 export async function sendGlobalMessage(context) {
   return await callMessageHttpController(context, _sendGlobalMessage)
 }
@@ -108,6 +112,31 @@ const _getGlobalMessages = async (req, res) => {
   await _getMessages(ThreadManager.GLOBAL_THREAD, req, res)
 }
 
+const _getGlobalMessage = async (req, res) => {
+  const { projectId, messageId } = req.params
+  logger.debug({ projectId, messageId }, 'getting single global message')
+  try {
+    const room = await ThreadManager.findThread(
+      projectId,
+      ThreadManager.GLOBAL_THREAD
+    )
+
+    const message = await MessageManager.getMessage(room._id, messageId)
+    const formattedMsg = MessageFormatter.formatMessageForClientSide(message)
+
+    res.status(200).setBody(formattedMsg)
+  } catch (error) {
+    if (
+      error instanceof ThreadManager.MissingThreadError ||
+      error instanceof MessageManager.MissingMessageError
+    ) {
+      res.status(404)
+      return
+    }
+    throw error
+  }
+}
+
 async function _sendGlobalMessage(req, res) {
   const { user_id: userId, content } = req.body
   const { projectId } = req.params

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

@@ -1,5 +1,7 @@
 import { db, ObjectId } from '../../mongodb.js'
 
+export class MissingMessageError extends Error {}
+
 export async function createMessage(roomId, userId, content, timestamp) {
   let newMessageOpts = {
     content,
@@ -85,6 +87,18 @@ export async function deleteUserMessage(userId, roomId, messageId) {
   })
 }
 
+export async function getMessage(roomId, messageId) {
+  const query = _ensureIdsAreObjectIds({
+    _id: messageId,
+    room_id: roomId,
+  })
+  const message = await db.messages.findOne(query)
+  if (!message) {
+    throw new MissingMessageError(`Message not found`)
+  }
+  return message
+}
+
 function _ensureIdsAreObjectIds(query) {
   if (query.user_id && !(query.user_id instanceof ObjectId)) {
     query.user_id = new ObjectId(query.user_id)

+ 7 - 2
services/chat/app/js/Features/Threads/ThreadManager.js

@@ -148,9 +148,14 @@ export async function duplicateThread(projectId, threadId) {
 }
 
 export async function findThread(projectId, threadId) {
+  projectId = new ObjectId(projectId.toString())
+  if (threadId !== GLOBAL_THREAD) {
+    threadId = new ObjectId(threadId.toString())
+  }
+
   const room = await db.rooms.findOne({
-    project_id: new ObjectId(projectId),
-    thread_id: new ObjectId(threadId),
+    project_id: projectId,
+    thread_id: threadId === GLOBAL_THREAD ? { $exists: false } : threadId,
   })
   if (!room) {
     throw new MissingThreadError('Thread not found')

+ 26 - 0
services/chat/chat.yaml

@@ -56,6 +56,32 @@ paths:
                   content: string
         description: 'UserID and Content of the message to be posted. '
       description: Send global message  for the project with Project ID provided
+  '/project/{projectId}/messages/{messageId}':
+    parameters:
+      - schema:
+          type: string
+        name: projectId
+        in: path
+        required: true
+      - schema:
+          type: string
+        name: messageId
+        in: path
+        required: true
+    get:
+      summary: Get single global message
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Message'
+        '404':
+          description: Message not found
+      operationId: getGlobalMessage
+      description: Get a single global message by message ID for the project with Project ID provided
   '/project/{projectId}/thread/{threadId}/messages':
     parameters:
       - schema:

+ 8 - 0
services/web/app/src/Features/Chat/ChatApiHandler.js

@@ -39,6 +39,12 @@ async function getGlobalMessages(projectId, limit, before) {
   return await fetchJson(url)
 }
 
+async function getGlobalMessage(projectId, messageId) {
+  return await fetchJson(
+    chatApiUrl(`/project/${projectId}/messages/${messageId}`)
+  )
+}
+
 async function sendComment(projectId, threadId, userId, content) {
   const comment = await fetchJson(
     chatApiUrl(`/project/${projectId}/thread/${threadId}/messages`),
@@ -142,6 +148,7 @@ module.exports = {
   destroyProject: callbackify(destroyProject),
   sendGlobalMessage: callbackify(sendGlobalMessage),
   getGlobalMessages: callbackify(getGlobalMessages),
+  getGlobalMessage: callbackify(getGlobalMessage),
   sendComment: callbackify(sendComment),
   resolveThread: callbackify(resolveThread),
   reopenThread: callbackify(reopenThread),
@@ -158,6 +165,7 @@ module.exports = {
     destroyProject,
     sendGlobalMessage,
     getGlobalMessages,
+    getGlobalMessage,
     sendComment,
     resolveThread,
     reopenThread,

+ 10 - 0
services/web/test/acceptance/src/mocks/MockChatApi.mjs

@@ -42,6 +42,16 @@ class MockChatApi extends AbstractMockApi {
     this.app.post('/project/:project_id/messages', (req, res) => {
       res.json(this.sendMessage(req.params.project_id, 'global', req.body))
     })
+    this.app.get('/project/:project_id/messages/:message_id', (req, res) => {
+      const projectId = req.params.project_id
+      const messageId = req.params.message_id
+      const thread = this.getThread(projectId, 'global')
+      const message = thread.find(msg => msg.id === messageId)
+      if (!message) {
+        return res.status(404).json({ error: 'Message not found' })
+      }
+      res.json(message)
+    })
     this.app.get(
       '/project/:project_id/thread/:thread_id/messages',
       (req, res) => {