package logic import ( "context" "slowwild/internal/svc" "strings" "git.banshen.xyz/huangguangrong/slow_wild_protobuff/slowwild/slowwildserver" "slowwild/internal/errorx" "slowwild/internal/model" "time" "slowwild/internal/utils" "github.com/spf13/cast" "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" ) type CreatePostLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger } func NewCreatePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreatePostLogic { return &CreatePostLogic{ ctx: ctx, svcCtx: svcCtx, Logger: logx.WithContext(ctx), } } // 发布帖子 func (l *CreatePostLogic) CreatePost(in *slowwildserver.CreatePostReq) (*slowwildserver.CreatePostRsp, error) { if in.UserId <= 0 || in.Content == "" { return nil, errorx.ErrInvalidParam } // 检查帖子类型是否合法 if in.Type != 0 && in.Type != 1 { return nil, errorx.NewCodeError(20001, "帖子类型不合法") } // 开启事务 err := l.svcCtx.UserModel.Transaction(l.ctx, func(tx *gorm.DB) error { postModel := model.NewPostModel(tx, l.svcCtx.Redis) postContentModel := model.NewPostContentModel(tx) userModel := model.NewUserModel(tx) tagModel := model.NewTagModel(tx, l.svcCtx.Redis) messageModel := model.NewMessageModel(tx) // 提取话题名称 var tagNames []string for _, tag := range in.Tags { tagNames = append(tagNames, tag.Name) } // 检查话题是否存在 existingTags, err := tagModel.FindByNames(l.ctx, tagNames) if err != nil { return err } // 找出不存在的话题名称 existingTagMap := make(map[string]bool) for _, tag := range existingTags { existingTagMap[tag.Name] = true } // 需要新建的话题 var newTags []*model.Tag for _, tag := range in.Tags { if !existingTagMap[tag.Name] { newTags = append(newTags, &model.Tag{ Model: &model.Model{ CreatedOn: time.Now().Unix(), ModifiedOn: time.Now().Unix(), }, UserId: in.UserId, Name: tag.Name, HotNum: 0, }) } } // 创建新话题 if len(newTags) > 0 { if err = tagModel.BatchCreate(l.ctx, newTags); err != nil { return err } } // 获取所有话题的ID var tagIds []int64 for _, tag := range existingTags { tagIds = append(tagIds, tag.ID) } for _, tag := range newTags { tagIds = append(tagIds, tag.ID) } // 判断@用户是否重复,重复只发一次 existUserMap := make(map[string]bool) if len(in.AtUserIds) > 0 { for _, id := range in.AtUserIds { existUserMap[cast.ToString(id)] = true } } atUserIds := make([]string, 0, len(existUserMap)) if len(existUserMap) > 0 { for id := range existUserMap { atUserIds = append(atUserIds, id) } } // 创建帖子 post := &model.Post{ Model: &model.Model{ CreatedOn: time.Now().Unix(), ModifiedOn: time.Now().Unix(), }, UserId: in.UserId, PostType: in.Type, Visibility: int8(in.Visibility), Tags: strings.Join(tagNames, ","), Ip: in.Ip, IpLoc: in.IpLoc, WithUserIds: strings.Join(atUserIds, ","), CommentCount: 0, CollectionCount: 0, UpvoteCount: 0, ShareCount: 0, IsTop: 0, IsEssence: 0, HotNum: 0, } // 创建帖子基本信息 if err := postModel.Create(l.ctx, post); err != nil { return err } // 处理内容,生成摘要 plainContent := utils.StripHTML(in.Content) contentSummary := utils.TruncateText(plainContent, 1000) // 创建帖子内容 postContent := &model.PostContent{ Model: &model.Model{ CreatedOn: time.Now().Unix(), ModifiedOn: time.Now().Unix(), }, PostId: post.ID, UserId: in.UserId, Title: in.Title, Content: in.Content, // 保存原始内容 ContentSummary: contentSummary, // 保存处理后的摘要 PostVideoCover: in.VideoCover, PostCovers: strings.Join(in.Images, ","), PostVideoUrl: in.VideoUrl, Sort: 0, } if err := postContentModel.Create(l.ctx, postContent); err != nil { return err } // 创建帖子和话题的关联关系 if err := tagModel.CreateTagWithPost(l.ctx, post.ID, tagIds); err != nil { return err } // 检查被艾特的用户是否存在 if len(atUserIds) > 0 { atUsers, err := userModel.FindByIds(l.ctx, in.AtUserIds) if err != nil { return err } // 发送站内信给被艾特的用户 for _, user := range atUsers { err = messageModel.SendNotification(l.ctx, in.UserId, user.ID, 1, "你被艾特了", "你被艾特在一条动态中", post.ID, 0, 0) if err != nil { return err } } } // 增加用户的帖子数 if err := userModel.IncrementTweetCount(l.ctx, in.UserId); err != nil { return err } // 删除缓存 postModel.ClearListCache(l.ctx) return nil }) if err != nil { l.Logger.Errorf("发布帖子失败: %v", err) return nil, errorx.NewCodeError(20002, "发布帖子失败") } return &slowwildserver.CreatePostRsp{}, nil }