- 修复 Service 层所有 FindByID 错误均返回 ErrUserNotFound 的严重 bug,新增 findPost/findPostWithAuthor 正确区分 gorm.ErrRecordNotFound 和数据库错误 - 新增帖子相关错误哨兵:ErrPostNotFound/ErrPostCannotEdit/ErrPostCannotSubmit/ErrPostCannotApprove/ErrPostCannotReject/ErrPostCannotUnlock - 修复 ShowAPI 缺少权限控制,非 approved 帖子可被任意用户通过 API 获取 - 修复 EditPage 缺少权限检查,非作者可访问编辑页面 - 修复 Update/Delete API 中 uid 断言未做 ok 检查 - Controller 层区分业务错误和内部错误,避免透传 Service 层错误信息给客户端 - 将 postStore 接口从 post_service.go 移至 repository.go,与其他仓储接口保持一致 - 移除 new.html 中孤立的 </template> 标签
168 lines
4.4 KiB
Go
168 lines
4.4 KiB
Go
package admin
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"metazone.cc/metalab/internal/common"
|
|
"metazone.cc/metalab/internal/model"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// AdminPostController 管理后台帖子控制器
|
|
type AdminPostController struct {
|
|
postService adminPostUseCase
|
|
}
|
|
|
|
// NewAdminPostController 构造函数
|
|
func NewAdminPostController(ps adminPostUseCase) *AdminPostController {
|
|
return &AdminPostController{postService: ps}
|
|
}
|
|
|
|
// PostsPage 管理后台帖子列表页
|
|
func (ctrl *AdminPostController) PostsPage(c *gin.Context) {
|
|
keyword := c.Query("keyword")
|
|
status := c.Query("status")
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
posts, total, err := ctrl.postService.ListAdmin(keyword, status, page, pageSize)
|
|
if err != nil {
|
|
c.HTML(http.StatusOK, "admin/posts/index.html", common.BuildAdminPageData(c, gin.H{
|
|
"Title": "内容管理",
|
|
"Error": "加载帖子列表失败",
|
|
}))
|
|
return
|
|
}
|
|
|
|
if posts == nil {
|
|
posts = []model.Post{}
|
|
}
|
|
|
|
p := common.Pagination{Page: page, PageSize: pageSize}
|
|
p.DefaultPagination()
|
|
totalPages := int((total + int64(p.PageSize) - 1) / int64(p.PageSize))
|
|
prevPage := p.Page - 1
|
|
if prevPage < 1 { prevPage = 1 }
|
|
nextPage := p.Page + 1
|
|
if nextPage > totalPages { nextPage = totalPages }
|
|
|
|
c.HTML(http.StatusOK, "admin/posts/index.html", common.BuildAdminPageData(c, gin.H{
|
|
"Title": "内容管理",
|
|
"Posts": posts,
|
|
"Total": total,
|
|
"Page": p.Page,
|
|
"TotalPages": totalPages,
|
|
"PrevPage": prevPage,
|
|
"NextPage": nextPage,
|
|
"Keyword": keyword,
|
|
"Status": status,
|
|
"StatusNames": model.PostStatusDisplayNames,
|
|
"ExtraCSS": "/admin/static/css/posts.css",
|
|
}))
|
|
}
|
|
|
|
// Approve 审核通过
|
|
func (ctrl *AdminPostController) Approve(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
common.Error(c, http.StatusBadRequest, "无效的帖子 ID")
|
|
return
|
|
}
|
|
|
|
if err := ctrl.postService.Approve(uint(id)); err != nil {
|
|
if errors.Is(err, common.ErrPostCannotApprove) || errors.Is(err, common.ErrPostNotFound) {
|
|
common.Error(c, http.StatusBadRequest, err.Error())
|
|
} else {
|
|
common.Error(c, http.StatusInternalServerError, "审核失败")
|
|
}
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "审核通过")
|
|
}
|
|
|
|
// Reject 退回
|
|
func (ctrl *AdminPostController) Reject(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
common.Error(c, http.StatusBadRequest, "无效的帖子 ID")
|
|
return
|
|
}
|
|
|
|
var req model.PostRejectRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
common.Error(c, http.StatusBadRequest, "请填写退回理由")
|
|
return
|
|
}
|
|
|
|
if err := ctrl.postService.Reject(uint(id), req.Reason); err != nil {
|
|
if errors.Is(err, common.ErrPostCannotReject) || errors.Is(err, common.ErrPostNotFound) {
|
|
common.Error(c, http.StatusBadRequest, err.Error())
|
|
} else {
|
|
common.Error(c, http.StatusInternalServerError, "退回失败")
|
|
}
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "已退回")
|
|
}
|
|
|
|
// Lock 锁定
|
|
func (ctrl *AdminPostController) Lock(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
common.Error(c, http.StatusBadRequest, "无效的帖子 ID")
|
|
return
|
|
}
|
|
|
|
if err := ctrl.postService.Lock(uint(id)); err != nil {
|
|
if errors.Is(err, common.ErrPostNotFound) {
|
|
common.Error(c, http.StatusBadRequest, err.Error())
|
|
} else {
|
|
common.Error(c, http.StatusInternalServerError, "锁定失败")
|
|
}
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "已锁定")
|
|
}
|
|
|
|
// Unlock 解锁
|
|
func (ctrl *AdminPostController) Unlock(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
common.Error(c, http.StatusBadRequest, "无效的帖子 ID")
|
|
return
|
|
}
|
|
|
|
if err := ctrl.postService.Unlock(uint(id)); err != nil {
|
|
if errors.Is(err, common.ErrPostCannotUnlock) || errors.Is(err, common.ErrPostNotFound) {
|
|
common.Error(c, http.StatusBadRequest, err.Error())
|
|
} else {
|
|
common.Error(c, http.StatusInternalServerError, "解锁失败")
|
|
}
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "已解锁")
|
|
}
|
|
|
|
// Restore 恢复软删除
|
|
func (ctrl *AdminPostController) Restore(c *gin.Context) {
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
common.Error(c, http.StatusBadRequest, "无效的帖子 ID")
|
|
return
|
|
}
|
|
|
|
if err := ctrl.postService.Restore(uint(id)); err != nil {
|
|
common.Error(c, http.StatusInternalServerError, "恢复失败")
|
|
return
|
|
}
|
|
|
|
common.OkMessage(c, "已恢复")
|
|
}
|