From 5031df86f466eba2798585868837fa4e991f62bf Mon Sep 17 00:00:00 2001 From: Rogee Date: Mon, 12 Jan 2026 09:55:11 +0800 Subject: [PATCH] fix: block interactions on unpublished content --- backend/app/services/content.go | 83 +++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/backend/app/services/content.go b/backend/app/services/content.go index f7f57eb..d97746d 100644 --- a/backend/app/services/content.go +++ b/backend/app/services/content.go @@ -157,21 +157,8 @@ func (s *content) Get(ctx context.Context, tenantID, userID, id int64) (*content return nil, errorx.ErrDatabaseError.WithCause(err) } - // 未发布内容仅允许作者或租户管理员查看。 - if item.Status != consts.ContentStatusPublished { - if userID == 0 { - return nil, errorx.ErrForbidden.WithMsg("内容未发布") - } - if item.UserID != userID { - exists, _ := models.TenantUserQuery.WithContext(ctx). - Where(models.TenantUserQuery.TenantID.Eq(item.TenantID), - models.TenantUserQuery.UserID.Eq(userID), - models.TenantUserQuery.Role.Contains(types.Array[consts.TenantUserRole]{consts.TenantUserRoleTenantAdmin})). - Exists() - if !exists { - return nil, errorx.ErrForbidden.WithMsg("内容未发布") - } - } + if err := s.ensureContentReadable(ctx, userID, &item); err != nil { + return nil, err } // Increment Views @@ -263,16 +250,19 @@ func (s *content) Get(ctx context.Context, tenantID, userID, id int64) (*content } func (s *content) ListComments(ctx context.Context, tenantID, userID, id int64, page int) (*requests.Pager, error) { + contentQuery := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(id)) if tenantID > 0 { - _, err := models.ContentQuery.WithContext(ctx). - Where(models.ContentQuery.ID.Eq(id), models.ContentQuery.TenantID.Eq(tenantID)). - First() - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errorx.ErrRecordNotFound - } - return nil, errorx.ErrDatabaseError.WithCause(err) + contentQuery = contentQuery.Where(models.ContentQuery.TenantID.Eq(tenantID)) + } + content, err := contentQuery.First() + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, errorx.ErrRecordNotFound } + return nil, errorx.ErrDatabaseError.WithCause(err) + } + if err := s.ensureContentReadable(ctx, userID, content); err != nil { + return nil, err } tbl, q := models.CommentQuery.QueryContext(ctx) @@ -354,6 +344,9 @@ func (s *content) CreateComment( if err != nil { return errorx.ErrRecordNotFound } + if err := s.ensureContentReadable(ctx, userID, c); err != nil { + return err + } comment := &models.Comment{ TenantID: c.TenantID, @@ -384,6 +377,20 @@ func (s *content) LikeComment(ctx context.Context, tenantID, userID, id int64) e if err != nil { return errorx.ErrRecordNotFound } + contentQuery := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(cm.ContentID)) + if tenantID > 0 { + contentQuery = contentQuery.Where(models.ContentQuery.TenantID.Eq(tenantID)) + } + c, err := contentQuery.First() + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return errorx.ErrRecordNotFound + } + return errorx.ErrDatabaseError.WithCause(err) + } + if err := s.ensureContentReadable(ctx, userID, c); err != nil { + return err + } err = models.Q.Transaction(func(tx *models.Query) error { exists, _ := tx.UserCommentAction.WithContext(ctx). @@ -610,6 +617,31 @@ func (s *content) toContentItemDTO(item *models.Content, price float64, authorIs return dto } +func (s *content) ensureContentReadable(ctx context.Context, userID int64, item *models.Content) error { + if item.Status == consts.ContentStatusPublished { + return nil + } + // 未发布内容仅允许作者或租户管理员查看。 + if userID == 0 { + return errorx.ErrForbidden.WithMsg("内容未发布") + } + if item.UserID == userID { + return nil + } + exists, err := models.TenantUserQuery.WithContext(ctx). + Where(models.TenantUserQuery.TenantID.Eq(item.TenantID), + models.TenantUserQuery.UserID.Eq(userID), + models.TenantUserQuery.Role.Contains(types.Array[consts.TenantUserRole]{consts.TenantUserRoleTenantAdmin})). + Exists() + if err != nil { + return errorx.ErrDatabaseError.WithCause(err) + } + if !exists { + return errorx.ErrForbidden.WithMsg("内容未发布") + } + return nil +} + func (s *content) toMediaURLs(assets []*models.ContentAsset) []content_dto.MediaURL { var urls []content_dto.MediaURL for _, ca := range assets { @@ -637,11 +669,14 @@ func (s *content) addInteract(ctx context.Context, tenantID, userID, contentId i query = query.Where(models.ContentQuery.TenantID.Eq(tenantID)) } c, err := query. - Select(models.ContentQuery.UserID, models.ContentQuery.Title). + Select(models.ContentQuery.UserID, models.ContentQuery.Title, models.ContentQuery.Status, models.ContentQuery.TenantID). First() if err != nil { return errorx.ErrRecordNotFound } + if err := s.ensureContentReadable(ctx, userID, c); err != nil { + return err + } err = models.Q.Transaction(func(tx *models.Query) error { exists, _ := tx.UserContentAction.WithContext(ctx).