fix: enforce content visibility and tenant login
This commit is contained in:
@@ -31,6 +31,8 @@ func (s *content) List(ctx context.Context, tenantID int64, filter *content_dto.
|
||||
if tenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(tenantID))
|
||||
}
|
||||
// 私密内容不参与公开列表展示。
|
||||
q = q.Where(tbl.Visibility.Neq(consts.ContentVisibilityPrivate))
|
||||
if filter.AuthorID != nil && *filter.AuthorID > 0 {
|
||||
q = q.Where(tbl.UserID.Eq(*filter.AuthorID))
|
||||
}
|
||||
@@ -622,28 +624,99 @@ func (s *content) toContentItemDTO(item *models.Content, price float64, authorIs
|
||||
}
|
||||
|
||||
func (s *content) ensureContentReadable(ctx context.Context, userID int64, item *models.Content) error {
|
||||
if item.Status == consts.ContentStatusPublished {
|
||||
if item.Status != consts.ContentStatusPublished {
|
||||
// 未发布内容仅允许作者或租户管理员查看。
|
||||
return s.ensureContentOwnerOrAdmin(ctx, userID, item, "内容未发布")
|
||||
}
|
||||
|
||||
switch item.Visibility {
|
||||
case consts.ContentVisibilityPublic, "":
|
||||
return nil
|
||||
case consts.ContentVisibilityPrivate:
|
||||
// 私密内容仅允许作者或租户管理员查看。
|
||||
return s.ensureContentOwnerOrAdmin(ctx, userID, item, "内容不可见")
|
||||
case consts.ContentVisibilityTenantOnly:
|
||||
// 店铺内可见内容需要登录并满足成员/购买条件。
|
||||
if userID == 0 {
|
||||
return errorx.ErrForbidden.WithMsg("内容仅限本店铺成员访问")
|
||||
}
|
||||
if item.UserID == userID {
|
||||
return nil
|
||||
}
|
||||
isAdmin, err := s.isTenantAdmin(ctx, item.TenantID, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isAdmin {
|
||||
return nil
|
||||
}
|
||||
// 已购买用户允许访问。
|
||||
hasAccess, err := models.ContentAccessQuery.WithContext(ctx).
|
||||
Where(models.ContentAccessQuery.UserID.Eq(userID),
|
||||
models.ContentAccessQuery.ContentID.Eq(item.ID),
|
||||
models.ContentAccessQuery.Status.Eq(consts.ContentAccessStatusActive)).
|
||||
Exists()
|
||||
if err != nil {
|
||||
return errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if hasAccess {
|
||||
return nil
|
||||
}
|
||||
isMember, err := s.isTenantMember(ctx, item.TenantID, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isMember {
|
||||
return errorx.ErrForbidden.WithMsg("内容仅限本店铺成员访问")
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
// 未发布内容仅允许作者或租户管理员查看。
|
||||
}
|
||||
|
||||
func (s *content) ensureContentOwnerOrAdmin(ctx context.Context, userID int64, item *models.Content, msg string) error {
|
||||
if userID == 0 {
|
||||
return errorx.ErrForbidden.WithMsg("内容未发布")
|
||||
return errorx.ErrForbidden.WithMsg(msg)
|
||||
}
|
||||
if item.UserID == userID {
|
||||
return nil
|
||||
}
|
||||
isAdmin, err := s.isTenantAdmin(ctx, item.TenantID, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isAdmin {
|
||||
return errorx.ErrForbidden.WithMsg(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *content) isTenantAdmin(ctx context.Context, tenantID, userID int64) (bool, error) {
|
||||
if tenantID == 0 || userID == 0 {
|
||||
return false, nil
|
||||
}
|
||||
exists, err := models.TenantUserQuery.WithContext(ctx).
|
||||
Where(models.TenantUserQuery.TenantID.Eq(item.TenantID),
|
||||
Where(models.TenantUserQuery.TenantID.Eq(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)
|
||||
return false, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
if !exists {
|
||||
return errorx.ErrForbidden.WithMsg("内容未发布")
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (s *content) isTenantMember(ctx context.Context, tenantID, userID int64) (bool, error) {
|
||||
if tenantID == 0 || userID == 0 {
|
||||
return false, nil
|
||||
}
|
||||
return nil
|
||||
tbl, q := models.TenantUserQuery.QueryContext(ctx)
|
||||
exists, err := q.Where(tbl.TenantID.Eq(tenantID), tbl.UserID.Eq(userID), tbl.Status.Eq(consts.UserStatusVerified)).Exists()
|
||||
if err != nil {
|
||||
return false, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (s *content) toMediaURLs(assets []*models.ContentAsset) []content_dto.MediaURL {
|
||||
|
||||
Reference in New Issue
Block a user