This repository has been archived on 2026-06-21. You can view files and clone it, but cannot push or open issues or pull requests.
Files
MetaLab/internal/controller/follow_controller.go
Victor_Jay a0df66587b fix: 修复关注/粉丝列表隐私检查假阳性导致本人也无法访问
- follow_repo.go: GetFollowListPublic 改用显式 WHERE uid=? 避免 GORM 主键解析潜在问题
- follow_service.go: GetFollowListPublic 失败时默认公开并记录日志,而非返回错误
- follow_controller.go: 错误兜底时 Accessible 默认 true,避免误锁用户
2026-06-01 20:22:50 +08:00

189 lines
5.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controller
import (
"net/http"
"strconv"
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/model"
"metazone.cc/metalab/internal/service"
"github.com/gin-gonic/gin"
)
// FollowController 关注 API 控制器
type FollowController struct {
followSvc followUseCase
}
// NewFollowController 构造函数
func NewFollowController(followSvc followUseCase) *FollowController {
return &FollowController{followSvc: followSvc}
}
// Toggle 切换关注 POST /api/users/:uid/follow
func (fc *FollowController) Toggle(c *gin.Context) {
uid, _, ok := common.GetGinUser(c)
if !ok {
common.Error(c, http.StatusUnauthorized, "请先登录")
return
}
targetUID, err := strconv.ParseUint(c.Param("uid"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户ID")
return
}
isFollowing, err := fc.followSvc.Toggle(uid, uint(targetUID))
if err != nil {
if err.Error() == "不能关注自己" {
common.Error(c, http.StatusBadRequest, err.Error())
return
}
common.Error(c, http.StatusInternalServerError, "操作失败")
return
}
// 获取最新状态
status, _ := fc.followSvc.GetStatus(uid, uint(targetUID))
common.Ok(c, gin.H{
"is_following": isFollowing,
"status": status,
})
}
// GetStatus 查询关注关系 GET /api/users/:uid/follow-status
func (fc *FollowController) GetStatus(c *gin.Context) {
targetUID, err := strconv.ParseUint(c.Param("uid"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户ID")
return
}
uid, _, _ := common.GetGinUser(c) // 允许未登录(返回全是 false
status, err := fc.followSvc.GetStatus(uid, uint(targetUID))
if err != nil {
common.Error(c, http.StatusInternalServerError, "查询失败")
return
}
common.Ok(c, status)
}
// Followers 粉丝列表 GET /api/users/:uid/followers
func (fc *FollowController) Followers(c *gin.Context) {
targetUID, err := strconv.ParseUint(c.Param("uid"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户ID")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
uid, _, _ := common.GetGinUser(c) // 允许未登录
result, err := fc.followSvc.ListFollowers(uint(targetUID), uid, page, pageSize)
if err != nil {
common.Error(c, http.StatusInternalServerError, "查询失败")
return
}
common.Ok(c, result)
}
// Following 关注列表 GET /api/users/:uid/following
func (fc *FollowController) Following(c *gin.Context) {
targetUID, err := strconv.ParseUint(c.Param("uid"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户ID")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
uid, _, _ := common.GetGinUser(c)
result, err := fc.followSvc.ListFollowing(uint(targetUID), uid, page, pageSize)
if err != nil {
common.Error(c, http.StatusInternalServerError, "查询失败")
return
}
common.Ok(c, result)
}
// FollowPageController 关注/粉丝页面控制器
type FollowPageController struct {
followSvc followUseCase
}
// NewFollowPageController 构造函数
func NewFollowPageController(followSvc followUseCase) *FollowPageController {
return &FollowPageController{followSvc: followSvc}
}
// FollowersPage 粉丝列表页面
func (fpc *FollowPageController) FollowersPage(c *gin.Context) {
targetUID, err := strconv.ParseUint(c.Param("uid"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户ID")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
uid, _, _ := common.GetGinUser(c)
result, err := fpc.followSvc.ListFollowers(uint(targetUID), uid, page, 20)
if err != nil {
result = &service.FollowListResult{Items: []model.UserFollow{}, Total: 0, Accessible: true}
}
c.HTML(http.StatusOK, "follow/followers.html", common.BuildPageData(c, gin.H{
"Title": "粉丝列表",
"ExtraCSS": "/static/css/follow.css",
"Result": result,
"TargetUID": targetUID,
"Page": result.Page,
"TotalPages": result.TotalPages,
"HasPrev": result.Page > 1,
"HasNext": result.Page < result.TotalPages,
"PrevPage": result.Page - 1,
"NextPage": result.Page + 1,
}))
}
// FollowingPage 关注列表页面
func (fpc *FollowPageController) FollowingPage(c *gin.Context) {
targetUID, err := strconv.ParseUint(c.Param("uid"), 10, 64)
if err != nil {
common.Error(c, http.StatusBadRequest, "无效的用户ID")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
uid, _, _ := common.GetGinUser(c)
result, err := fpc.followSvc.ListFollowing(uint(targetUID), uid, page, 20)
if err != nil {
result = &service.FollowListResult{Items: []model.UserFollow{}, Total: 0, Accessible: true}
}
c.HTML(http.StatusOK, "follow/following.html", common.BuildPageData(c, gin.H{
"Title": "关注列表",
"ExtraCSS": "/static/css/follow.css",
"Result": result,
"TargetUID": targetUID,
"Page": result.Page,
"TotalPages": result.TotalPages,
"HasPrev": result.Page > 1,
"HasNext": result.Page < result.TotalPages,
"PrevPage": result.Page - 1,
"NextPage": result.Page + 1,
}))
}