Files
urldb/handlers/report_handler.go
2025-11-19 08:32:01 +08:00

310 lines
9.3 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 handlers
import (
"net/http"
"strconv"
"github.com/ctwj/urldb/db/converter"
"github.com/ctwj/urldb/db/dto"
"github.com/ctwj/urldb/db/entity"
"github.com/ctwj/urldb/db/repo"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"gorm.io/gorm"
)
type ReportHandler struct {
reportRepo repo.ReportRepository
resourceRepo repo.ResourceRepository
validate *validator.Validate
}
func NewReportHandler(reportRepo repo.ReportRepository, resourceRepo repo.ResourceRepository) *ReportHandler {
return &ReportHandler{
reportRepo: reportRepo,
resourceRepo: resourceRepo,
validate: validator.New(),
}
}
// CreateReport 创建举报
// @Summary 创建举报
// @Description 提交资源举报
// @Tags Report
// @Accept json
// @Produce json
// @Param request body dto.ReportCreateRequest true "举报信息"
// @Success 200 {object} Response{data=dto.ReportResponse}
// @Failure 400 {object} Response
// @Failure 500 {object} Response
// @Router /reports [post]
func (h *ReportHandler) CreateReport(c *gin.Context) {
var req dto.ReportCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
ErrorResponse(c, "参数错误: "+err.Error(), http.StatusBadRequest)
return
}
// 验证参数
if err := h.validate.Struct(req); err != nil {
ErrorResponse(c, "参数验证失败: "+err.Error(), http.StatusBadRequest)
return
}
// 创建举报实体
report := &entity.Report{
ResourceKey: req.ResourceKey,
Reason: req.Reason,
Description: req.Description,
Contact: req.Contact,
UserAgent: req.UserAgent,
IPAddress: req.IPAddress,
Status: "pending", // 默认为待处理
}
// 保存到数据库
if err := h.reportRepo.Create(report); err != nil {
ErrorResponse(c, "创建举报失败: "+err.Error(), http.StatusInternalServerError)
return
}
// 返回响应
response := converter.ReportToResponse(report)
SuccessResponse(c, response)
}
// GetReport 获取举报详情
// @Summary 获取举报详情
// @Description 根据ID获取举报详情
// @Tags Report
// @Produce json
// @Param id path int true "举报ID"
// @Success 200 {object} Response{data=dto.ReportResponse}
// @Failure 400 {object} Response
// @Failure 404 {object} Response
// @Failure 500 {object} Response
// @Router /reports/{id} [get]
func (h *ReportHandler) GetReport(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
report, err := h.reportRepo.GetByID(uint(id))
if err != nil {
if err == gorm.ErrRecordNotFound {
ErrorResponse(c, "举报不存在", http.StatusNotFound)
return
}
ErrorResponse(c, "获取举报失败: "+err.Error(), http.StatusInternalServerError)
return
}
response := converter.ReportToResponse(report)
SuccessResponse(c, response)
}
// ListReports 获取举报列表
// @Summary 获取举报列表
// @Description 获取举报列表(支持分页和状态筛选)
// @Tags Report
// @Produce json
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(10)
// @Param status query string false "处理状态"
// @Success 200 {object} Response{data=object{items=[]dto.ReportResponse,total=int}}
// @Failure 400 {object} Response
// @Failure 500 {object} Response
// @Router /reports [get]
func (h *ReportHandler) ListReports(c *gin.Context) {
var req dto.ReportListRequest
if err := c.ShouldBindQuery(&req); err != nil {
ErrorResponse(c, "参数错误: "+err.Error(), http.StatusBadRequest)
return
}
// 设置默认值
if req.Page == 0 {
req.Page = 1
}
if req.PageSize == 0 {
req.PageSize = 10
}
// 验证参数
if err := h.validate.Struct(req); err != nil {
ErrorResponse(c, "参数验证失败: "+err.Error(), http.StatusBadRequest)
return
}
reports, total, err := h.reportRepo.List(req.Status, req.Page, req.PageSize)
if err != nil {
ErrorResponse(c, "获取举报列表失败: "+err.Error(), http.StatusInternalServerError)
return
}
// 获取每个举报关联的资源
var reportResponses []*dto.ReportResponse
for _, report := range reports {
// 通过资源key查找关联的资源
resources, err := h.getResourcesByResourceKey(report.ResourceKey)
if err != nil {
// 如果获取资源失败,仍然返回基本的举报信息
reportResponses = append(reportResponses, converter.ReportToResponse(report))
} else {
// 使用包含资源详情的转换函数
response := converter.ReportToResponseWithResources(report, resources)
reportResponses = append(reportResponses, response)
}
}
PageResponse(c, reportResponses, total, req.Page, req.PageSize)
}
// getResourcesByResourceKey 根据资源key获取关联的资源列表
func (h *ReportHandler) getResourcesByResourceKey(resourceKey string) ([]*entity.Resource, error) {
// 从资源仓库获取与key关联的所有资源
resources, err := h.resourceRepo.FindByResourceKey(resourceKey)
if err != nil {
return nil, err
}
// 将 []entity.Resource 转换为 []*entity.Resource
var resourcePointers []*entity.Resource
for i := range resources {
resourcePointers = append(resourcePointers, &resources[i])
}
return resourcePointers, nil
}
// UpdateReport 更新举报状态
// @Summary 更新举报状态
// @Description 更新举报处理状态
// @Tags Report
// @Accept json
// @Produce json
// @Param id path int true "举报ID"
// @Param request body dto.ReportUpdateRequest true "更新信息"
// @Success 200 {object} Response{data=dto.ReportResponse}
// @Failure 400 {object} Response
// @Failure 404 {object} Response
// @Failure 500 {object} Response
// @Router /reports/{id} [put]
func (h *ReportHandler) UpdateReport(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
var req dto.ReportUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
ErrorResponse(c, "参数错误: "+err.Error(), http.StatusBadRequest)
return
}
// 验证参数
if err := h.validate.Struct(req); err != nil {
ErrorResponse(c, "参数验证失败: "+err.Error(), http.StatusBadRequest)
return
}
// 获取当前举报
_, err = h.reportRepo.GetByID(uint(id))
if err != nil {
if err == gorm.ErrRecordNotFound {
ErrorResponse(c, "举报不存在", http.StatusNotFound)
return
}
ErrorResponse(c, "获取举报失败: "+err.Error(), http.StatusInternalServerError)
return
}
// 更新状态
processedBy := uint(0) // 从上下文获取当前用户ID如果存在的话
if currentUser := c.GetUint("user_id"); currentUser > 0 {
processedBy = currentUser
}
if err := h.reportRepo.UpdateStatus(uint(id), req.Status, &processedBy, req.Note); err != nil {
ErrorResponse(c, "更新举报状态失败: "+err.Error(), http.StatusInternalServerError)
return
}
// 获取更新后的举报信息
updatedReport, err := h.reportRepo.GetByID(uint(id))
if err != nil {
ErrorResponse(c, "获取更新后举报信息失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, converter.ReportToResponse(updatedReport))
}
// DeleteReport 删除举报
// @Summary 删除举报
// @Description 删除举报记录
// @Tags Report
// @Produce json
// @Param id path int true "举报ID"
// @Success 200 {object} Response
// @Failure 400 {object} Response
// @Failure 500 {object} Response
// @Router /reports/{id} [delete]
func (h *ReportHandler) DeleteReport(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
if err := h.reportRepo.Delete(uint(id)); err != nil {
ErrorResponse(c, "删除举报失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, nil)
}
// GetReportByResource 获取某个资源的举报列表
// @Summary 获取资源举报列表
// @Description 获取某个资源的所有举报记录
// @Tags Report
// @Produce json
// @Param resource_key path string true "资源Key"
// @Success 200 {object} Response{data=[]dto.ReportResponse}
// @Failure 400 {object} Response
// @Failure 500 {object} Response
// @Router /reports/resource/{resource_key} [get]
func (h *ReportHandler) GetReportByResource(c *gin.Context) {
resourceKey := c.Param("resource_key")
if resourceKey == "" {
ErrorResponse(c, "资源Key不能为空", http.StatusBadRequest)
return
}
reports, err := h.reportRepo.GetByResourceKey(resourceKey)
if err != nil {
ErrorResponse(c, "获取资源举报失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, converter.ReportsToResponse(reports))
}
// RegisterReportRoutes 注册举报相关路由
func RegisterReportRoutes(router *gin.RouterGroup, reportRepo repo.ReportRepository, resourceRepo repo.ResourceRepository) {
handler := NewReportHandler(reportRepo, resourceRepo)
reports := router.Group("/reports")
{
reports.POST("", handler.CreateReport) // 创建举报
reports.GET("/:id", handler.GetReport) // 获取举报详情
reports.GET("", handler.ListReports) // 获取举报列表
reports.PUT("/:id", handler.UpdateReport) // 更新举报状态
reports.DELETE("/:id", handler.DeleteReport) // 删除举报
reports.GET("/resource/:resource_key", handler.GetReportByResource) // 获取资源举报列表
}
}