/** * package api * 作用:用户管理相关API处理器 */ package api import ( "encoding/json" "fmt" "math/rand" "strconv" "time" "xk-websocket-v2/internal/model" "xk-websocket-v2/internal/service" "xk-websocket-v2/internal/utils" "github.com/gin-gonic/gin" ) /** * GetMyInfoHandler * 功能:获取当前用户信息 * 路径:GET /api/user/my-info * 需要:JWT认证 */ func GetMyInfoHandler(c *gin.Context) { // 从Context获取用户ID(由JWT中间件注入) userID, exists := c.Get("user_id") if !exists { utils.Unauthorized(c, "未认证") return } user, err := service.UserSvc.GetUserByID(userID.(string)) if err != nil { utils.NotFound(c, "用户不存在") return } 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 * 功能:获取用户列表 * 路径:GET /api/user/list */ func GetUserListHandler(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 20 } users, total, err := service.UserSvc.GetUserList(page, pageSize) if err != nil { utils.InternalError(c, "查询失败") return } // 确保返回空数组而不是null if users == nil { users = []model.User{} } utils.SuccessWithData(c, gin.H{ "data": users, "total": total, "page": page, "size": pageSize, }, "获取成功") } /** * CreateUserHandler * 功能:创建用户(管理员) * 路径:POST /api/user/create */ func CreateUserHandler(c *gin.Context) { // 该接口本质是管理员功能,但当前系统没有角色体系,任何登录用户都能创建任意账号(普通注册应走 /api/register)。 // 在缺少管理员鉴权的前提下,直接禁用以关闭越权创建用户的风险;待引入角色系统后再按 admin 放开。 utils.Forbidden(c, "无权限:创建用户需要管理员权限") } /** * UpdateUserHandler * 功能:更新用户信息 * 路径:POST /api/user/update */ func UpdateUserHandler(c *gin.Context) { // 强制只能修改当前登录用户自己的资料:忽略请求体中的 id,防止越权修改他人 uid, ok := c.Get("user_id") if !ok { utils.Unauthorized(c, "未认证") return } currentUserID := uid.(string) var req struct { ID string `json:"id"` Updates map[string]interface{} `json:"updates" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误: "+err.Error()) return } // 字段白名单:仅允许更新以下资料字段。 // 过滤掉 password/id/email 等敏感或身份字段,防止通过此接口改密码或伪造身份。 // phone 保留:PC 端"修改手机号"功能走本接口更新自己的手机号(越权风险已由 // currentUserID 强制"只能改自己"消除;users.phone 有唯一索引,占用冲突由数据库兜底报错) // moment_cover:朋友圈顶部封面图,用户可自行更换 allowed := map[string]bool{"name": true, "avatar": true, "desc": true, "region": true, "phone": true, "moment_cover": true} updates := make(map[string]interface{}) for k, v := range req.Updates { if allowed[k] { updates[k] = v } } if len(updates) == 0 { utils.BadRequest(c, "没有可更新的字段") return } if err := service.UserSvc.UpdateUser(currentUserID, updates); err != nil { utils.BadRequest(c, "更新失败: "+err.Error()) return } // 如果更新了头像或名称,通知好友 if service.ContactSvc != nil && service.ChatSvc != nil { if _, hasName := updates["name"]; hasName { go notifyFriendsOfProfileUpdate(currentUserID, updates) } else if _, hasAvatar := updates["avatar"]; hasAvatar { go notifyFriendsOfProfileUpdate(currentUserID, updates) } } utils.Success(c, "更新成功") } /** * notifyFriendsOfProfileUpdate * 功能:通知好友用户信息更新 */ func notifyFriendsOfProfileUpdate(userID string, updates map[string]interface{}) { if service.ContactSvc == nil || service.ChatSvc == nil || service.UserSvc == nil { return } // 获取更新后的用户信息 user, err := service.UserSvc.GetUserByID(userID) if err != nil { return } // 获取好友列表 friendIDs, err := service.ContactSvc.GetFriendUserIDs(userID) if err != nil || len(friendIDs) == 0 { return } // 构建通知消息 notifExtra := map[string]interface{}{ "type": "profile_update", "user_id": userID, "name": user.Name, "avatar": user.Avatar, "updates": updates, } notifExtraJSON, _ := json.Marshal(notifExtra) // 发送给所有好友 for _, friendID := range friendIDs { notifMsg := model.ChatMessage{ RoomID: userID, SenderUserID: userID, ReceiverUserID: friendID, MessageType: model.MessageTypeFriendNotif, Content: user.Name + " 更新了个人资料", Extra: string(notifExtraJSON), } // 不持久化此类通知,直接推送 pushMsg := model.WsPayload{ RequestType: "receive_message", Data: notifMsg, } msgBytes, _ := json.Marshal(pushMsg) service.ChatSvc.DispatchMessage(friendID, msgBytes) } } /** * DeleteUserHandler * 功能:删除用户 * 路径:POST /api/user/delete */ func DeleteUserHandler(c *gin.Context) { // 仅允许注销当前登录用户自己,禁止删除他人(原实现可传任意 id 越权删除) uid, ok := c.Get("user_id") if !ok { utils.Unauthorized(c, "未认证") return } currentUserID := uid.(string) var req struct { ID string `json:"id"` } if err := c.ShouldBindJSON(&req); err != nil { utils.BadRequest(c, "参数错误") return } if req.ID != "" && req.ID != currentUserID { utils.Forbidden(c, "无权删除其他用户") return } if err := service.UserSvc.DeleteUser(currentUserID); err != nil { utils.BadRequest(c, "删除失败: "+err.Error()) return } utils.Success(c, "删除成功") } // 辅助函数:生成用户ID func generateUserID() string { // 使用时间戳+随机数生成用户ID timestamp := time.Now().UnixNano() random := rand.Intn(1000000) return fmt.Sprintf("user_%d_%d", timestamp, random) }