Replace websocket flow with SSE support in backend.

Update handlers, services, router, and data conversion logic to support server-sent events and related message pipeline changes.

Made-with: Cursor
This commit is contained in:
2026-03-10 12:58:23 +08:00
parent 4c0177149a
commit 86ef150fec
19 changed files with 689 additions and 1719 deletions

View File

@@ -2,6 +2,7 @@ package repository
import (
"carrot_bbs/internal/model"
"time"
"gorm.io/gorm"
)
@@ -52,9 +53,41 @@ func (r *PostRepository) GetByID(id string) (*model.Post, error) {
// Update 更新帖子
func (r *PostRepository) Update(post *model.Post) error {
post.UpdatedAt = time.Now()
return r.db.Save(post).Error
}
// UpdateWithImages 更新帖子及其图片images=nil 表示不更新图片)
func (r *PostRepository) UpdateWithImages(post *model.Post, images *[]string) error {
return r.db.Transaction(func(tx *gorm.DB) error {
post.UpdatedAt = time.Now()
if err := tx.Save(post).Error; err != nil {
return err
}
if images == nil {
return nil
}
if err := tx.Where("post_id = ?", post.ID).Delete(&model.PostImage{}).Error; err != nil {
return err
}
for i, url := range *images {
image := &model.PostImage{
PostID: post.ID,
URL: url,
SortOrder: i,
}
if err := tx.Create(image).Error; err != nil {
return err
}
}
return nil
})
}
// UpdateModerationStatus 更新帖子审核状态
func (r *PostRepository) UpdateModerationStatus(postID string, status model.PostStatus, rejectReason string, reviewedBy string) error {
updates := map[string]interface{}{
@@ -100,15 +133,24 @@ func (r *PostRepository) Delete(id string) error {
}
// List 分页获取帖子列表
func (r *PostRepository) List(page, pageSize int, userID string) ([]*model.Post, int64, error) {
// includePending=true 时,仅在指定 userID 下额外返回 pending用于作者查看自己待审核帖子
func (r *PostRepository) List(page, pageSize int, userID string, includePending bool) ([]*model.Post, int64, error) {
var posts []*model.Post
var total int64
query := r.db.Model(&model.Post{}).Where("status = ?", model.PostStatusPublished)
query := r.db.Model(&model.Post{})
if userID != "" {
query = query.Where("user_id = ?", userID)
}
if includePending && userID != "" {
query = query.Where("status IN ?", []model.PostStatus{
model.PostStatusPublished,
model.PostStatusPending,
})
} else {
query = query.Where("status = ?", model.PostStatusPublished)
}
query.Count(&total)
@@ -119,14 +161,32 @@ func (r *PostRepository) List(page, pageSize int, userID string) ([]*model.Post,
}
// GetUserPosts 获取用户帖子
func (r *PostRepository) GetUserPosts(userID string, page, pageSize int) ([]*model.Post, int64, error) {
func (r *PostRepository) GetUserPosts(userID string, page, pageSize int, includePending bool) ([]*model.Post, int64, error) {
var posts []*model.Post
var total int64
r.db.Model(&model.Post{}).Where("user_id = ? AND status = ?", userID, model.PostStatusPublished).Count(&total)
statusQuery := r.db.Model(&model.Post{}).Where("user_id = ?", userID)
if includePending {
statusQuery = statusQuery.Where("status IN ?", []model.PostStatus{
model.PostStatusPublished,
model.PostStatusPending,
})
} else {
statusQuery = statusQuery.Where("status = ?", model.PostStatusPublished)
}
statusQuery.Count(&total)
offset := (page - 1) * pageSize
err := r.db.Where("user_id = ? AND status = ?", userID, model.PostStatusPublished).Preload("User").Preload("Images").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&posts).Error
listQuery := r.db.Where("user_id = ?", userID)
if includePending {
listQuery = listQuery.Where("status IN ?", []model.PostStatus{
model.PostStatusPublished,
model.PostStatusPending,
})
} else {
listQuery = listQuery.Where("status = ?", model.PostStatusPublished)
}
err := listQuery.Preload("User").Preload("Images").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&posts).Error
return posts, total, err
}
@@ -256,7 +316,8 @@ func (r *PostRepository) IsFavorited(postID, userID string) bool {
// IncrementViews 增加帖子观看量
func (r *PostRepository) IncrementViews(postID string) error {
return r.db.Model(&model.Post{}).Where("id = ?", postID).
Updates(map[string]interface{}{
// 浏览量属于统计字段不应影响帖子内容更新时间updated_at
UpdateColumns(map[string]interface{}{
"views_count": gorm.Expr("views_count + 1"),
"hot_score": gorm.Expr("likes_count * 2 + comments_count * 3 + (views_count + 1) * 0.1"),
}).Error