|
@@ -0,0 +1,567 @@
|
|
|
|
|
+package model
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "context"
|
|
|
|
|
+ "encoding/json"
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "time"
|
|
|
|
|
+
|
|
|
|
|
+ "git.banshen.xyz/huangguangrong/slow_wild_protobuff/slowwild/slowwildserver"
|
|
|
|
|
+ "github.com/go-redis/redis/v8"
|
|
|
|
|
+ "gorm.io/gorm"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+const (
|
|
|
|
|
+ // 缓存key前缀
|
|
|
|
|
+ prefixPostKey = "post:%d" // 帖子信息
|
|
|
|
|
+ prefixPostContentKey = "post:content:%d" // 帖子内容
|
|
|
|
|
+ prefixUserLikeKey = "user:like:%d:%d" // 用户点赞状态
|
|
|
|
|
+ prefixUserCollectKey = "user:collect:%d:%d" // 用户收藏状态
|
|
|
|
|
+ prefixPostListKey = "post:list:%d:%d:%d:%s" // 帖子列表 (searchType:sortType:page:keyword)
|
|
|
|
|
+
|
|
|
|
|
+ cacheExpiry = 24 * time.Hour // 缓存过期时间
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// PPost 冒泡/文章
|
|
|
|
|
+type Post struct {
|
|
|
|
|
+ *Model
|
|
|
|
|
+ UserId int64 `json:"user_id" gorm:"user_id"` // 用户ID
|
|
|
|
|
+ PostType int32 `json:"post_type" gorm:"post_type"` // 帖子类型0-普通图文1-视频
|
|
|
|
|
+ CommentCount int64 `json:"comment_count" gorm:"comment_count"` // 评论数
|
|
|
|
|
+ CollectionCount int64 `json:"collection_count" gorm:"collection_count"` // 收藏数
|
|
|
|
|
+ UpvoteCount int64 `json:"upvote_count" gorm:"upvote_count"` // 点赞数
|
|
|
|
|
+ ShareCount int64 `json:"share_count" gorm:"share_count"` // 分享数
|
|
|
|
|
+ Visibility int8 `json:"visibility" gorm:"visibility"` // 可见性: 0私密 1好友可见 2关注可见 4公开
|
|
|
|
|
+ IsTop int8 `json:"is_top" gorm:"is_top"` // 是否置顶
|
|
|
|
|
+ IsEssence int8 `json:"is_essence" gorm:"is_essence"` // 是否精华
|
|
|
|
|
+ LatestRepliedOn int64 `json:"latest_replied_on" gorm:"latest_replied_on"` // 最新回复时间
|
|
|
|
|
+ Tags string `json:"tags" gorm:"tags"` // 标签
|
|
|
|
|
+ Ip string `json:"ip" gorm:"ip"` // IP地址
|
|
|
|
|
+ IpLoc string `json:"ip_loc" gorm:"ip_loc"` // IP城市地址
|
|
|
|
|
+ WithUserIds string `json:"with_user_ids" gorm:"with_user_ids"` // 被艾特的用户
|
|
|
|
|
+ HotNum int64 `json:"hot_num" gorm:"hot_num"` // 热度值
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TableName 表名称
|
|
|
|
|
+func (*Post) TableName() string {
|
|
|
|
|
+ return "p_post"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// PostModel 帖子模型
|
|
|
|
|
+type PostModel struct {
|
|
|
|
|
+ conn *gorm.DB
|
|
|
|
|
+ redis *redis.Client
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func NewPostModel(conn *gorm.DB, rdb *redis.Client) *PostModel {
|
|
|
|
|
+ return &PostModel{
|
|
|
|
|
+ conn: conn,
|
|
|
|
|
+ redis: rdb,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Create 创建帖子
|
|
|
|
|
+func (m *PostModel) Create(ctx context.Context, post *Post) error {
|
|
|
|
|
+ return m.conn.WithContext(ctx).Create(post).Error
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// PostContentModel 帖子内容模型
|
|
|
|
|
+type PostContentModel struct {
|
|
|
|
|
+ conn *gorm.DB
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func NewPostContentModel(conn *gorm.DB) *PostContentModel {
|
|
|
|
|
+ return &PostContentModel{
|
|
|
|
|
+ conn: conn,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Create 创建帖子内容
|
|
|
|
|
+func (m *PostContentModel) Create(ctx context.Context, content *PostContent) error {
|
|
|
|
|
+ return m.conn.WithContext(ctx).Create(content).Error
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// GetPostList 根据条件获取帖子列表
|
|
|
|
|
+func (m *PostModel) GetPostList(ctx context.Context, req *slowwildserver.GetPostListReq) ([]*Post, error) {
|
|
|
|
|
+ // 构建缓存key
|
|
|
|
|
+ cacheKey := fmt.Sprintf(prefixPostListKey, req.SearchType, req.SortType, req.Page, req.Keyword)
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试从缓存获取
|
|
|
|
|
+ var posts []*Post
|
|
|
|
|
+ data, err := m.redis.Get(ctx, cacheKey).Bytes()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ if err := json.Unmarshal(data, &posts); err == nil {
|
|
|
|
|
+ return posts, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var normalPosts []*Post
|
|
|
|
|
+
|
|
|
|
|
+ // 先查询置顶帖子
|
|
|
|
|
+ topQuery := m.conn.WithContext(ctx).Model(&Post{}).Where("is_top = ?", 1)
|
|
|
|
|
+ normalQuery := m.conn.WithContext(ctx).Model(&Post{}).Where("is_top = ?", 0)
|
|
|
|
|
+
|
|
|
|
|
+ // 根据搜索类型构建查询条件
|
|
|
|
|
+ switch req.SearchType {
|
|
|
|
|
+ case 1: // 搜索内容/标题
|
|
|
|
|
+ subQuery := fmt.Sprintf("%%%s%%", req.Keyword)
|
|
|
|
|
+ topQuery = topQuery.Joins("LEFT JOIN p_post_content ON p_post.id = p_post_content.post_id").
|
|
|
|
|
+ Where("p_post_content.content LIKE ? OR p_post_content.title LIKE ?", subQuery, subQuery)
|
|
|
|
|
+ normalQuery = normalQuery.Joins("LEFT JOIN p_post_content ON p_post.id = p_post_content.post_id").
|
|
|
|
|
+ Where("p_post_content.content LIKE ? OR p_post_content.title LIKE ?", subQuery, subQuery)
|
|
|
|
|
+ case 2: // 话题搜索
|
|
|
|
|
+ topQuery = topQuery.Joins("JOIN p_tag_with_post ON p_tag_with_post.post_id = p_post.id").
|
|
|
|
|
+ Where("p_tag_with_post.tag_id = ?", req.Keyword)
|
|
|
|
|
+ normalQuery = normalQuery.Joins("JOIN p_tag_with_post ON p_tag_with_post.post_id = p_post.id").
|
|
|
|
|
+ Where("p_tag_with_post.tag_id = ?", req.Keyword)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 根据排序类型构建排序条件
|
|
|
|
|
+ switch req.SortType {
|
|
|
|
|
+ case 1: // 热度排序
|
|
|
|
|
+ topQuery = topQuery.Order("hot_num DESC")
|
|
|
|
|
+ normalQuery = normalQuery.Order("hot_num DESC")
|
|
|
|
|
+ default: // 默认创建时间排序
|
|
|
|
|
+ topQuery = topQuery.Order("created_on DESC")
|
|
|
|
|
+ normalQuery = normalQuery.Order("created_on DESC")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询置顶帖子
|
|
|
|
|
+ if err := topQuery.Find(&posts).Error; err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询普通帖子
|
|
|
|
|
+ offset := (req.Page - 1) * req.PageSize
|
|
|
|
|
+ limit := int(req.PageSize) - len(posts)
|
|
|
|
|
+ if limit > 0 {
|
|
|
|
|
+ if err := normalQuery.Offset(int(offset)).Limit(limit).Find(&normalPosts).Error; err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ posts = append(posts, normalPosts...)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 缓存查询结果
|
|
|
|
|
+ if data, err := json.Marshal(posts); err == nil {
|
|
|
|
|
+ // 设置较短的过期时间,因为列表数据变化较频繁
|
|
|
|
|
+ m.redis.Set(ctx, cacheKey, data, 5*time.Minute)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return posts, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// GetPostContents 批量获取帖子内容(带缓存)
|
|
|
|
|
+func (m *PostModel) GetPostContents(ctx context.Context, postIds []int64) (map[int64]*PostContent, error) {
|
|
|
|
|
+ contentMap := make(map[int64]*PostContent)
|
|
|
|
|
+ var missedIds []int64
|
|
|
|
|
+
|
|
|
|
|
+ // 先从Redis获取
|
|
|
|
|
+ for _, id := range postIds {
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostContentKey, id)
|
|
|
|
|
+ data, err := m.redis.Get(ctx, key).Bytes()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ var content PostContent
|
|
|
|
|
+ if err := json.Unmarshal(data, &content); err == nil {
|
|
|
|
|
+ contentMap[id] = &content
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ missedIds = append(missedIds, id)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询未命中的内容
|
|
|
|
|
+ if len(missedIds) > 0 {
|
|
|
|
|
+ var contents []*PostContent
|
|
|
|
|
+ err := m.conn.WithContext(ctx).Where("post_id IN ?", missedIds).Find(&contents).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入缓存并添加到结果
|
|
|
|
|
+ for _, content := range contents {
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostContentKey, content.PostId)
|
|
|
|
|
+ if data, err := json.Marshal(content); err == nil {
|
|
|
|
|
+ m.redis.Set(ctx, key, data, cacheExpiry)
|
|
|
|
|
+ }
|
|
|
|
|
+ contentMap[content.PostId] = content
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return contentMap, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IsPostLikedByUser 检查用户是否点赞了帖子(带缓存)
|
|
|
|
|
+func (m *PostModel) IsPostLikedByUser(ctx context.Context, userId, postId int64) (bool, error) {
|
|
|
|
|
+ key := fmt.Sprintf(prefixUserLikeKey, userId, postId)
|
|
|
|
|
+ exists, err := m.redis.Exists(ctx, key).Result()
|
|
|
|
|
+ if err == nil && exists == 1 {
|
|
|
|
|
+ return m.redis.Get(ctx, key).Bool()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var count int64
|
|
|
|
|
+ err = m.conn.WithContext(ctx).
|
|
|
|
|
+ Model(&PostAction{}).
|
|
|
|
|
+ Where("user_id = ? AND post_id = ? and type = 0", userId, postId).
|
|
|
|
|
+ Count(&count).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return false, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ liked := count > 0
|
|
|
|
|
+ m.redis.Set(ctx, key, liked, cacheExpiry)
|
|
|
|
|
+ return liked, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IsPostCollectedByUser 检查用户是否收藏了帖子(带缓存)
|
|
|
|
|
+func (m *PostModel) IsPostCollectedByUser(ctx context.Context, userId, postId int64) (bool, error) {
|
|
|
|
|
+ key := fmt.Sprintf(prefixUserCollectKey, userId, postId)
|
|
|
|
|
+ exists, err := m.redis.Exists(ctx, key).Result()
|
|
|
|
|
+ if err == nil && exists == 1 {
|
|
|
|
|
+ return m.redis.Get(ctx, key).Bool()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var count int64
|
|
|
|
|
+ err = m.conn.WithContext(ctx).
|
|
|
|
|
+ Model(&PostAction{}).
|
|
|
|
|
+ Where("user_id = ? AND post_id = ? and type = 1", userId, postId).
|
|
|
|
|
+ Count(&count).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return false, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ collected := count > 0
|
|
|
|
|
+ m.redis.Set(ctx, key, collected, cacheExpiry)
|
|
|
|
|
+ return collected, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 在需要更新帖子时,清除相关缓存
|
|
|
|
|
+func (m *PostModel) ClearListCache(ctx context.Context) error {
|
|
|
|
|
+ // 使用通配符匹配所有列表缓存
|
|
|
|
|
+ pattern := "post:list:*"
|
|
|
|
|
+ keys, err := m.redis.Keys(ctx, pattern).Result()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if len(keys) > 0 {
|
|
|
|
|
+ return m.redis.Del(ctx, keys...).Err()
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// UpdatePost 更新帖子时清除缓存
|
|
|
|
|
+func (m *PostModel) UpdatePost(ctx context.Context, post *Post) error {
|
|
|
|
|
+ err := m.conn.WithContext(ctx).Save(post).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 清除帖子相关的所有缓存
|
|
|
|
|
+ m.redis.Del(ctx, fmt.Sprintf(prefixPostKey, post.ID))
|
|
|
|
|
+ m.ClearListCache(ctx)
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// GetPostDetail 获取帖子详情(带缓存)
|
|
|
|
|
+func (m *PostModel) GetPostDetail(ctx context.Context, postId int64) (*Post, error) {
|
|
|
|
|
+ // 尝试从缓存获取
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostKey, postId)
|
|
|
|
|
+ data, err := m.redis.Get(ctx, key).Bytes()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ var post Post
|
|
|
|
|
+ if err := json.Unmarshal(data, &post); err == nil {
|
|
|
|
|
+ return &post, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库获取
|
|
|
|
|
+ var post Post
|
|
|
|
|
+ err = m.conn.WithContext(ctx).First(&post, postId).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入缓存
|
|
|
|
|
+ if data, err := json.Marshal(post); err == nil {
|
|
|
|
|
+ m.redis.Set(ctx, key, data, cacheExpiry)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return &post, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// GetPostContent 获取帖子内容(带缓存)
|
|
|
|
|
+func (m *PostModel) GetPostContent(ctx context.Context, postId int64) (*PostContent, error) {
|
|
|
|
|
+ // 尝试从缓存获取
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostContentKey, postId)
|
|
|
|
|
+ data, err := m.redis.Get(ctx, key).Bytes()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ var content PostContent
|
|
|
|
|
+ if err := json.Unmarshal(data, &content); err == nil {
|
|
|
|
|
+ return &content, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库获取
|
|
|
|
|
+ var content PostContent
|
|
|
|
|
+ err = m.conn.WithContext(ctx).Where("post_id = ?", postId).First(&content).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入缓存
|
|
|
|
|
+ if data, err := json.Marshal(content); err == nil {
|
|
|
|
|
+ m.redis.Set(ctx, key, data, cacheExpiry)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return &content, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IncrementCollectionCount 增加收藏数
|
|
|
|
|
+func (m *PostModel) IncrementCollectionCount(ctx context.Context, postId int64, increment int) error {
|
|
|
|
|
+ err := m.conn.WithContext(ctx).Model(&Post{}).
|
|
|
|
|
+ Where("id = ?", postId).
|
|
|
|
|
+ UpdateColumn("collection_count", gorm.Expr("collection_count + ?", increment)).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除相关缓存
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostKey, postId)
|
|
|
|
|
+ m.redis.Del(ctx, key)
|
|
|
|
|
+ m.ClearListCache(ctx)
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IncrementCommentCount 增加评论数
|
|
|
|
|
+func (m *PostModel) IncrementCommentCount(ctx context.Context, postId int64, increment int) error {
|
|
|
|
|
+ err := m.conn.WithContext(ctx).Model(&Post{}).
|
|
|
|
|
+ Where("id = ?", postId).
|
|
|
|
|
+ UpdateColumn("comment_count", gorm.Expr("comment_count + ?", increment)).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除相关缓存
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostKey, postId)
|
|
|
|
|
+ m.redis.Del(ctx, key)
|
|
|
|
|
+ m.ClearListCache(ctx)
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IncrementShareCount 增加分享数
|
|
|
|
|
+func (m *PostModel) IncrementShareCount(ctx context.Context, postId int64) error {
|
|
|
|
|
+ err := m.conn.WithContext(ctx).Model(&Post{}).
|
|
|
|
|
+ Where("id = ?", postId).
|
|
|
|
|
+ UpdateColumn("share_count", gorm.Expr("share_count + ?", 1)).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除相关缓存
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostKey, postId)
|
|
|
|
|
+ m.redis.Del(ctx, key)
|
|
|
|
|
+ m.ClearListCache(ctx)
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Delete 删除帖子
|
|
|
|
|
+func (m *PostModel) Delete(ctx context.Context, postId int64) error {
|
|
|
|
|
+ return m.conn.WithContext(ctx).Model(&Post{}).
|
|
|
|
|
+ Where("id = ?", postId).
|
|
|
|
|
+ Update("is_del", 1).Error
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ClearCache 清除帖子相关的所有缓存
|
|
|
|
|
+func (m *PostModel) ClearCache(ctx context.Context, postId int64) {
|
|
|
|
|
+ // 删除帖子详情缓存
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostKey, postId)
|
|
|
|
|
+ m.redis.Del(ctx, key)
|
|
|
|
|
+
|
|
|
|
|
+ // 删除帖子内容缓存
|
|
|
|
|
+ key = fmt.Sprintf(prefixPostContentKey, postId)
|
|
|
|
|
+ m.redis.Del(ctx, key)
|
|
|
|
|
+
|
|
|
|
|
+ // 删除帖子列表缓存
|
|
|
|
|
+ m.ClearListCache(ctx)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// IncrementUpvoteCount 增加点赞数
|
|
|
|
|
+func (m *PostModel) IncrementUpvoteCount(ctx context.Context, postId int64, increment int) error {
|
|
|
|
|
+ err := m.conn.WithContext(ctx).Model(&Post{}).
|
|
|
|
|
+ Where("id = ?", postId).
|
|
|
|
|
+ UpdateColumn("upvote_count", gorm.Expr("upvote_count + ?", increment)).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除相关缓存
|
|
|
|
|
+ key := fmt.Sprintf(prefixPostKey, postId)
|
|
|
|
|
+ m.redis.Del(ctx, key)
|
|
|
|
|
+ m.ClearListCache(ctx)
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// GetUserCollectionPosts 获取用户收藏的帖子列表(带缓存)
|
|
|
|
|
+func (m *PostModel) GetUserCollectionPosts(ctx context.Context, userId int64, page, pageSize int) ([]*Post, int64, error) {
|
|
|
|
|
+ // 尝试从缓存获取
|
|
|
|
|
+ key := fmt.Sprintf("user:collection:%d:%d:%d", userId, page, pageSize)
|
|
|
|
|
+ data, err := m.redis.Get(ctx, key).Bytes()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ var cacheData struct {
|
|
|
|
|
+ Posts []*Post
|
|
|
|
|
+ Total int64
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(data, &cacheData); err == nil {
|
|
|
|
|
+ return cacheData.Posts, cacheData.Total, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库获取
|
|
|
|
|
+ var posts []*Post
|
|
|
|
|
+ var total int64
|
|
|
|
|
+
|
|
|
|
|
+ // 获取收藏总数
|
|
|
|
|
+ err = m.conn.Model(&PostAction{}).
|
|
|
|
|
+ Where("user_id = ? AND action_type = ? AND is_del = 0", userId, 1). // 1表示收藏动作
|
|
|
|
|
+ Count(&total).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取收藏的帖子列表
|
|
|
|
|
+ offset := (page - 1) * pageSize
|
|
|
|
|
+ err = m.conn.Table("p_post_action pa").
|
|
|
|
|
+ Select("p.*").
|
|
|
|
|
+ Joins("LEFT JOIN p_post p ON p.id = pa.post_id").
|
|
|
|
|
+ Where("pa.user_id = ? AND pa.action_type = ? AND pa.is_del = 0 AND p.is_del = 0", userId, 1).
|
|
|
|
|
+ Order("pa.created_on DESC").
|
|
|
|
|
+ Offset(offset).
|
|
|
|
|
+ Limit(pageSize).
|
|
|
|
|
+ Find(&posts).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入缓存
|
|
|
|
|
+ cacheData := struct {
|
|
|
|
|
+ Posts []*Post
|
|
|
|
|
+ Total int64
|
|
|
|
|
+ }{
|
|
|
|
|
+ Posts: posts,
|
|
|
|
|
+ Total: total,
|
|
|
|
|
+ }
|
|
|
|
|
+ if data, err := json.Marshal(cacheData); err == nil {
|
|
|
|
|
+ m.redis.Set(ctx, key, data, 5*time.Minute)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return posts, total, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// GetUserLikePosts 获取用户点赞的帖子列表(带缓存)
|
|
|
|
|
+func (m *PostModel) GetUserLikePosts(ctx context.Context, userId int64, page, pageSize int) ([]*Post, int64, error) {
|
|
|
|
|
+ // 尝试从缓存获取
|
|
|
|
|
+ key := fmt.Sprintf("user:like:%d:%d:%d", userId, page, pageSize)
|
|
|
|
|
+ data, err := m.redis.Get(ctx, key).Bytes()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ var cacheData struct {
|
|
|
|
|
+ Posts []*Post
|
|
|
|
|
+ Total int64
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(data, &cacheData); err == nil {
|
|
|
|
|
+ return cacheData.Posts, cacheData.Total, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库获取
|
|
|
|
|
+ var posts []*Post
|
|
|
|
|
+ var total int64
|
|
|
|
|
+
|
|
|
|
|
+ // 获取点赞总数
|
|
|
|
|
+ err = m.conn.Model(&PostAction{}).
|
|
|
|
|
+ Where("user_id = ? AND action_type = ? AND is_del = 0", userId, 0). // 0表示点赞动作
|
|
|
|
|
+ Count(&total).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取点赞的帖子列表
|
|
|
|
|
+ offset := (page - 1) * pageSize
|
|
|
|
|
+ err = m.conn.Table("p_post_action pa").
|
|
|
|
|
+ Select("p.*").
|
|
|
|
|
+ Joins("LEFT JOIN p_post p ON p.id = pa.post_id").
|
|
|
|
|
+ Where("pa.user_id = ? AND pa.action_type = ? AND pa.is_del = 0 AND p.is_del = 0", userId, 0).
|
|
|
|
|
+ Order("pa.created_on DESC").
|
|
|
|
|
+ Offset(offset).
|
|
|
|
|
+ Limit(pageSize).
|
|
|
|
|
+ Find(&posts).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入缓存
|
|
|
|
|
+ cacheData := struct {
|
|
|
|
|
+ Posts []*Post
|
|
|
|
|
+ Total int64
|
|
|
|
|
+ }{
|
|
|
|
|
+ Posts: posts,
|
|
|
|
|
+ Total: total,
|
|
|
|
|
+ }
|
|
|
|
|
+ if data, err := json.Marshal(cacheData); err == nil {
|
|
|
|
|
+ m.redis.Set(ctx, key, data, 5*time.Minute)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return posts, total, nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// GetUserPosts 获取用户发布的帖子列表(带缓存)
|
|
|
|
|
+func (m *PostModel) GetUserPosts(ctx context.Context, userId int64, page, pageSize int) ([]*Post, int64, error) {
|
|
|
|
|
+ // 尝试从缓存获取
|
|
|
|
|
+ key := fmt.Sprintf("user:posts:%d:%d:%d", userId, page, pageSize)
|
|
|
|
|
+ data, err := m.redis.Get(ctx, key).Bytes()
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ var cacheData struct {
|
|
|
|
|
+ Posts []*Post
|
|
|
|
|
+ Total int64
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(data, &cacheData); err == nil {
|
|
|
|
|
+ return cacheData.Posts, cacheData.Total, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库获取
|
|
|
|
|
+ var posts []*Post
|
|
|
|
|
+ var total int64
|
|
|
|
|
+
|
|
|
|
|
+ // 获取发布帖子总数
|
|
|
|
|
+ err = m.conn.Model(&Post{}).
|
|
|
|
|
+ Where("user_id = ? AND is_del = 0", userId).
|
|
|
|
|
+ Count(&total).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取发布的帖子列表
|
|
|
|
|
+ offset := (page - 1) * pageSize
|
|
|
|
|
+ err = m.conn.Where("user_id = ? AND is_del = 0", userId).
|
|
|
|
|
+ Order("created_on DESC").
|
|
|
|
|
+ Offset(offset).
|
|
|
|
|
+ Limit(pageSize).
|
|
|
|
|
+ Find(&posts).Error
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, 0, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入缓存
|
|
|
|
|
+ cacheData := struct {
|
|
|
|
|
+ Posts []*Post
|
|
|
|
|
+ Total int64
|
|
|
|
|
+ }{
|
|
|
|
|
+ Posts: posts,
|
|
|
|
|
+ Total: total,
|
|
|
|
|
+ }
|
|
|
|
|
+ if data, err := json.Marshal(cacheData); err == nil {
|
|
|
|
|
+ m.redis.Set(ctx, key, data, 5*time.Minute)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return posts, total, nil
|
|
|
|
|
+}
|