feat: 异步校验社区post文本内容是否违规

This commit is contained in:
Blizzard
2026-02-14 13:08:52 +08:00
parent 3cf4841fdd
commit 4ffc41ea84
7 changed files with 112 additions and 16 deletions
+2
View File
@@ -12,6 +12,7 @@ type ApiGroup struct {
LevelConfigApi
UserProfileApi
BadgeConfigApi
CallbackApi
}
var (
@@ -24,4 +25,5 @@ var (
levelConfigService = service.GroupApp.PlantServiceGroup.LevelConfigService
userProfileService = service.GroupApp.PlantServiceGroup.UserProfileService
badgeConfigService = service.GroupApp.PlantServiceGroup.BadgeConfigService
callbackService = service.GroupApp.PlantServiceGroup.CallbackService
)
+13 -12
View File
@@ -39,18 +39,19 @@ func MigrateTable() {
system.SysOperationRecord{},
system.Oss{},
plant.MyPlant{}, //我的植物
plant.CarePlan{}, //植物养护计划
plant.CareTask{}, //植物养护任务
plant.CareRecord{}, //植物养护记录
plant.GrowthRecord{}, //植物成长记录
plant.Topic{}, //帖子话题
plant.Post{}, //帖子
plant.PostLike{}, //帖子点赞
plant.PostComment{}, //帖子评论
plant.Class{}, //百科分类
plant.Wiki{}, //百科植物
plant.ClassifyRecord{}, //植物识别记录
plant.MyPlant{}, //我的植物
plant.CarePlan{}, //植物养护计划
plant.CareTask{}, //植物养护任务
plant.CareRecord{}, //植物养护记录
plant.GrowthRecord{}, //植物成长记录
plant.MediaCheckResult{}, //媒体安全检测结果
plant.Topic{}, //帖子话题
plant.Post{}, //帖子
plant.PostLike{}, //帖子点赞
plant.PostComment{}, //帖子评论
plant.Class{}, //百科分类
plant.Wiki{}, //百科植物
plant.ClassifyRecord{}, //植物识别记录
plant.LevelConfig{}, //等级配置
plant.BadgeConfig{}, //徽章配置
+2 -1
View File
@@ -35,7 +35,8 @@ func Routers() {
NeedAuthGroup.Use(middleware.AuthMiddleware())
{
//无须鉴权的路由
systemRouter.InitAuthRouter(PublicGroup) //登录不需要鉴权
systemRouter.InitAuthRouter(PublicGroup) //登录不需要鉴权
plantGroup.InitCallbackRouter(PublicGroup) // 回调
}
{
+1 -1
View File
@@ -16,7 +16,7 @@ type Post struct {
LikeCount int `json:"likeCount" form:"likeCount" gorm:"default:0;column:like_count;comment:点赞次数"`
StarCount int `json:"starCount" form:"starCount" gorm:"default:0;column:star_count;comment:收藏次数"`
Location string `json:"location" form:"location" gorm:"column:location;size:100;comment:位置"`
HasReviewed int `json:"hasReviewed" form:"hasReviewed" gorm:"column:has_reviewed;default:0;comment:是否审核通过"`
HasReviewed int `json:"hasReviewed" form:"hasReviewed" gorm:"column:has_reviewed;default:0;comment:是否审核通过"` // 0-未审核 1-审核通过 2-违规
HasLiked int `json:"hasLiked" form:"hasLiked" gorm:"-"`
HasStar int `json:"hasStar" form:"hasStar" gorm:"-"`
//图片
+2
View File
@@ -12,6 +12,7 @@ type RouterGroup struct {
LevelConfigRouter
BadgeConfigRouter
UserProfileRouter
CallbackRouter
}
// 初始化路由
@@ -25,4 +26,5 @@ var (
levelConfigApi = v1.ApiGroupApp.PlantApiGroup.LevelConfigApi
userProfileApi = v1.ApiGroupApp.PlantApiGroup.UserProfileApi
badgeConfigApi = v1.ApiGroupApp.PlantApiGroup.BadgeConfigApi
callbackApi = v1.ApiGroupApp.PlantApiGroup.CallbackApi
)
+1
View File
@@ -10,4 +10,5 @@ type ServiceGroup struct {
LevelConfigService
BadgeConfigService
UserProfileService
CallbackService
}
+91 -2
View File
@@ -6,7 +6,11 @@ import (
plantReq "sundynix-go/model/plant/request"
"sundynix-go/model/system"
"sundynix-go/utils/wechat"
"gorm.io/gorm"
"go.uber.org/zap"
)
type PostService struct{}
@@ -15,9 +19,11 @@ var PostServiceApp = new(PostService)
// PublishPost 发表帖子
func (s *PostService) PublishPost(req plantReq.CreatePost, userId string) error {
return global.DB.Transaction(func(tx *gorm.DB) error {
var postId string
var ossList []*system.Oss
err := global.DB.Transaction(func(tx *gorm.DB) error {
//1.验证oss是否存在
var ossList []*system.Oss
err := tx.Where("id in ?", req.OssIds).Find(&ossList).Error
if err != nil {
return err
@@ -33,6 +39,8 @@ func (s *PostService) PublishPost(req plantReq.CreatePost, userId string) error
if err != nil {
return err
}
postId = post.Id
//3.处理图片关系
if len(ossList) > 0 {
var relations []map[string]interface{}
@@ -49,6 +57,87 @@ func (s *PostService) PublishPost(req plantReq.CreatePost, userId string) error
}
return nil
})
if err != nil {
return err
}
// 4.异步内容安全检查
// 4.异步内容安全检查
go func(pid, uid, title, content string, imgs []*system.Oss) {
defer func() {
if r := recover(); r != nil {
global.Logger.Error("异步内容安全检查Panic", zap.Any("panic", r))
}
}()
// 获取用户 openid
var user system.User
if err := global.DB.Where("id = ?", uid).First(&user).Error; err != nil {
global.Logger.Error("获取用户失败,跳过安全检查", zap.String("userId", uid), zap.Error(err))
return
}
openid := user.MiniOpenId
if openid == "" {
global.Logger.Warn("用户无MiniOpenId,跳过安全检查", zap.String("userId", uid))
return
}
// 文本检查
fullContent := title + "\n" + content
isSafe := wechat.MsgSecCheck(fullContent, openid)
// 文本违规 -> 直接拒绝
if !isSafe {
if err := global.DB.Model(&plant.Post{}).Where("id = ?", pid).Update("has_reviewed", 2).Error; err != nil {
global.Logger.Error("更新帖子违规状态失败", zap.String("postId", pid), zap.Error(err))
}
global.Logger.Info("帖子内容违规,已标记", zap.String("postId", pid))
return // 文本违规,无需再检查图片
}
if err := global.DB.Model(&plant.Post{}).Where("id = ?", pid).Update("has_reviewed", 1).Error; err != nil {
global.Logger.Error("更新帖子违规状态失败", zap.String("postId", pid), zap.Error(err))
}
return // 文本违规,无需再检查图片
// 文本通过,判断是否有图片
//if len(imgs) == 0 {
// // 无图且文本通过 -> 直接通过
// if err := global.DB.Model(&plant.Post{}).Where("id = ?", pid).Update("has_reviewed", 1).Error; err != nil {
// global.Logger.Error("更新帖子通过状态失败", zap.String("postId", pid), zap.Error(err))
// }
// return
//}
// 有图,文本通过 -> 保持状态为0(待审核),等待图片回调
// todo 图片检查
//for _, oss := range imgs {
// // 假设 oss.Url 是完整链接
// traceId, err := wechat.MediaCheckAsync(oss.Url, 2, openid)
// if err != nil {
// global.Logger.Error("图片安全检查请求失败", zap.String("url", oss.Url), zap.Error(err))
// continue
// }
// global.Logger.Info("图片安全检查请求成功", zap.String("traceId", traceId))
//
// // 保存检测记录
// checkResult := plant.MediaCheckResult{
// TraceId: traceId,
// PostId: pid,
// OssId: oss.Id,
// UserId: uid,
// Status: 0, // 检测中
// Type: 2, // 图片
// }
// if err := global.DB.Create(&checkResult).Error; err != nil {
// global.Logger.Error("保存媒体检测记录失败", zap.Error(err))
// }
//}
}(postId, userId, req.Title, req.Content, ossList)
return nil
}
// PostPage 帖子列表