package handler import ( "net/http" "strconv" "github.com/freefire/jiang13-bbs/middleware" "github.com/freefire/jiang13-bbs/model" "github.com/freefire/jiang13-bbs/service" "github.com/gin-gonic/gin" ) // UpdateProfileRequest 更新资料请求(头像不在此通道,见 /api/upload/avatar) type UpdateProfileRequest struct { Nickname string `json:"nickname"` Email string `json:"email"` Signature string `json:"signature"` } // UpdateProfile 更新当前登录用户的资料(昵称、邮箱、签名) func (h *Handlers) UpdateProfile(c *gin.Context) { claims := middleware.CurrentUser(c) var req UpdateProfileRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数格式错误"}) return } user, err := h.Auth.UpdateProfile(claims.ID, req.Nickname, req.Email, req.Signature) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 返回更新后的完整资料(含 email/signature,供前端刷新展示) c.JSON(http.StatusOK, gin.H{ "user": gin.H{ "id": user.ID, "username": user.Username, "nickname": user.Nickname, "avatar": user.Avatar, "signature": user.Signature, "email": user.Email, "role": user.Role, }, }) } // UserProfile 获取用户资料:基本信息 + 统计 + 发帖列表(分页) func (h *Handlers) UserProfile(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的用户 ID"}) return } user, err := h.Auth.GetUserByID(uint(id)) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) size, _ := strconv.Atoi(c.DefaultQuery("size", "20")) var viewerID uint var actor *service.Actor if claims := middleware.CurrentUser(c); claims != nil { viewerID = claims.ID if a, err := h.Auth.LoadActor(claims.ID); err == nil { actor = a } } posts, postsTotal, err := h.Post.ListByUser(user.ID, viewerID, actor, page, size) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } // 填充点赞状态(仅登录用户) if viewerID > 0 { ids := make([]uint, 0, len(posts)) for _, p := range posts { ids = append(ids, p.ID) } likedMap := h.Like.BatchHasLiked(ids, viewerID) for i := range posts { posts[i].Liked = likedMap[posts[i].ID] } } postCount, _ := h.Post.CountByUser(user.ID) commentCount, _ := h.Comment.CountByUser(user.ID) // 签到积分概览(失败不阻塞资料返回) pointsTotal, streak := 0, 0 if cs, err := h.Checkin.Status(user.ID); err == nil && cs != nil { pointsTotal = cs.TotalPoints streak = cs.Streak } // 板块管理员公开其授权板块(角色徽章展示"板块管理员 · 板块名") var boardIDs []uint if user.Role == model.RoleBoardAdmin { boardIDs, _ = h.Auth.GetUserBoardIDs(user.ID) } if boardIDs == nil { boardIDs = []uint{} } userPayload := gin.H{ "id": user.ID, "username": user.Username, "nickname": user.Nickname, "avatar": user.Avatar, "signature": user.Signature, "role": user.Role, "board_ids": boardIDs, "created_at": user.CreatedAt, "level": user.Level, "total_points": user.TotalPoints, } // 仅对具备用户管理权限的访客下发封禁态(避免信息公开) if actor != nil && actor.HasPerm(service.PermUsers) { userPayload["banned"] = user.Banned } // 徽章墙(失败不阻塞资料返回) if h.Badge != nil { if badges, err := h.Badge.ForUser(user.ID); err == nil && badges != nil { userPayload["badges"] = badges } } c.JSON(http.StatusOK, gin.H{ "user": userPayload, "stats": gin.H{ "post_count": postCount, "comment_count": commentCount, "points": pointsTotal, "streak": streak, }, "posts": nonNilSlice(posts), "posts_total": postsTotal, "page": page, "size": size, }) } // UserComments 获取用户发表的评论列表(分页,含帖子标题) func (h *Handlers) UserComments(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "无效的用户 ID"}) return } // 校验用户存在 if _, err := h.Auth.GetUserByID(uint(id)); err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "用户不存在"}) return } if allow, err := h.Setting.AllowComments(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "评论暂时不可用"}) return } else if !allow { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) size, _ := strconv.Atoi(c.DefaultQuery("size", "20")) c.JSON(http.StatusOK, gin.H{ "comments": []any{}, "total": 0, "page": page, "size": size, }) return } if requireLogin, err := h.Setting.CommentsRequireLogin(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "评论暂时不可用"}) return } else if requireLogin && middleware.CurrentUser(c) == nil { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) size, _ := strconv.Atoi(c.DefaultQuery("size", "20")) c.JSON(http.StatusOK, gin.H{ "comments": []any{}, "total": 0, "page": page, "size": size, "require_login": true, }) return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) size, _ := strconv.Atoi(c.DefaultQuery("size", "20")) comments, total, err := h.Comment.ListByUser(uint(id), page, size) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "comments": nonNilSlice(comments), "total": total, "page": page, "size": size, }) }