## CI 修复 (P0/P1) P0 — 编译阻塞: - interfaces.go: postUseCase ISP 接口移除不用的 Create/Update/Delete P1 — 必须修复: - ST1000: 为 13 个包添加包注释 (common/config/model/service/...) - ST1005: redis_store.go 全部错误消息改为小写开头 - errcheck (19处): defer Close()→闭包忽略, notifier.Create→_=, r.Run→检查error - errorlint (9处): switch-on-error→errors.Is 链, ==→errors.Is - ST1020/ST1022: 导出符号注释以符号名开头 P2 — 安全评审: - gosec (12处): G203/G301/G304/G306 添加 nolint 注释并附理由 P3 — 清理: - unused: 移除 hasUnicode/energyStore/current/energyAdminUseCase - gofumpt + goimports 全量格式化 (35+ 文件)
156 lines
4.3 KiB
Go
156 lines
4.3 KiB
Go
// Package admin 提供管理后台的 HTTP 控制器:用户管理、审核、站点设置等。
|
||
package admin
|
||
|
||
import (
|
||
"errors"
|
||
"net/http"
|
||
"strconv"
|
||
|
||
"metazone.cc/mce/internal/common"
|
||
"metazone.cc/mce/internal/model"
|
||
"metazone.cc/mce/internal/service"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// Note: service import kept for ListUsersParams / ListUsersResult DTOs
|
||
|
||
// AdminController 管理后台控制器
|
||
type AdminController struct {
|
||
adminService adminUseCase
|
||
}
|
||
|
||
// NewAdminController 构造函数
|
||
func NewAdminController(adminService adminUseCase) *AdminController {
|
||
return &AdminController{adminService: adminService}
|
||
}
|
||
|
||
// Dashboard 管理首页(欢迎页)
|
||
func (ac *AdminController) Dashboard(c *gin.Context) {
|
||
totalUsers, err := ac.adminService.CountUsers()
|
||
if err != nil {
|
||
totalUsers = 0
|
||
}
|
||
postStats, err := ac.adminService.GetPostStats()
|
||
if err != nil {
|
||
postStats = &service.PostStats{}
|
||
}
|
||
storeMetrics := ac.adminService.GetStoreMetrics()
|
||
c.HTML(http.StatusOK, "admin/dashboard/index.html", common.BuildAdminPageData(c, gin.H{
|
||
"Title": "管理首页",
|
||
"TotalUsers": totalUsers,
|
||
"PostTotal": postStats.Total,
|
||
"PostApproved": postStats.Approved,
|
||
"PostPending": postStats.Pending,
|
||
"StoreType": storeMetrics.Type,
|
||
"StoreHealthy": storeMetrics.Healthy,
|
||
"StoreDegraded": storeMetrics.Degraded,
|
||
"DegradedNote": storeMetrics.DegradedNote,
|
||
"ActiveSessions": storeMetrics.ActiveCount,
|
||
}))
|
||
}
|
||
|
||
// UsersPage 用户管理页面
|
||
func (ac *AdminController) UsersPage(c *gin.Context) {
|
||
c.HTML(http.StatusOK, "admin/users/index.html", common.BuildAdminPageData(c, gin.H{
|
||
"Title": "用户管理",
|
||
"ExtraCSS": "/admin/static/css/users.css",
|
||
"ExtraJS": "/admin/static/js/users.js",
|
||
"RoleNames": model.RoleDisplayNames,
|
||
"StatusNames": model.StatusDisplayNames,
|
||
}))
|
||
}
|
||
|
||
// ListUsers 用户列表 API(分页 + 搜索 + 筛选)
|
||
func (ac *AdminController) ListUsers(c *gin.Context) {
|
||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||
|
||
params := service.ListUsersParams{
|
||
Keyword: c.Query("keyword"),
|
||
Role: c.Query("role"),
|
||
Status: c.Query("status"),
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
}
|
||
|
||
result, err := ac.adminService.ListUsers(params)
|
||
if err != nil {
|
||
common.Error(c, http.StatusInternalServerError, "查询失败")
|
||
return
|
||
}
|
||
|
||
common.Ok(c, result)
|
||
}
|
||
|
||
// UpdateUserStatus 封禁/解封用户
|
||
func (ac *AdminController) UpdateUserStatus(c *gin.Context) {
|
||
targetUID, err := parseUIDParam(c)
|
||
if err != nil {
|
||
common.Error(c, http.StatusBadRequest, "无效的用户 ID")
|
||
return
|
||
}
|
||
|
||
var req struct {
|
||
Status string `json:"status" binding:"required"`
|
||
}
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
common.Error(c, http.StatusBadRequest, "参数错误")
|
||
return
|
||
}
|
||
|
||
operatorUID := c.GetUint("uid")
|
||
if err := ac.adminService.UpdateUserStatus(operatorUID, targetUID, req.Status); err != nil {
|
||
handleServiceError(c, err)
|
||
return
|
||
}
|
||
|
||
action := "封禁"
|
||
switch req.Status {
|
||
case model.StatusActive:
|
||
action = "解封"
|
||
case model.StatusLocked:
|
||
action = "已锁定"
|
||
}
|
||
common.OkMessage(c, action+"成功")
|
||
}
|
||
|
||
// ResetToken 强制用户下线
|
||
func (ac *AdminController) ResetToken(c *gin.Context) {
|
||
targetUID, err := parseUIDParam(c)
|
||
if err != nil {
|
||
common.Error(c, http.StatusBadRequest, "无效的用户 ID")
|
||
return
|
||
}
|
||
|
||
operatorUID := c.GetUint("uid")
|
||
if err := ac.adminService.ResetUserToken(operatorUID, targetUID); err != nil {
|
||
handleServiceError(c, err)
|
||
return
|
||
}
|
||
|
||
common.OkMessage(c, "已强制下线")
|
||
}
|
||
|
||
// parseUIDParam 从 URL 路径参数解析 uid
|
||
func parseUIDParam(c *gin.Context) (uint, error) {
|
||
uid, err := strconv.ParseUint(c.Param("uid"), 10, 64)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
return uint(uid), nil
|
||
}
|
||
|
||
// handleServiceError 统一处理 service 层返回的错误
|
||
func handleServiceError(c *gin.Context, err error) {
|
||
if errors.Is(err, common.ErrPermissionDenied) {
|
||
common.Error(c, http.StatusForbidden, "权限不足")
|
||
} else if errors.Is(err, common.ErrUserNotFound) {
|
||
common.Error(c, http.StatusNotFound, "用户不存在")
|
||
} else if errors.Is(err, common.ErrEmailExists) {
|
||
common.Error(c, http.StatusConflict, "该邮箱已被其他用户注册,无法解锁")
|
||
} else {
|
||
common.Error(c, http.StatusInternalServerError, "操作失败")
|
||
}
|
||
}
|