feat(channel): integrate channel functionality into post management
All checks were successful
Build Backend / build (push) Successful in 19m14s
Build Backend / build-docker (push) Successful in 1m28s

- Added Channel support in Post model, including ChannelID field in PostRequest and PostResponse DTOs.
- Updated PostService and PostRepository to handle channel-specific logic for creating and listing posts.
- Introduced ChannelRepository and ChannelService, along with corresponding handlers for managing channels.
- Enhanced router to include routes for channel management and public channel listing.
- Seeded default channels in the database during initialization.
This commit is contained in:
lafay
2026-03-24 22:27:53 +08:00
parent 15f0f1605e
commit fc0d6ff19d
19 changed files with 416 additions and 42 deletions

View File

@@ -25,22 +25,22 @@ const (
// PostService 帖子服务接口
type PostService interface {
// 帖子CRUD
Create(ctx context.Context, userID, title, content string, images []string) (*model.Post, error)
Create(ctx context.Context, userID, title, content string, images []string, channelID *string) (*model.Post, error)
GetByID(ctx context.Context, id string) (*model.Post, error)
Update(ctx context.Context, post *model.Post) error
UpdateWithImages(ctx context.Context, post *model.Post, images *[]string) error
Delete(ctx context.Context, id string) error
// 帖子列表
List(ctx context.Context, page, pageSize int, userID string, includePending bool) ([]*model.Post, int64, error)
GetLatestPosts(ctx context.Context, page, pageSize int, userID string) ([]*model.Post, int64, error)
GetLatestPostsForOwner(ctx context.Context, page, pageSize int, userID string) ([]*model.Post, int64, error)
List(ctx context.Context, page, pageSize int, userID string, includePending bool, channelID *string) ([]*model.Post, int64, error)
GetLatestPosts(ctx context.Context, page, pageSize int, userID string, channelID *string) ([]*model.Post, int64, error)
GetLatestPostsForOwner(ctx context.Context, page, pageSize int, userID string, channelID *string) ([]*model.Post, int64, error)
GetUserPosts(ctx context.Context, userID string, page, pageSize int, includePending bool) ([]*model.Post, int64, error)
GetFavorites(ctx context.Context, userID string, page, pageSize int) ([]*model.Post, int64, error)
Search(ctx context.Context, keyword string, page, pageSize int) ([]*model.Post, int64, error)
// 游标分页方法
ListByCursor(ctx context.Context, userID string, includePending bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Post], error)
ListByCursor(ctx context.Context, userID string, includePending bool, channelID *string, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Post], error)
SearchByCursor(ctx context.Context, keyword string, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Post], error)
GetUserPostsByCursor(ctx context.Context, userID string, includePending bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Post], error)
GetFollowingPostsByCursor(ctx context.Context, userID string, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Post], error)
@@ -106,12 +106,13 @@ type PostListResult struct {
}
// Create 创建帖子
func (s *postServiceImpl) Create(ctx context.Context, userID, title, content string, images []string) (*model.Post, error) {
func (s *postServiceImpl) Create(ctx context.Context, userID, title, content string, images []string, channelID *string) (*model.Post, error) {
post := &model.Post{
UserID: userID,
Title: title,
Content: content,
Status: model.PostStatusPending,
UserID: userID,
ChannelID: channelID,
Title: title,
Content: content,
Status: model.PostStatusPending,
}
err := s.postRepo.Create(post, images)
@@ -288,7 +289,7 @@ func (s *postServiceImpl) Delete(ctx context.Context, id string) error {
}
// List 获取帖子列表(带缓存)
func (s *postServiceImpl) List(ctx context.Context, page, pageSize int, userID string, includePending bool) ([]*model.Post, int64, error) {
func (s *postServiceImpl) List(ctx context.Context, page, pageSize int, userID string, includePending bool, channelID *string) ([]*model.Post, int64, error) {
cacheSettings := cache.GetSettings()
postListTTL := cacheSettings.PostListTTL
if postListTTL <= 0 {
@@ -308,6 +309,9 @@ func (s *postServiceImpl) List(ctx context.Context, page, pageSize int, userID s
if includePending && userID != "" {
visibilityUserKey = "owner:" + userID
}
if channelID != nil && *channelID != "" {
visibilityUserKey += ":channel:" + *channelID
}
cacheKey := cache.PostListKey("latest", visibilityUserKey, page, pageSize)
result, err := cache.GetOrLoadTyped(
@@ -317,7 +321,7 @@ func (s *postServiceImpl) List(ctx context.Context, page, pageSize int, userID s
jitter,
nullTTL,
func() (*PostListResult, error) {
posts, total, err := s.postRepo.List(page, pageSize, userID, includePending)
posts, total, err := s.postRepo.List(page, pageSize, userID, includePending, channelID)
if err != nil {
return nil, err
}
@@ -341,7 +345,7 @@ func (s *postServiceImpl) List(ctx context.Context, page, pageSize int, userID s
}
}
if missingAuthor {
posts, total, loadErr := s.postRepo.List(page, pageSize, userID, includePending)
posts, total, loadErr := s.postRepo.List(page, pageSize, userID, includePending, channelID)
if loadErr != nil {
return nil, 0, loadErr
}
@@ -353,13 +357,13 @@ func (s *postServiceImpl) List(ctx context.Context, page, pageSize int, userID s
}
// GetLatestPosts 获取最新帖子(语义化别名)
func (s *postServiceImpl) GetLatestPosts(ctx context.Context, page, pageSize int, userID string) ([]*model.Post, int64, error) {
return s.List(ctx, page, pageSize, userID, false)
func (s *postServiceImpl) GetLatestPosts(ctx context.Context, page, pageSize int, userID string, channelID *string) ([]*model.Post, int64, error) {
return s.List(ctx, page, pageSize, userID, false, channelID)
}
// GetLatestPostsForOwner 获取作者视角帖子列表(包含待审核)
func (s *postServiceImpl) GetLatestPostsForOwner(ctx context.Context, page, pageSize int, userID string) ([]*model.Post, int64, error) {
return s.List(ctx, page, pageSize, userID, true)
func (s *postServiceImpl) GetLatestPostsForOwner(ctx context.Context, page, pageSize int, userID string, channelID *string) ([]*model.Post, int64, error) {
return s.List(ctx, page, pageSize, userID, true, channelID)
}
// GetUserPosts 获取用户帖子
@@ -647,11 +651,11 @@ func (s *postServiceImpl) DeletePostWithTransaction(ctx context.Context, postID
// ========== 游标分页方法 ==========
// ListByCursor 游标分页获取帖子列表
func (s *postServiceImpl) ListByCursor(ctx context.Context, userID string, includePending bool, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Post], error) {
func (s *postServiceImpl) ListByCursor(ctx context.Context, userID string, includePending bool, channelID *string, req *cursor.PageRequest) (*cursor.CursorPageResult[*model.Post], error) {
// 规范化请求参数
req.Normalize()
return s.postRepo.GetPostsByCursor(ctx, userID, includePending, req)
return s.postRepo.GetPostsByCursor(ctx, userID, includePending, channelID, req)
}
// SearchByCursor 游标分页搜索帖子