435 lines
12 KiB
Go
435 lines
12 KiB
Go
package plant
|
|
|
|
import (
|
|
"sundynix-go/global"
|
|
"sundynix-go/model/plant"
|
|
plantReq "sundynix-go/model/plant/request"
|
|
"sundynix-go/model/system"
|
|
|
|
"sundynix-go/utils/wechat"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type PostService struct{}
|
|
|
|
var PostServiceApp = new(PostService)
|
|
|
|
// PublishPost 发表帖子
|
|
func (s *PostService) PublishPost(req plantReq.CreatePost, userId string) error {
|
|
var postId string
|
|
var ossList []*system.Oss
|
|
|
|
err := global.DB.Transaction(func(tx *gorm.DB) error {
|
|
//1.验证oss是否存在
|
|
err := tx.Where("id in ?", req.OssIds).Find(&ossList).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//2.保存帖子
|
|
post := plant.Post{
|
|
Title: req.Title,
|
|
UserId: userId,
|
|
Content: req.Content,
|
|
Location: req.Location,
|
|
}
|
|
err = tx.Create(&post).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
postId = post.Id
|
|
|
|
//3.处理图片关系
|
|
if len(ossList) > 0 {
|
|
var relations []map[string]interface{}
|
|
for _, oss := range ossList {
|
|
relations = append(relations, map[string]interface{}{
|
|
"post_id": post.Id,
|
|
"oss_id": oss.Id,
|
|
})
|
|
}
|
|
err = tx.Table("sundynix_post_oss").Create(relations).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
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 帖子列表
|
|
func (s *PostService) PostPage(req plantReq.PostPage, userId string) (list interface{}, total int64, err error) {
|
|
limit := req.PageSize
|
|
offset := req.PageSize * (req.Current - 1)
|
|
db := global.DB.Model(&plant.Post{}).
|
|
Preload("ImgList", func(db *gorm.DB) *gorm.DB {
|
|
return db.Order("created_at desc")
|
|
}).
|
|
Preload("Publisher", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Avatar")
|
|
}).
|
|
Preload("CommentList", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Commentator", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Avatar")
|
|
})
|
|
}).Preload("LikeList", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Liker")
|
|
})
|
|
var posts []plant.Post
|
|
if req.Title != "" {
|
|
db = db.Where("title like ?", "%"+req.Title+"%")
|
|
}
|
|
if req.HasReviewed != nil {
|
|
db = db.Where("has_reviewed = ?", *req.HasReviewed)
|
|
}
|
|
//todo 审核帖子
|
|
err = db.Count(&total).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&posts).Error
|
|
// 优化 N+1 查询
|
|
var postIds []string
|
|
for _, v := range posts {
|
|
postIds = append(postIds, v.Id)
|
|
}
|
|
// 批量查询当前用户点赞的记录
|
|
var postLikeList []*plant.PostLike
|
|
err = global.DB.Where("user_id = ? and post_id in ?", userId, postIds).Find(&postLikeList).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
//批量查询当前用户的收藏
|
|
var stars []*plant.UserStar
|
|
err = global.DB.Where("user_id = ? and post_id in ?", userId, postIds).Find(&stars).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
// 构建id映射
|
|
likesMap := make(map[string]bool)
|
|
for _, v := range postLikeList {
|
|
likesMap[v.PostId] = true
|
|
}
|
|
starsMap := make(map[string]bool)
|
|
for _, v := range stars {
|
|
starsMap[v.PostId] = true
|
|
}
|
|
// 是否点赞
|
|
for i := range posts {
|
|
if likesMap[posts[i].Id] {
|
|
posts[i].HasLiked = 1
|
|
} else {
|
|
posts[i].HasLiked = 0
|
|
}
|
|
|
|
if starsMap[posts[i].Id] {
|
|
posts[i].HasStar = 1
|
|
} else {
|
|
posts[i].HasStar = 0
|
|
}
|
|
}
|
|
|
|
return posts, total, err
|
|
}
|
|
|
|
// MyPost 我的帖子
|
|
func (s *PostService) MyPost(req plantReq.PostPage, userId string) (list interface{}, total int64, err error) {
|
|
limit := req.PageSize
|
|
offset := req.PageSize * (req.Current - 1)
|
|
db := global.DB.Model(&plant.Post{}).
|
|
Preload("ImgList", func(db *gorm.DB) *gorm.DB {
|
|
return db.Order("created_at desc")
|
|
}).
|
|
Preload("Publisher", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Avatar")
|
|
}).
|
|
Preload("LikeList", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Liker", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Avatar")
|
|
})
|
|
}).
|
|
Preload("CommentList", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Commentator", func(db *gorm.DB) *gorm.DB {
|
|
return db.Preload("Avatar")
|
|
})
|
|
})
|
|
var posts []plant.Post
|
|
db = db.Where("user_id = ?", userId)
|
|
if req.Title != "" {
|
|
db = db.Where("title like ?", "%"+req.Title+"%")
|
|
}
|
|
//todo 审核帖子
|
|
err = db.Count(&total).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&posts).Error
|
|
// 优化 N+1 查询
|
|
var postIds []string
|
|
for _, v := range posts {
|
|
postIds = append(postIds, v.Id)
|
|
}
|
|
// 批量查询当前用户点赞的记录
|
|
var postLikeList []*plant.PostLike
|
|
err = global.DB.Where("user_id = ? and post_id in ?", userId, postIds).Find(&postLikeList).Error
|
|
if err != nil {
|
|
return
|
|
}
|
|
// 构建id映射
|
|
likesMap := make(map[string]bool)
|
|
for _, v := range postLikeList {
|
|
likesMap[v.PostId] = true
|
|
}
|
|
// 是否点赞
|
|
for i := range posts {
|
|
if likesMap[posts[i].Id] {
|
|
posts[i].HasLiked = 1
|
|
} else {
|
|
posts[i].HasLiked = 0
|
|
}
|
|
}
|
|
|
|
return posts, total, err
|
|
}
|
|
|
|
// LikePost 点赞帖或取消赞
|
|
func (s *PostService) LikePost(userId, postId, class string) error {
|
|
// class = 1点赞
|
|
if class == "1" {
|
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
|
var post plant.Post
|
|
err := tx.Where("id = ?", postId).First(&post).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//1.更新点赞数
|
|
err = tx.Model(&post).Update("like_count", post.LikeCount+1).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//2.添加点赞记录
|
|
like := plant.PostLike{
|
|
UserId: userId,
|
|
PostId: postId,
|
|
}
|
|
return tx.Create(&like).Error
|
|
})
|
|
} else if class == "2" {
|
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
|
var like plant.PostLike
|
|
err := tx.Where("post_id = ? and user_id = ?", postId, userId).First(&like).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//1.更新点赞数
|
|
var post plant.Post
|
|
err = tx.Where("id = ?", postId).First(&post).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = tx.Model(&post).
|
|
Where("like_count > 0"). // 只有大于 0 才会执行减法
|
|
Update("like_count", post.LikeCount-1).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//2.删除点赞记录
|
|
return tx.Unscoped().Delete(&like).Error
|
|
})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CommentPost 评论帖子
|
|
func (s *PostService) CommentPost(req plantReq.CreateComment, userId string) error {
|
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
|
//1.为帖子评论数量+1
|
|
var post plant.Post
|
|
err := global.DB.Where("id = ?", req.PostId).First(&post).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//1.更新评论数
|
|
err = tx.Model(&post).Update("comment_count", post.CommentCount+1).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//2.添加评论
|
|
comment := plant.PostComment{
|
|
PostId: req.PostId,
|
|
UserId: userId,
|
|
Content: req.Content,
|
|
}
|
|
return tx.Create(&comment).Error
|
|
})
|
|
}
|
|
|
|
// DeletePost 删除帖子
|
|
func (s *PostService) DeletePost(ids []string) error {
|
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
|
var imgIds []string
|
|
tx.Table("sundynix_post_oss").Where("post_id IN ?", ids).Pluck("oss_id", &imgIds)
|
|
|
|
// 2. 清理中间表记录 (解开多对多关系)
|
|
// 使用 Exec 直接操作中间表比循环 Clear 快得多
|
|
if err := tx.Exec("DELETE FROM sundynix_post_oss WHERE post_id IN ?", ids).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// 3. 物理删除图片记录本身
|
|
if len(imgIds) > 0 {
|
|
if err := tx.Unscoped().Where("id IN ?", imgIds).Delete(&system.Oss{}).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// 4. 批量删除点赞 (PostLike)
|
|
if err := tx.Unscoped().Where("post_id IN ?", ids).Delete(&plant.PostLike{}).Error; err != nil {
|
|
return err
|
|
}
|
|
// 5. 批量删除评论 (PostComment)
|
|
if err := tx.Unscoped().Where("post_id IN ?", ids).Delete(&plant.PostComment{}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// 6. 最后删除主表 Post
|
|
if err := tx.Unscoped().Where("id IN ?", ids).Delete(&plant.Post{}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// StarPost 收藏帖子
|
|
func (s *PostService) StarPost(userId string, postId string, class string) error {
|
|
if class == "1" {
|
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
|
var post plant.Post
|
|
err := tx.Where("id = ?", postId).First(&post).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//1.更新点赞数
|
|
err = tx.Model(&post).Update("star_count", post.LikeCount+1).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//2.添加到我的收藏
|
|
star := plant.UserStar{
|
|
UserId: userId,
|
|
Type: 2,
|
|
PostId: postId,
|
|
}
|
|
return tx.Create(&star).Error
|
|
})
|
|
} else if class == "2" {
|
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
|
var star plant.UserStar
|
|
err := tx.Where("post_id = ? and user_id = ?", postId, userId).First(&star).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//1.更新收藏数
|
|
var post plant.Post
|
|
err = tx.Where("id = ?", postId).First(&post).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = tx.Model(&post).
|
|
Where("star_count > ?", 0). // 只有大于 0 才会执行减法
|
|
Update("star_count", gorm.Expr("star_count - 1")).
|
|
Error
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//2.删除收藏
|
|
return tx.Unscoped().Delete(&star).Error
|
|
})
|
|
}
|
|
return nil
|
|
}
|