- follow_repo.go: GetFollowListPublic 改用显式 WHERE uid=? 避免 GORM 主键解析潜在问题 - follow_service.go: GetFollowListPublic 失败时默认公开并记录日志,而非返回错误 - follow_controller.go: 错误兜底时 Accessible 默认 true,避免误锁用户
189 lines
5.2 KiB
Go
189 lines
5.2 KiB
Go
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,
|
||
}))
|
||
}
|