[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
This commit is contained in:
Domagoj Kriskovic
2025-09-04 15:24:26 +02:00
committed by Copybot
parent 0eda16cb15
commit 423144ea61
6 changed files with 94 additions and 2 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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')

View File

@@ -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:

View File

@@ -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,

View File

@@ -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) => {