feat(chat): add endpoint to get quoted message by ID
All checks were successful
Build Backend / build (push) Successful in 2m21s
Build Backend / build-docker (push) Successful in 58s

Add GET /api/v1/messages/:id endpoint to retrieve quoted/replied messages
for preview fill and navigation purposes. The endpoint includes authorization
checks ensuring only conversation participants can access the message.

Additionally improve file upload handling for native clients (expo-file-system)
by accepting explicit displayName from frontend, with sanitization to prevent
path traversal and 255-character length limit. File extension detection now
prioritizes the real display name over the multipart header filename.
This commit is contained in:
lafay
2026-07-02 23:22:24 +08:00
parent d8e56e60dc
commit d240485d0e
5 changed files with 109 additions and 7 deletions

View File

@@ -358,6 +358,37 @@ func (h *MessageHandler) GetMessages(c *gin.Context) {
response.Paginated(c, result, total, page, pageSize)
}
// GetReplyMessage 按消息 ID 获取被引用消息(用于引用预览回填/跳转)
// GET /api/v1/messages/:id
func (h *MessageHandler) GetReplyMessage(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
response.Unauthorized(c, "")
return
}
messageID := c.Param("id")
if messageID == "" {
response.BadRequest(c, "message id is required")
return
}
message, err := h.chatService.GetReplyMessage(c.Request.Context(), messageID, userID)
if err != nil {
response.BadRequest(c, err.Error())
return
}
// 转换为响应格式(标记已过期文件 / 撤回占位等,保持与列表接口一致)
result := h.convertMessagesWithExpiry(c.Request.Context(), []*model.Message{message})
if len(result) == 0 {
response.InternalServerError(c, "failed to convert message")
return
}
response.Success(c, result[0])
}
// SendMessage 发送消息
// POST /api/conversations/:id/messages
func (h *MessageHandler) SendMessage(c *gin.Context) {

View File

@@ -109,8 +109,12 @@ func (h *UploadHandler) UploadFile(c *gin.Context) {
}
folder := c.DefaultPostForm("folder", "chat")
// 前端(尤其原生端 expo-file-system无法自定义 multipart filename
// 文件常被复制到缓存目录并以 UUID 命名,导致 header Filename 丢失真实名。
// 因此前端额外把真实文件名通过 "name" 字段回传,作为权威展示名。
displayName := c.PostForm("name")
result, err := h.uploadService.UploadFile(c.Request.Context(), file, folder, userID)
result, err := h.uploadService.UploadFile(c.Request.Context(), file, folder, userID, displayName)
if err != nil {
// 参数类错误(大小/类型)返回 400其余返回 500
if file.Size > 0 && file.Size <= 100<<20 {