修复了一些问题
This commit is contained in:
@@ -25,7 +25,7 @@ func LoginHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 获取客户端IP
|
||||
ip := getClientIP(c)
|
||||
ip := utils.GetClientIP(c)
|
||||
|
||||
// 调用认证服务登录
|
||||
user, err := service.AuthSvc.Login(req.Account, req.Password)
|
||||
@@ -57,24 +57,6 @@ func LoginHandler(c *gin.Context) {
|
||||
}, "登录成功")
|
||||
}
|
||||
|
||||
// getClientIP 获取客户端IP
|
||||
func getClientIP(c *gin.Context) string {
|
||||
// 优先从X-Forwarded-For获取
|
||||
ip := c.GetHeader("X-Forwarded-For")
|
||||
if ip != "" {
|
||||
return ip
|
||||
}
|
||||
|
||||
// 从X-Real-IP获取
|
||||
ip = c.GetHeader("X-Real-IP")
|
||||
if ip != "" {
|
||||
return ip
|
||||
}
|
||||
|
||||
// 从RemoteAddr获取
|
||||
return c.ClientIP()
|
||||
}
|
||||
|
||||
/**
|
||||
* RegisterHandler
|
||||
* 功能:用户注册
|
||||
@@ -222,4 +204,3 @@ func SendSmsCodeHandler(c *gin.Context) {
|
||||
"code": code, // 仅开发环境,生产环境应移除
|
||||
}, "验证码已发送")
|
||||
}
|
||||
|
||||
|
||||
@@ -310,6 +310,7 @@ func UpdateContactHandler(c *gin.Context) {
|
||||
GroupID uint `json:"group_id"`
|
||||
IsTop *bool `json:"is_top"`
|
||||
IsMuted *bool `json:"is_muted"`
|
||||
IsBlocked *bool `json:"is_blocked"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -330,6 +331,9 @@ func UpdateContactHandler(c *gin.Context) {
|
||||
if req.IsMuted != nil {
|
||||
updates["is_muted"] = *req.IsMuted
|
||||
}
|
||||
if req.IsBlocked != nil {
|
||||
updates["is_blocked"] = *req.IsBlocked
|
||||
}
|
||||
|
||||
if err := service.ContactSvc.UpdateContact(userID.(string), contactID, updates); err != nil {
|
||||
utils.BadRequest(c, "更新失败: "+err.Error())
|
||||
|
||||
@@ -56,14 +56,19 @@ func SendHandler(c *gin.Context) {
|
||||
// 4. 构造临时的发送者客户端对象
|
||||
// 这个对象将传递给 Service 层,用于识别消息来源
|
||||
mockClient := &manager.Client{
|
||||
UserID: senderID,
|
||||
ID: clientID,
|
||||
UserID: senderID,
|
||||
ID: clientID,
|
||||
RemoteIP: utils.GetClientIP(c),
|
||||
}
|
||||
|
||||
// 5. 调用核心业务逻辑处理消息
|
||||
service.ChatSvc.HandleUserMessage(mockClient, &req)
|
||||
// 5. 调用核心业务逻辑处理消息,返回持久化后的消息体供前端对齐 ID
|
||||
savedMsg := service.ChatSvc.HandleUserMessage(mockClient, &req)
|
||||
|
||||
// 6. 返回成功响应
|
||||
// 6. 返回成功响应(含服务端消息 ID,避免前端重复展示)
|
||||
if savedMsg != nil {
|
||||
utils.SuccessWithData(c, savedMsg, "消息已发送")
|
||||
return
|
||||
}
|
||||
utils.Success(c, "消息已发送")
|
||||
}
|
||||
|
||||
@@ -169,6 +174,54 @@ func HistoryHandler(c *gin.Context) {
|
||||
}, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* RecallMessageHandler
|
||||
* 功能:撤回消息(2 分钟内,仅发送者可撤回)
|
||||
* 路径:POST /api/messages/recall
|
||||
*/
|
||||
func RecallMessageHandler(c *gin.Context) {
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
utils.Unauthorized(c, "未认证")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
MessageID uint `json:"message_id" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
var msg model.ChatMessage
|
||||
if err := service.ChatSvc.DB.First(&msg, req.MessageID).Error; err != nil {
|
||||
utils.NotFound(c, "消息不存在")
|
||||
return
|
||||
}
|
||||
|
||||
if msg.SenderUserID != userID.(string) {
|
||||
utils.Forbidden(c, "无权撤回该消息")
|
||||
return
|
||||
}
|
||||
|
||||
if time.Since(msg.CreatedAt) > 2*time.Minute {
|
||||
utils.BadRequest(c, "超过2分钟,无法撤回")
|
||||
return
|
||||
}
|
||||
|
||||
msg.MessageType = model.MessageTypeSystem
|
||||
msg.Content = "撤回了一条消息"
|
||||
if err := service.ChatSvc.DB.Save(&msg).Error; err != nil {
|
||||
utils.InternalError(c, "撤回失败")
|
||||
return
|
||||
}
|
||||
|
||||
service.ChatSvc.BroadcastChatMessage(msg)
|
||||
|
||||
utils.SuccessWithData(c, msg, "撤回成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* SyncMessagesHandler
|
||||
* 功能:全量同步消息 (V1 兼容)。
|
||||
@@ -178,7 +231,6 @@ func SyncMessagesHandler(c *gin.Context) {
|
||||
HistoryHandler(c)
|
||||
}
|
||||
|
||||
|
||||
// ==========================================
|
||||
// 系统与 WebRTC 接口
|
||||
// ==========================================
|
||||
|
||||
@@ -934,3 +934,93 @@ func GetMemberMuteStatusHandler(c *gin.Context) {
|
||||
"muted_until": mutedUntil,
|
||||
}, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetGroupSettingsHandler
|
||||
* 功能:获取群设置(名称、头像、公告、邀请权限等)
|
||||
* 路径:GET /api/groups/:room_id/settings
|
||||
*/
|
||||
func GetGroupSettingsHandler(c *gin.Context) {
|
||||
roomID := c.Param("room_id")
|
||||
room, err := service.RoomSvc.GetRoom(roomID)
|
||||
if err != nil {
|
||||
utils.NotFound(c, "群聊不存在")
|
||||
return
|
||||
}
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"name": room.RoomName,
|
||||
"avatar": room.RoomAvatar,
|
||||
"description": room.Announcement,
|
||||
"invite_permission": 0,
|
||||
"created_at": room.CreatedAt,
|
||||
"updated_at": room.UpdatedAt,
|
||||
}, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateGroupSettingsHandler
|
||||
* 功能:更新群设置
|
||||
* 路径:POST /api/groups/:room_id/settings
|
||||
*/
|
||||
func UpdateGroupSettingsHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
roomID := c.Param("room_id")
|
||||
|
||||
ok, err := service.RoomSvc.IsGroupAdminOrOwner(roomID, userID.(string))
|
||||
if err != nil || !ok {
|
||||
utils.Forbidden(c, "无权限修改群设置")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Avatar string `json:"avatar"`
|
||||
Description string `json:"description"`
|
||||
InvitePermission *int `json:"invite_permission"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{}
|
||||
if req.Name != "" {
|
||||
updates["room_name"] = req.Name
|
||||
}
|
||||
if req.Avatar != "" {
|
||||
updates["room_avatar"] = req.Avatar
|
||||
}
|
||||
if req.Description != "" {
|
||||
updates["announcement"] = req.Description
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
utils.BadRequest(c, "没有可更新的字段")
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.RoomSvc.DB.Model(&model.ChatRoom{}).Where("room_id = ?", roomID).Updates(updates).Error; err != nil {
|
||||
utils.InternalError(c, "更新失败")
|
||||
return
|
||||
}
|
||||
GetGroupSettingsHandler(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* GetCallHistoryHandler
|
||||
* 功能:获取当前用户的通话记录(基于 call_id 消息)
|
||||
* 路径:GET /api/calls/history
|
||||
*/
|
||||
func GetCallHistoryHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
var messages []model.ChatMessage
|
||||
err := service.ChatSvc.DB.
|
||||
Where("(sender_user_id = ? OR receiver_user_id = ?) AND call_id <> '' AND call_id IS NOT NULL", userID, userID).
|
||||
Order("created_at DESC").
|
||||
Limit(50).
|
||||
Find(&messages).Error
|
||||
if err != nil {
|
||||
utils.InternalError(c, "查询失败")
|
||||
return
|
||||
}
|
||||
utils.SuccessWithData(c, messages, "获取成功")
|
||||
}
|
||||
|
||||
126
internal/api/settings_handler.go
Normal file
126
internal/api/settings_handler.go
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* package api
|
||||
* 作用:用户设置与消息已读回执 HTTP 接口
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"xk-websocket-v2/internal/model"
|
||||
"xk-websocket-v2/internal/service"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
/**
|
||||
* GetUserSettingsHandler
|
||||
* 功能:获取当前用户的全部设置
|
||||
*/
|
||||
func GetUserSettingsHandler(c *gin.Context) {
|
||||
userID, ok := c.Get("user_id")
|
||||
if !ok {
|
||||
utils.Unauthorized(c, "未认证")
|
||||
return
|
||||
}
|
||||
|
||||
var rows []model.UserSetting
|
||||
if err := service.ChatSvc.DB.Where("user_id = ?", userID.(string)).Find(&rows).Error; err != nil {
|
||||
utils.InternalError(c, "查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
result := make(map[string]string, len(rows))
|
||||
for _, row := range rows {
|
||||
result[row.SettingKey] = row.SettingValue
|
||||
}
|
||||
utils.SuccessWithData(c, result, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateUserSettingsHandler
|
||||
* 功能:批量更新用户设置
|
||||
*/
|
||||
func UpdateUserSettingsHandler(c *gin.Context) {
|
||||
userID, ok := c.Get("user_id")
|
||||
if !ok {
|
||||
utils.Unauthorized(c, "未认证")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Settings map[string]string `json:"settings" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
uid := userID.(string)
|
||||
now := time.Now()
|
||||
for key, val := range req.Settings {
|
||||
setting := model.UserSetting{
|
||||
UserID: uid,
|
||||
SettingKey: key,
|
||||
SettingValue: val,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
service.ChatSvc.DB.Save(&setting)
|
||||
}
|
||||
|
||||
GetUserSettingsHandler(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* MarkMessagesReadHandler
|
||||
* 功能:批量标记消息已读
|
||||
*/
|
||||
func MarkMessagesReadHandler(c *gin.Context) {
|
||||
userID, ok := c.Get("user_id")
|
||||
if !ok {
|
||||
utils.Unauthorized(c, "未认证")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
MessageIDs []uint `json:"message_ids" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
uid := userID.(string)
|
||||
now := time.Now()
|
||||
readIDs := make([]uint, 0, len(req.MessageIDs))
|
||||
for _, mid := range req.MessageIDs {
|
||||
receipt := model.MessageReadReceipt{
|
||||
MessageID: mid,
|
||||
UserID: uid,
|
||||
ReadAt: now,
|
||||
}
|
||||
service.ChatSvc.DB.Where("message_id = ? AND user_id = ?", mid, uid).
|
||||
Assign(receipt).FirstOrCreate(&receipt)
|
||||
readIDs = append(readIDs, mid)
|
||||
|
||||
// 通知消息发送者(已读回执)
|
||||
var msg model.ChatMessage
|
||||
if err := service.ChatSvc.DB.First(&msg, mid).Error; err == nil && msg.SenderUserID != "" && msg.SenderUserID != uid {
|
||||
payload := model.WsPayload{
|
||||
RequestType: "messages_read",
|
||||
Data: map[string]interface{}{
|
||||
"message_ids": []uint{mid},
|
||||
"reader_id": uid,
|
||||
"room_id": msg.RoomID,
|
||||
},
|
||||
}
|
||||
if bytes, err := json.Marshal(payload); err == nil {
|
||||
service.ChatSvc.DispatchMessage(msg.SenderUserID, bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, gin.H{"message_ids": readIDs}, "已标记已读")
|
||||
}
|
||||
@@ -40,6 +40,27 @@ func GetMyInfoHandler(c *gin.Context) {
|
||||
utils.SuccessWithData(c, user, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUserByIDHandler
|
||||
* 功能:根据用户 ID 获取公开资料
|
||||
* 路径:GET /api/user/:id
|
||||
*/
|
||||
func GetUserByIDHandler(c *gin.Context) {
|
||||
targetID := c.Param("id")
|
||||
if targetID == "" {
|
||||
utils.BadRequest(c, "用户ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := service.UserSvc.GetUserByID(targetID)
|
||||
if err != nil {
|
||||
utils.NotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
user.Password = ""
|
||||
utils.SuccessWithData(c, user, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUserListHandler
|
||||
* 功能:获取用户列表
|
||||
|
||||
Reference in New Issue
Block a user