You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
paopao-ce/internal/dao/jinzhu/tweets.go

760 lines
20 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// Copyright 2022 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package jinzhu
import (
"fmt"
"strings"
"time"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/cs"
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr"
"github.com/rocboss/paopao-ce/pkg/debug"
"gorm.io/gorm"
)
var (
_ core.TweetService = (*tweetSrv)(nil)
_ core.TweetManageService = (*tweetManageSrv)(nil)
_ core.TweetHelpService = (*tweetHelpSrv)(nil)
_ core.TweetServantA = (*tweetSrvA)(nil)
_ core.TweetManageServantA = (*tweetManageSrvA)(nil)
_ core.TweetHelpServantA = (*tweetHelpSrvA)(nil)
)
type tweetSrv struct {
db *gorm.DB
}
type tweetManageSrv struct {
cacheIndex core.CacheIndexService
db *gorm.DB
}
type tweetHelpSrv struct {
db *gorm.DB
}
type tweetSrvA struct {
db *gorm.DB
}
type tweetManageSrvA struct {
db *gorm.DB
}
type tweetHelpSrvA struct {
db *gorm.DB
}
func newTweetService(db *gorm.DB) core.TweetService {
return &tweetSrv{
db: db,
}
}
func newTweetManageService(db *gorm.DB, cacheIndex core.CacheIndexService) core.TweetManageService {
return &tweetManageSrv{
cacheIndex: cacheIndex,
db: db,
}
}
func newTweetHelpService(db *gorm.DB) core.TweetHelpService {
return &tweetHelpSrv{
db: db,
}
}
func newTweetServantA(db *gorm.DB) core.TweetServantA {
return &tweetSrvA{
db: db,
}
}
func newTweetManageServantA(db *gorm.DB) core.TweetManageServantA {
return &tweetManageSrvA{
db: db,
}
}
func newTweetHelpServantA(db *gorm.DB) core.TweetHelpServantA {
return &tweetHelpSrvA{
db: db,
}
}
// MergePosts post数据整合
func (s *tweetHelpSrv) MergePosts(posts []*ms.Post) ([]*ms.PostFormated, error) {
postIds := make([]int64, 0, len(posts))
userIds := make([]int64, 0, len(posts))
for _, post := range posts {
postIds = append(postIds, post.ID)
userIds = append(userIds, post.UserID)
}
postContents, err := s.getPostContentsByIDs(postIds)
if err != nil {
return nil, err
}
users, err := s.getUsersByIDs(userIds)
if err != nil {
return nil, err
}
userMap := make(map[int64]*dbr.UserFormated, len(users))
for _, user := range users {
userMap[user.ID] = user.Format()
}
contentMap := make(map[int64][]*dbr.PostContentFormated, len(postContents))
for _, content := range postContents {
contentMap[content.PostID] = append(contentMap[content.PostID], content.Format())
}
// 数据整合
postsFormated := make([]*dbr.PostFormated, 0, len(posts))
for _, post := range posts {
postFormated := post.Format()
postFormated.User = userMap[post.UserID]
postFormated.Contents = contentMap[post.ID]
postsFormated = append(postsFormated, postFormated)
}
return postsFormated, nil
}
// RevampPosts post数据整形修复
func (s *tweetHelpSrv) RevampPosts(posts []*ms.PostFormated) ([]*ms.PostFormated, error) {
postIds := make([]int64, 0, len(posts))
userIds := make([]int64, 0, len(posts))
for _, post := range posts {
postIds = append(postIds, post.ID)
userIds = append(userIds, post.UserID)
}
postContents, err := s.getPostContentsByIDs(postIds)
if err != nil {
return nil, err
}
users, err := s.getUsersByIDs(userIds)
if err != nil {
return nil, err
}
userMap := make(map[int64]*dbr.UserFormated, len(users))
for _, user := range users {
userMap[user.ID] = user.Format()
}
contentMap := make(map[int64][]*dbr.PostContentFormated, len(postContents))
for _, content := range postContents {
contentMap[content.PostID] = append(contentMap[content.PostID], content.Format())
}
// 数据整合
for _, post := range posts {
post.User = userMap[post.UserID]
post.Contents = contentMap[post.ID]
}
return posts, nil
}
func (s *tweetHelpSrv) getPostContentsByIDs(ids []int64) ([]*dbr.PostContent, error) {
return (&dbr.PostContent{}).List(s.db, &dbr.ConditionsT{
"post_id IN ?": ids,
"ORDER": "sort ASC",
}, 0, 0)
}
func (s *tweetHelpSrv) getUsersByIDs(ids []int64) ([]*dbr.User, error) {
user := &dbr.User{}
return user.List(s.db, &dbr.ConditionsT{
"id IN ?": ids,
}, 0, 0)
}
func (s *tweetManageSrv) CreatePostCollection(postID, userID int64) (*ms.PostCollection, error) {
collection := &dbr.PostCollection{
PostID: postID,
UserID: userID,
}
return collection.Create(s.db)
}
func (s *tweetManageSrv) DeletePostCollection(p *ms.PostCollection) error {
return p.Delete(s.db)
}
func (s *tweetManageSrv) CreatePostContent(content *ms.PostContent) (*ms.PostContent, error) {
return content.Create(s.db)
}
func (s *tweetManageSrv) CreateAttachment(obj *ms.Attachment) (int64, error) {
attachment, err := obj.Create(s.db)
return attachment.ID, err
}
func (s *tweetManageSrv) CreatePost(post *ms.Post) (*ms.Post, error) {
post.LatestRepliedOn = time.Now().Unix()
p, err := post.Create(s.db)
if err != nil {
return nil, err
}
s.cacheIndex.SendAction(core.IdxActCreatePost, post)
return p, nil
}
func (s *tweetManageSrv) DeletePost(post *ms.Post) ([]string, error) {
var mediaContents []string
postId := post.ID
postContent := &dbr.PostContent{}
err := s.db.Transaction(
func(tx *gorm.DB) error {
if contents, err := postContent.MediaContentsByPostId(tx, postId); err == nil {
mediaContents = contents
} else {
return err
}
// 删推文
if err := post.Delete(tx); err != nil {
return err
}
// 删内容
if err := postContent.DeleteByPostId(tx, postId); err != nil {
return err
}
// 删评论
if contents, err := s.deleteCommentByPostId(tx, postId); err == nil {
mediaContents = append(mediaContents, contents...)
} else {
return err
}
if tags := strings.Split(post.Tags, ","); len(tags) > 0 {
// 删tag宽松处理错误有错误不会回滚
deleteTags(tx, tags)
}
return nil
},
)
if err != nil {
return nil, err
}
s.cacheIndex.SendAction(core.IdxActDeletePost, post)
return mediaContents, nil
}
func (s *tweetManageSrv) deleteCommentByPostId(db *gorm.DB, postId int64) ([]string, error) {
comment := &dbr.Comment{}
commentContent := &dbr.CommentContent{}
// 获取推文的所有评论id
commentIds, err := comment.CommentIdsByPostId(db, postId)
if err != nil {
return nil, err
}
// 获取评论的媒体内容
mediaContents, err := commentContent.MediaContentsByCommentId(db, commentIds)
if err != nil {
return nil, err
}
// 删评论
if err = comment.DeleteByPostId(db, postId); err != nil {
return nil, err
}
// 删评论内容
if err = commentContent.DeleteByCommentIds(db, commentIds); err != nil {
return nil, err
}
// 删评论的评论
if err = (&dbr.CommentReply{}).DeleteByCommentIds(db, commentIds); err != nil {
return nil, err
}
return mediaContents, nil
}
func (s *tweetManageSrv) LockPost(post *ms.Post) error {
post.IsLock = 1 - post.IsLock
return post.Update(s.db)
}
func (s *tweetManageSrv) StickPost(post *ms.Post) error {
post.IsTop = 1 - post.IsTop
if err := post.Update(s.db); err != nil {
return err
}
s.cacheIndex.SendAction(core.IdxActStickPost, post)
return nil
}
func (s *tweetManageSrv) HighlightPost(userId int64, postId int64) (res int, err error) {
var post dbr.Post
tx := s.db.Begin()
defer tx.Rollback()
post.Get(tx)
if err = tx.Where("id = ? AND is_del = 0", postId).First(&post).Error; err != nil {
return
}
if post.UserID != userId {
return 0, cs.ErrNoPermission
}
post.IsEssence = 1 - post.IsEssence
if err = post.Update(tx); err != nil {
return
}
tx.Commit()
return post.IsEssence, nil
}
func (s *tweetManageSrv) VisiblePost(post *ms.Post, visibility cs.TweetVisibleType) (err error) {
oldVisibility := post.Visibility
post.Visibility = ms.PostVisibleT(visibility)
// TODO: 这个判断是否可以不要呢
if oldVisibility == ms.PostVisibleT(visibility) {
return nil
}
// 私密推文 特殊处理
if visibility == cs.TweetVisitPrivate {
// 强制取消置顶
// TODO: 置顶推文用户是否有权设置成私密? 后续完善
post.IsTop = 0
}
tx := s.db.Begin()
defer tx.Rollback()
if err = post.Update(tx); err != nil {
return
}
// tag处理
tags := strings.Split(post.Tags, ",")
// TODO: 暂时宽松不处理错误,这里或许可以有优化,后续完善
if oldVisibility == dbr.PostVisitPrivate {
// 从私密转为非私密才需要重新创建tag
createTags(tx, post.UserID, tags)
} else if visibility == cs.TweetVisitPrivate {
// 从非私密转为私密才需要删除tag
deleteTags(tx, tags)
}
tx.Commit()
s.cacheIndex.SendAction(core.IdxActVisiblePost, post)
return
}
func (s *tweetManageSrv) UpdatePost(post *ms.Post) (err error) {
if err = post.Update(s.db); err != nil {
return
}
s.cacheIndex.SendAction(core.IdxActUpdatePost, post)
return
}
func (s *tweetManageSrv) CreatePostStar(postID, userID int64) (*ms.PostStar, error) {
star := &dbr.PostStar{
PostID: postID,
UserID: userID,
}
return star.Create(s.db)
}
func (s *tweetManageSrv) DeletePostStar(p *ms.PostStar) error {
return p.Delete(s.db)
}
func (s *tweetSrv) GetPostByID(id int64) (*ms.Post, error) {
post := &dbr.Post{
Model: &dbr.Model{
ID: id,
},
}
return post.Get(s.db)
}
func (s *tweetSrv) GetPosts(conditions ms.ConditionsT, offset, limit int) ([]*ms.Post, error) {
return (&dbr.Post{}).List(s.db, conditions, offset, limit)
}
func (s *tweetSrv) ListUserTweets(userId int64, style uint8, justEssence bool, limit, offset int) (res []*ms.Post, total int64, err error) {
db := s.db.Model(&dbr.Post{}).Where("user_id = ?", userId)
switch style {
case cs.StyleUserTweetsAdmin:
fallthrough
case cs.StyleUserTweetsSelf:
db = db.Where("visibility >= ?", cs.TweetVisitPrivate)
case cs.StyleUserTweetsFriend:
db = db.Where("visibility >= ?", cs.TweetVisitFriend)
case cs.StyleUserTweetsFollowing:
db = db.Where("visibility >= ?", cs.TweetVisitFollowing)
case cs.StyleUserTweetsGuest:
fallthrough
default:
db = db.Where("visibility >= ?", cs.TweetVisitPublic)
}
if justEssence {
db = db.Where("is_essence=1")
}
if err = db.Count(&total).Error; err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
if err = db.Order("is_top DESC, latest_replied_on DESC").Find(&res).Error; err != nil {
return
}
return
}
func (s *tweetSrv) ListIndexNewestTweets(limit, offset int) (res []*ms.Post, total int64, err error) {
db := s.db.Table(_post_).Where("visibility >= ?", cs.TweetVisitPublic)
if err = db.Count(&total).Error; err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
if err = db.Order("is_top DESC, latest_replied_on DESC").Find(&res).Error; err != nil {
return
}
return
}
func (s *tweetSrv) ListIndexHotsTweets(limit, offset int) (res []*ms.Post, total int64, err error) {
db := s.db.Table(_post_).Joins(fmt.Sprintf("LEFT JOIN %s metric ON %s.id=metric.post_id", _post_metric_, _post_)).Where(fmt.Sprintf("visibility >= ? AND %s.is_del=0 AND metric.is_del=0", _post_), cs.TweetVisitPublic)
if err = db.Count(&total).Error; err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
if err = db.Order("is_top DESC, metric.rank_score DESC, latest_replied_on DESC").Find(&res).Error; err != nil {
return
}
return
}
func (s *tweetSrv) ListSyncSearchTweets(limit, offset int) (res []*ms.Post, total int64, err error) {
db := s.db.Table(_post_).Where("visibility >= ?", cs.TweetVisitFriend)
if err = db.Count(&total).Error; err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
if err = db.Find(&res).Error; err != nil {
return
}
return
}
func (s *tweetSrv) ListFollowingTweets(userId int64, limit, offset int) (res []*ms.Post, total int64, err error) {
beFriendIds, beFollowIds, xerr := s.getUserRelation(userId)
if xerr != nil {
return nil, 0, xerr
}
beFriendCount, beFollowCount := len(beFriendIds), len(beFollowIds)
db := s.db.Model(&dbr.Post{})
//可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开',
switch {
case beFriendCount > 0 && beFollowCount > 0:
db = db.Where("user_id=? OR (visibility>=50 AND user_id IN(?)) OR (visibility>=60 AND user_id IN(?))", userId, beFriendIds, beFollowIds)
case beFriendCount > 0 && beFollowCount == 0:
db = db.Where("user_id=? OR (visibility>=50 AND user_id IN(?))", userId, beFriendIds)
case beFriendCount == 0 && beFollowCount > 0:
db = db.Where("user_id=? OR (visibility>=60 AND user_id IN(?))", userId, beFollowIds)
case beFriendCount == 0 && beFollowCount == 0:
db = db.Where("user_id = ?", userId)
}
if err = db.Count(&total).Error; err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
if err = db.Order("is_top DESC, latest_replied_on DESC").Find(&res).Error; err != nil {
return
}
return
}
func (s *tweetSrv) getUserRelation(userId int64) (beFriendIds []int64, beFollowIds []int64, err error) {
if err = s.db.Table(_contact_).Where("friend_id=? AND status=2 AND is_del=0", userId).Select("user_id").Find(&beFriendIds).Error; err != nil {
return
}
if err = s.db.Table(_following_).Where("user_id=? AND is_del=0", userId).Select("follow_id").Find(&beFollowIds).Error; err != nil {
return
}
// 即是好友又是关注者,保留好友去除关注者
for _, id := range beFriendIds {
for i := 0; i < len(beFollowIds); i++ {
// 找到item即删数据库已经保证唯一性
if beFollowIds[i] == id {
lastIdx := len(beFollowIds) - 1
beFollowIds[i] = beFollowIds[lastIdx]
beFollowIds = beFollowIds[:lastIdx]
break
}
}
}
return
}
func (s *tweetSrv) GetPostCount(conditions ms.ConditionsT) (int64, error) {
return (&dbr.Post{}).Count(s.db, conditions)
}
func (s *tweetSrv) GetUserPostStar(postID, userID int64) (*ms.PostStar, error) {
star := &dbr.PostStar{
PostID: postID,
UserID: userID,
}
return star.Get(s.db)
}
func (s *tweetSrv) GetUserPostStars(userID int64, limit int, offset int) ([]*ms.PostStar, error) {
star := &dbr.PostStar{
UserID: userID,
}
return star.List(s.db, &dbr.ConditionsT{
"ORDER": s.db.NamingStrategy.TableName("PostStar") + ".id DESC",
}, cs.RelationSelf, limit, offset)
}
func (s *tweetSrv) ListUserStarTweets(user *cs.VistUser, limit int, offset int) (res []*ms.PostStar, total int64, err error) {
star := &dbr.PostStar{
UserID: user.UserId,
}
if total, err = star.Count(s.db, user.RelTyp, &dbr.ConditionsT{}); err != nil {
return
}
res, err = star.List(s.db, &dbr.ConditionsT{
"ORDER": s.db.NamingStrategy.TableName("PostStar") + ".id DESC",
}, user.RelTyp, limit, offset)
return
}
func (s *tweetSrv) getUserTweets(db *gorm.DB, user *cs.VistUser, limit int, offset int) (res []*ms.Post, total int64, err error) {
visibilities := []core.PostVisibleT{core.PostVisitPublic}
switch user.RelTyp {
case cs.RelationAdmin, cs.RelationSelf:
visibilities = append(visibilities, core.PostVisitPrivate, core.PostVisitFriend)
case cs.RelationFriend:
visibilities = append(visibilities, core.PostVisitFriend)
case cs.RelationGuest:
fallthrough
default:
// nothing
}
db = db.Where("visibility IN ? AND is_del=0", visibilities)
err = db.Count(&total).Error
if err != nil {
return
}
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
err = db.Order("latest_replied_on DESC").Find(&res).Error
return
}
func (s *tweetSrv) ListUserMediaTweets(user *cs.VistUser, limit int, offset int) ([]*ms.Post, int64, error) {
db := s.db.Table(_post_by_media_).Where("user_id=?", user.UserId)
return s.getUserTweets(db, user, limit, offset)
}
func (s *tweetSrv) ListUserCommentTweets(user *cs.VistUser, limit int, offset int) ([]*ms.Post, int64, error) {
db := s.db.Table(_post_by_comment_).Where("comment_user_id=?", user.UserId)
return s.getUserTweets(db, user, limit, offset)
}
func (s *tweetSrv) GetUserPostStarCount(userID int64) (int64, error) {
star := &dbr.PostStar{
UserID: userID,
}
return star.Count(s.db, cs.RelationSelf, &dbr.ConditionsT{})
}
func (s *tweetSrv) GetUserPostCollection(postID, userID int64) (*ms.PostCollection, error) {
star := &dbr.PostCollection{
PostID: postID,
UserID: userID,
}
return star.Get(s.db)
}
func (s *tweetSrv) GetUserPostCollections(userID int64, offset, limit int) ([]*ms.PostCollection, error) {
collection := &dbr.PostCollection{
UserID: userID,
}
return collection.List(s.db, &dbr.ConditionsT{
"ORDER": s.db.NamingStrategy.TableName("PostCollection") + ".id DESC",
}, offset, limit)
}
func (s *tweetSrv) GetUserPostCollectionCount(userID int64) (int64, error) {
collection := &dbr.PostCollection{
UserID: userID,
}
return collection.Count(s.db, &dbr.ConditionsT{})
}
func (s *tweetSrv) GetUserWalletBills(userID int64, offset, limit int) ([]*ms.WalletStatement, error) {
statement := &dbr.WalletStatement{
UserID: userID,
}
return statement.List(s.db, &dbr.ConditionsT{
"ORDER": "id DESC",
}, offset, limit)
}
func (s *tweetSrv) GetUserWalletBillCount(userID int64) (int64, error) {
statement := &dbr.WalletStatement{
UserID: userID,
}
return statement.Count(s.db, &dbr.ConditionsT{})
}
func (s *tweetSrv) GetPostAttatchmentBill(postID, userID int64) (*ms.PostAttachmentBill, error) {
bill := &dbr.PostAttachmentBill{
PostID: postID,
UserID: userID,
}
return bill.Get(s.db)
}
func (s *tweetSrv) GetPostContentsByIDs(ids []int64) ([]*ms.PostContent, error) {
return (&dbr.PostContent{}).List(s.db, &dbr.ConditionsT{
"post_id IN ?": ids,
"ORDER": "sort ASC",
}, 0, 0)
}
func (s *tweetSrv) GetPostContentByID(id int64) (*ms.PostContent, error) {
return (&dbr.PostContent{
Model: &dbr.Model{
ID: id,
},
}).Get(s.db)
}
func (s *tweetSrvA) TweetInfoById(id int64) (*cs.TweetInfo, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetSrvA) TweetItemById(id int64) (*cs.TweetItem, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetSrvA) UserTweets(visitorId, userId int64) (cs.TweetList, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetSrvA) ReactionByTweetId(userId int64, tweetId int64) (*cs.ReactionItem, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetSrvA) UserReactions(userId int64, offset int, limit int) (cs.ReactionList, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetSrvA) FavoriteByTweetId(userId int64, tweetId int64) (*cs.FavoriteItem, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetSrvA) UserFavorites(userId int64, offset int, limit int) (cs.FavoriteList, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetSrvA) AttachmentByTweetId(userId int64, tweetId int64) (*cs.AttachmentBill, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetManageSrvA) CreateAttachment(obj *cs.Attachment) (int64, error) {
// TODO
return 0, debug.ErrNotImplemented
}
func (s *tweetManageSrvA) CreateTweet(userId int64, req *cs.NewTweetReq) (*cs.TweetItem, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetManageSrvA) DeleteTweet(userId int64, tweetId int64) ([]string, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetManageSrvA) LockTweet(userId int64, tweetId int64) error {
// TODO
return debug.ErrNotImplemented
}
func (s *tweetManageSrvA) StickTweet(userId int64, tweetId int64) error {
// TODO
return debug.ErrNotImplemented
}
func (s *tweetManageSrvA) VisibleTweet(userId int64, visibility cs.TweetVisibleType) error {
// TODO
return debug.ErrNotImplemented
}
func (s *tweetManageSrvA) CreateReaction(userId int64, tweetId int64) error {
// TODO
return debug.ErrNotImplemented
}
func (s *tweetManageSrvA) DeleteReaction(userId int64, reactionId int64) error {
// TODO
return debug.ErrNotImplemented
}
func (s *tweetManageSrvA) CreateFavorite(userId int64, tweetId int64) error {
// TODO
return debug.ErrNotImplemented
}
func (s *tweetManageSrvA) DeleteFavorite(userId int64, favoriteId int64) error {
// TODO
return debug.ErrNotImplemented
}
func (s *tweetHelpSrvA) RevampTweets(tweets cs.TweetList) (cs.TweetList, error) {
// TODO
return nil, debug.ErrNotImplemented
}
func (s *tweetHelpSrvA) MergeTweets(tweets cs.TweetInfo) (cs.TweetList, error) {
// TODO
return nil, debug.ErrNotImplemented
}