fix: block interactions on unpublished content

This commit is contained in:
2026-01-12 09:55:11 +08:00
parent 810c5a52a5
commit 5031df86f4

View File

@@ -157,21 +157,8 @@ func (s *content) Get(ctx context.Context, tenantID, userID, id int64) (*content
return nil, errorx.ErrDatabaseError.WithCause(err) return nil, errorx.ErrDatabaseError.WithCause(err)
} }
// 未发布内容仅允许作者或租户管理员查看。 if err := s.ensureContentReadable(ctx, userID, &item); err != nil {
if item.Status != consts.ContentStatusPublished { return nil, err
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("内容未发布")
}
}
} }
// Increment Views // 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) { 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 { if tenantID > 0 {
_, err := models.ContentQuery.WithContext(ctx). contentQuery = contentQuery.Where(models.ContentQuery.TenantID.Eq(tenantID))
Where(models.ContentQuery.ID.Eq(id), models.ContentQuery.TenantID.Eq(tenantID)). }
First() content, err := contentQuery.First()
if err != nil { if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) { if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errorx.ErrRecordNotFound return nil, errorx.ErrRecordNotFound
}
return nil, errorx.ErrDatabaseError.WithCause(err)
} }
return nil, errorx.ErrDatabaseError.WithCause(err)
}
if err := s.ensureContentReadable(ctx, userID, content); err != nil {
return nil, err
} }
tbl, q := models.CommentQuery.QueryContext(ctx) tbl, q := models.CommentQuery.QueryContext(ctx)
@@ -354,6 +344,9 @@ func (s *content) CreateComment(
if err != nil { if err != nil {
return errorx.ErrRecordNotFound return errorx.ErrRecordNotFound
} }
if err := s.ensureContentReadable(ctx, userID, c); err != nil {
return err
}
comment := &models.Comment{ comment := &models.Comment{
TenantID: c.TenantID, TenantID: c.TenantID,
@@ -384,6 +377,20 @@ func (s *content) LikeComment(ctx context.Context, tenantID, userID, id int64) e
if err != nil { if err != nil {
return errorx.ErrRecordNotFound 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 { err = models.Q.Transaction(func(tx *models.Query) error {
exists, _ := tx.UserCommentAction.WithContext(ctx). exists, _ := tx.UserCommentAction.WithContext(ctx).
@@ -610,6 +617,31 @@ func (s *content) toContentItemDTO(item *models.Content, price float64, authorIs
return dto 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 { func (s *content) toMediaURLs(assets []*models.ContentAsset) []content_dto.MediaURL {
var urls []content_dto.MediaURL var urls []content_dto.MediaURL
for _, ca := range assets { 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)) query = query.Where(models.ContentQuery.TenantID.Eq(tenantID))
} }
c, err := query. c, err := query.
Select(models.ContentQuery.UserID, models.ContentQuery.Title). Select(models.ContentQuery.UserID, models.ContentQuery.Title, models.ContentQuery.Status, models.ContentQuery.TenantID).
First() First()
if err != nil { if err != nil {
return errorx.ErrRecordNotFound return errorx.ErrRecordNotFound
} }
if err := s.ensureContentReadable(ctx, userID, c); err != nil {
return err
}
err = models.Q.Transaction(func(tx *models.Query) error { err = models.Q.Transaction(func(tx *models.Query) error {
exists, _ := tx.UserContentAction.WithContext(ctx). exists, _ := tx.UserContentAction.WithContext(ctx).