Files
backend/internal/handler/report_handler.go

496 lines
14 KiB
Go
Raw Normal View History

2026-01-21 21:34:11 +08:00
package handler
import (
"carrotskin/internal/container"
"carrotskin/internal/model"
"strconv"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// ReportHandler 举报处理器
type ReportHandler struct {
container *container.Container
logger *zap.Logger
}
// NewReportHandler 创建ReportHandler实例
func NewReportHandler(c *container.Container) *ReportHandler {
return &ReportHandler{
container: c,
logger: c.Logger,
}
}
// CreateReportRequest 创建举报请求
type CreateReportRequest struct {
TargetType string `json:"target_type" binding:"required"` // "texture" 或 "user"
TargetID int64 `json:"target_id" binding:"required"`
Reason string `json:"reason" binding:"required"`
}
// CreateReport 创建举报
// @Summary 创建举报
// @Description 用户举报皮肤或其他用户
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body CreateReportRequest true "举报信息"
// @Success 200 {object} model.Response{data=model.Report} "创建成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 401 {object} model.ErrorResponse "未授权"
// @Router /api/v1/report [post]
func (h *ReportHandler) CreateReport(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req CreateReportRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "参数错误", err)
return
}
// 转换目标类型
var targetType model.ReportType
switch req.TargetType {
case "texture":
targetType = model.ReportTypeTexture
case "user":
targetType = model.ReportTypeUser
default:
RespondBadRequest(c, "无效的举报类型", nil)
return
}
report, err := h.container.ReportService.CreateReport(c.Request.Context(), userID, targetType, req.TargetID, req.Reason)
if err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, report)
}
// GetByID 获取举报详情
// @Summary 获取举报详情
// @Description 获取指定ID的举报详细信息
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "举报ID"
// @Success 200 {object} model.Response{data=model.Report} "获取成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 404 {object} model.ErrorResponse "举报不存在"
// @Router /api/v1/report/{id} [get]
func (h *ReportHandler) GetByID(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
RespondBadRequest(c, "无效的举报ID", err)
return
}
report, err := h.container.ReportService.GetByID(c.Request.Context(), id)
if err != nil {
RespondNotFound(c, err.Error())
return
}
RespondSuccess(c, report)
}
// GetByReporterID 获取举报人的举报记录
// @Summary 获取举报人的举报记录
// @Description 获取指定用户的举报记录列表
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param reporter_id path int true "举报人ID"
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Router /api/v1/report/reporter/{reporter_id} [get]
func (h *ReportHandler) GetByReporterID(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
reporterID, err := strconv.ParseInt(c.Param("reporter_id"), 10, 64)
if err != nil {
RespondBadRequest(c, "无效的举报人ID", err)
return
}
page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1)
pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20)
reports, total, err := h.container.ReportService.GetByReporterID(c.Request.Context(), reporterID, userID, page, pageSize)
if err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, gin.H{
"list": reports,
"total": total,
"page": page,
"per_page": pageSize,
})
}
// GetByTarget 获取目标对象的举报记录
// @Summary 获取目标对象的举报记录
// @Description 获取指定目标对象的举报记录列表(仅管理员)
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param target_type path string true "目标类型 (texture/user)"
// @Param target_id path int true "目标ID"
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 403 {object} model.ErrorResponse "无权访问"
// @Router /api/v1/report/target/{target_type}/{target_id} [get]
func (h *ReportHandler) GetByTarget(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
targetTypeStr := c.Param("target_type")
targetID, err := strconv.ParseInt(c.Param("target_id"), 10, 64)
if err != nil {
RespondBadRequest(c, "无效的目标ID", err)
return
}
var targetType model.ReportType
switch targetTypeStr {
case "texture":
targetType = model.ReportTypeTexture
case "user":
targetType = model.ReportTypeUser
default:
RespondBadRequest(c, "无效的目标类型", nil)
return
}
page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1)
pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20)
reports, total, err := h.container.ReportService.GetByTarget(c.Request.Context(), targetType, targetID, userID, page, pageSize)
if err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, gin.H{
"list": reports,
"total": total,
"page": page,
"per_page": pageSize,
})
}
// GetByStatus 根据状态查询举报记录
// @Summary 根据状态查询举报记录
// @Description 根据状态查询举报记录列表(仅管理员)
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param status path string true "状态 (pending/approved/rejected)"
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Router /api/v1/report/status/{status} [get]
func (h *ReportHandler) GetByStatus(c *gin.Context) {
statusStr := c.Param("status")
var status model.ReportStatus
switch statusStr {
case "pending":
status = model.ReportStatusPending
case "approved":
status = model.ReportStatusApproved
case "rejected":
status = model.ReportStatusRejected
default:
RespondBadRequest(c, "无效的状态", nil)
return
}
page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1)
pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20)
reports, total, err := h.container.ReportService.GetByStatus(c.Request.Context(), status, page, pageSize)
if err != nil {
RespondServerError(c, err.Error(), err)
return
}
RespondSuccess(c, gin.H{
"list": reports,
"total": total,
"page": page,
"per_page": pageSize,
})
}
// Search 搜索举报记录
// @Summary 搜索举报记录
// @Description 搜索举报记录(仅管理员)
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param keyword query int false "关键词举报人ID或目标ID"
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(20)
// @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 403 {object} model.ErrorResponse "无权访问"
// @Router /api/v1/report/search [get]
func (h *ReportHandler) Search(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
keywordStr := c.Query("keyword")
keyword, err := strconv.ParseInt(keywordStr, 10, 64)
if err != nil {
RespondBadRequest(c, "无效的关键词", err)
return
}
page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1)
pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20)
reports, total, err := h.container.ReportService.Search(c.Request.Context(), keyword, userID, page, pageSize)
if err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, gin.H{
"list": reports,
"total": total,
"page": page,
"per_page": pageSize,
})
}
// ReviewRequest 处理举报请求
type ReviewRequest struct {
Status string `json:"status" binding:"required"` // "approved" 或 "rejected"
ReviewNote string `json:"review_note"`
}
// Review 处理举报记录
// @Summary 处理举报记录
// @Description 管理员处理举报记录
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "举报ID"
// @Param request body ReviewRequest true "处理信息"
// @Success 200 {object} model.Response{data=model.Report} "处理成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 403 {object} model.ErrorResponse "无权访问"
// @Router /api/v1/report/{id}/review [put]
func (h *ReportHandler) Review(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
RespondBadRequest(c, "无效的举报ID", err)
return
}
var req ReviewRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "参数错误", err)
return
}
// 转换状态
var status model.ReportStatus
switch req.Status {
case "approved":
status = model.ReportStatusApproved
case "rejected":
status = model.ReportStatusRejected
default:
RespondBadRequest(c, "无效的状态", nil)
return
}
report, err := h.container.ReportService.Review(c.Request.Context(), id, userID, status, req.ReviewNote)
if err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, report)
}
// BatchReviewRequest 批量处理举报请求
type BatchReviewRequest struct {
IDs []int64 `json:"ids" binding:"required"`
Status string `json:"status" binding:"required"` // "approved" 或 "rejected"
ReviewNote string `json:"review_note"`
}
// BatchReview 批量处理举报记录
// @Summary 批量处理举报记录
// @Description 管理员批量处理举报记录
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body BatchReviewRequest true "处理信息"
// @Success 200 {object} model.Response{data=map[string]interface{}} "处理成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 403 {object} model.ErrorResponse "无权访问"
// @Router /api/v1/report/batch-review [put]
func (h *ReportHandler) BatchReview(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req BatchReviewRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "参数错误", err)
return
}
// 转换状态
var status model.ReportStatus
switch req.Status {
case "approved":
status = model.ReportStatusApproved
case "rejected":
status = model.ReportStatusRejected
default:
RespondBadRequest(c, "无效的状态", nil)
return
}
affected, err := h.container.ReportService.BatchReview(c.Request.Context(), req.IDs, userID, status, req.ReviewNote)
if err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, gin.H{
"affected": affected,
})
}
// Delete 删除举报记录
// @Summary 删除举报记录
// @Description 删除指定的举报记录
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "举报ID"
// @Success 200 {object} model.Response "删除成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 403 {object} model.ErrorResponse "无权访问"
// @Router /api/v1/report/{id} [delete]
func (h *ReportHandler) Delete(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
RespondBadRequest(c, "无效的举报ID", err)
return
}
if err := h.container.ReportService.Delete(c.Request.Context(), id, userID); err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, nil)
}
// BatchDeleteRequest 批量删除请求
type BatchDeleteRequest struct {
IDs []int64 `json:"ids" binding:"required"`
}
// BatchDelete 批量删除举报记录
// @Summary 批量删除举报记录
// @Description 管理员批量删除举报记录
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body BatchDeleteRequest true "删除信息"
// @Success 200 {object} model.Response{data=map[string]interface{}} "删除成功"
// @Failure 400 {object} model.ErrorResponse "参数错误"
// @Failure 403 {object} model.ErrorResponse "无权访问"
// @Router /api/v1/report/batch-delete [delete]
func (h *ReportHandler) BatchDelete(c *gin.Context) {
userID, ok := GetUserIDFromContext(c)
if !ok {
return
}
var req BatchDeleteRequest
if err := c.ShouldBindJSON(&req); err != nil {
RespondBadRequest(c, "参数错误", err)
return
}
affected, err := h.container.ReportService.BatchDelete(c.Request.Context(), req.IDs, userID)
if err != nil {
RespondBadRequest(c, err.Error(), err)
return
}
RespondSuccess(c, gin.H{
"affected": affected,
})
}
// GetStats 获取举报统计信息
// @Summary 获取举报统计信息
// @Description 获取举报统计信息(仅管理员)
// @Tags report
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功"
// @Router /api/v1/report/stats [get]
func (h *ReportHandler) GetStats(c *gin.Context) {
stats, err := h.container.ReportService.GetStats(c.Request.Context())
if err != nil {
RespondServerError(c, err.Error(), err)
return
}
RespondSuccess(c, stats)
}