feat: tenant-scoped routing and portal navigation
This commit is contained in:
@@ -18,11 +18,14 @@ import (
|
||||
// @provider
|
||||
type content struct{}
|
||||
|
||||
func (s *content) List(ctx context.Context, filter *content_dto.ContentListFilter) (*requests.Pager, error) {
|
||||
func (s *content) List(ctx context.Context, tenantID int64, filter *content_dto.ContentListFilter) (*requests.Pager, error) {
|
||||
tbl, q := models.ContentQuery.QueryContext(ctx)
|
||||
|
||||
// Filters
|
||||
q = q.Where(tbl.Status.Eq(consts.ContentStatusPublished))
|
||||
if tenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(tenantID))
|
||||
}
|
||||
if filter.Keyword != nil && *filter.Keyword != "" {
|
||||
keyword := "%" + *filter.Keyword + "%"
|
||||
q = q.Where(tbl.Title.Like(keyword)).Or(tbl.Description.Like(keyword))
|
||||
@@ -31,6 +34,9 @@ func (s *content) List(ctx context.Context, filter *content_dto.ContentListFilte
|
||||
q = q.Where(tbl.Genre.Eq(*filter.Genre))
|
||||
}
|
||||
if filter.TenantID != nil && *filter.TenantID > 0 {
|
||||
if tenantID > 0 && *filter.TenantID != tenantID {
|
||||
return nil, errorx.ErrForbidden.WithMsg("租户不匹配")
|
||||
}
|
||||
q = q.Where(tbl.TenantID.Eq(*filter.TenantID))
|
||||
}
|
||||
if filter.IsPinned != nil {
|
||||
@@ -128,16 +134,22 @@ func (s *content) List(ctx context.Context, filter *content_dto.ContentListFilte
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *content) Get(ctx context.Context, userID, id int64) (*content_dto.ContentDetail, error) {
|
||||
func (s *content) Get(ctx context.Context, tenantID, userID, id int64) (*content_dto.ContentDetail, error) {
|
||||
// Increment Views
|
||||
_, _ = models.ContentQuery.WithContext(ctx).
|
||||
Where(models.ContentQuery.ID.Eq(id)).
|
||||
UpdateSimple(models.ContentQuery.Views.Add(1))
|
||||
update := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(id))
|
||||
if tenantID > 0 {
|
||||
update = update.Where(models.ContentQuery.TenantID.Eq(tenantID))
|
||||
}
|
||||
_, _ = update.UpdateSimple(models.ContentQuery.Views.Add(1))
|
||||
|
||||
_, q := models.ContentQuery.QueryContext(ctx)
|
||||
|
||||
var item models.Content
|
||||
err := q.UnderlyingDB().
|
||||
db := q.UnderlyingDB()
|
||||
if tenantID > 0 {
|
||||
db = db.Where("tenant_id = ?", tenantID)
|
||||
}
|
||||
err := db.
|
||||
Preload("Author").
|
||||
Preload("ContentAssets", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Order("sort ASC")
|
||||
@@ -232,10 +244,25 @@ func (s *content) Get(ctx context.Context, userID, id int64) (*content_dto.Conte
|
||||
return detail, nil
|
||||
}
|
||||
|
||||
func (s *content) ListComments(ctx context.Context, userID, id int64, page int) (*requests.Pager, error) {
|
||||
func (s *content) ListComments(ctx context.Context, tenantID, userID, id int64, page int) (*requests.Pager, error) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
tbl, q := models.CommentQuery.QueryContext(ctx)
|
||||
|
||||
q = q.Where(tbl.ContentID.Eq(id)).Preload(tbl.User)
|
||||
if tenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(tenantID))
|
||||
}
|
||||
q = q.Order(tbl.CreatedAt.Desc())
|
||||
|
||||
p := requests.Pagination{Page: int64(page), Limit: 10}
|
||||
@@ -291,6 +318,7 @@ func (s *content) ListComments(ctx context.Context, userID, id int64, page int)
|
||||
|
||||
func (s *content) CreateComment(
|
||||
ctx context.Context,
|
||||
tenantID int64,
|
||||
userID int64,
|
||||
id int64,
|
||||
form *content_dto.CommentCreateForm,
|
||||
@@ -300,7 +328,11 @@ func (s *content) CreateComment(
|
||||
}
|
||||
uid := userID
|
||||
|
||||
c, err := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(id)).First()
|
||||
query := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(id))
|
||||
if tenantID > 0 {
|
||||
query = query.Where(models.ContentQuery.TenantID.Eq(tenantID))
|
||||
}
|
||||
c, err := query.First()
|
||||
if err != nil {
|
||||
return errorx.ErrRecordNotFound
|
||||
}
|
||||
@@ -319,14 +351,18 @@ func (s *content) CreateComment(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *content) LikeComment(ctx context.Context, userID, id int64) error {
|
||||
func (s *content) LikeComment(ctx context.Context, tenantID, userID, id int64) error {
|
||||
if userID == 0 {
|
||||
return errorx.ErrUnauthorized
|
||||
}
|
||||
uid := userID
|
||||
|
||||
// Fetch comment for author
|
||||
cm, err := models.CommentQuery.WithContext(ctx).Where(models.CommentQuery.ID.Eq(id)).First()
|
||||
query := models.CommentQuery.WithContext(ctx).Where(models.CommentQuery.ID.Eq(id))
|
||||
if tenantID > 0 {
|
||||
query = query.Where(models.CommentQuery.TenantID.Eq(tenantID))
|
||||
}
|
||||
cm, err := query.First()
|
||||
if err != nil {
|
||||
return errorx.ErrRecordNotFound
|
||||
}
|
||||
@@ -357,14 +393,18 @@ func (s *content) LikeComment(ctx context.Context, userID, id int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *content) GetLibrary(ctx context.Context, userID int64) ([]user_dto.ContentItem, error) {
|
||||
func (s *content) GetLibrary(ctx context.Context, tenantID, userID int64) ([]user_dto.ContentItem, error) {
|
||||
if userID == 0 {
|
||||
return nil, errorx.ErrUnauthorized
|
||||
}
|
||||
uid := userID
|
||||
|
||||
tbl, q := models.ContentAccessQuery.QueryContext(ctx)
|
||||
accessList, err := q.Where(tbl.UserID.Eq(uid), tbl.Status.Eq(consts.ContentAccessStatusActive)).Find()
|
||||
q = q.Where(tbl.UserID.Eq(uid), tbl.Status.Eq(consts.ContentAccessStatusActive))
|
||||
if tenantID > 0 {
|
||||
q = q.Where(tbl.TenantID.Eq(tenantID))
|
||||
}
|
||||
accessList, err := q.Find()
|
||||
if err != nil {
|
||||
return nil, errorx.ErrDatabaseError.WithCause(err)
|
||||
}
|
||||
@@ -380,7 +420,11 @@ func (s *content) GetLibrary(ctx context.Context, userID int64) ([]user_dto.Cont
|
||||
|
||||
ctbl, cq := models.ContentQuery.QueryContext(ctx)
|
||||
var list []*models.Content
|
||||
err = cq.Where(ctbl.ID.In(contentIDs...)).
|
||||
cq = cq.Where(ctbl.ID.In(contentIDs...))
|
||||
if tenantID > 0 {
|
||||
cq = cq.Where(ctbl.TenantID.Eq(tenantID))
|
||||
}
|
||||
err = cq.
|
||||
UnderlyingDB().
|
||||
Preload("Author").
|
||||
Preload("ContentAssets.Asset").
|
||||
@@ -398,36 +442,40 @@ func (s *content) GetLibrary(ctx context.Context, userID int64) ([]user_dto.Cont
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (s *content) GetFavorites(ctx context.Context, userID int64) ([]user_dto.ContentItem, error) {
|
||||
return s.getInteractList(ctx, userID, "favorite")
|
||||
func (s *content) GetFavorites(ctx context.Context, tenantID, userID int64) ([]user_dto.ContentItem, error) {
|
||||
return s.getInteractList(ctx, tenantID, userID, "favorite")
|
||||
}
|
||||
|
||||
func (s *content) AddFavorite(ctx context.Context, userID, contentId int64) error {
|
||||
return s.addInteract(ctx, userID, contentId, "favorite")
|
||||
func (s *content) AddFavorite(ctx context.Context, tenantID, userID, contentId int64) error {
|
||||
return s.addInteract(ctx, tenantID, userID, contentId, "favorite")
|
||||
}
|
||||
|
||||
func (s *content) RemoveFavorite(ctx context.Context, userID, contentId int64) error {
|
||||
return s.removeInteract(ctx, userID, contentId, "favorite")
|
||||
func (s *content) RemoveFavorite(ctx context.Context, tenantID, userID, contentId int64) error {
|
||||
return s.removeInteract(ctx, tenantID, userID, contentId, "favorite")
|
||||
}
|
||||
|
||||
func (s *content) GetLikes(ctx context.Context, userID int64) ([]user_dto.ContentItem, error) {
|
||||
return s.getInteractList(ctx, userID, "like")
|
||||
func (s *content) GetLikes(ctx context.Context, tenantID, userID int64) ([]user_dto.ContentItem, error) {
|
||||
return s.getInteractList(ctx, tenantID, userID, "like")
|
||||
}
|
||||
|
||||
func (s *content) AddLike(ctx context.Context, userID, contentId int64) error {
|
||||
return s.addInteract(ctx, userID, contentId, "like")
|
||||
func (s *content) AddLike(ctx context.Context, tenantID, userID, contentId int64) error {
|
||||
return s.addInteract(ctx, tenantID, userID, contentId, "like")
|
||||
}
|
||||
|
||||
func (s *content) RemoveLike(ctx context.Context, userID, contentId int64) error {
|
||||
return s.removeInteract(ctx, userID, contentId, "like")
|
||||
func (s *content) RemoveLike(ctx context.Context, tenantID, userID, contentId int64) error {
|
||||
return s.removeInteract(ctx, tenantID, userID, contentId, "like")
|
||||
}
|
||||
|
||||
func (s *content) ListTopics(ctx context.Context) ([]content_dto.Topic, error) {
|
||||
func (s *content) ListTopics(ctx context.Context, tenantID int64) ([]content_dto.Topic, error) {
|
||||
var results []struct {
|
||||
Genre string
|
||||
Count int
|
||||
}
|
||||
err := models.ContentQuery.WithContext(ctx).UnderlyingDB().
|
||||
db := models.ContentQuery.WithContext(ctx).UnderlyingDB()
|
||||
if tenantID > 0 {
|
||||
db = db.Where("tenant_id = ?", tenantID)
|
||||
}
|
||||
err := db.
|
||||
Model(&models.Content{}).
|
||||
Where("status = ?", consts.ContentStatusPublished).
|
||||
Select("genre, count(*) as count").
|
||||
@@ -445,8 +493,12 @@ func (s *content) ListTopics(ctx context.Context) ([]content_dto.Topic, error) {
|
||||
|
||||
// Fetch latest content in this genre to get a cover
|
||||
var c models.Content
|
||||
models.ContentQuery.WithContext(ctx).
|
||||
Where(models.ContentQuery.Genre.Eq(r.Genre), models.ContentQuery.Status.Eq(consts.ContentStatusPublished)).
|
||||
query := models.ContentQuery.WithContext(ctx).
|
||||
Where(models.ContentQuery.Genre.Eq(r.Genre), models.ContentQuery.Status.Eq(consts.ContentStatusPublished))
|
||||
if tenantID > 0 {
|
||||
query = query.Where(models.ContentQuery.TenantID.Eq(tenantID))
|
||||
}
|
||||
query.
|
||||
Order(models.ContentQuery.PublishedAt.Desc()).
|
||||
UnderlyingDB().
|
||||
Preload("ContentAssets").
|
||||
@@ -554,15 +606,19 @@ func (s *content) toMediaURLs(assets []*models.ContentAsset) []content_dto.Media
|
||||
return urls
|
||||
}
|
||||
|
||||
func (s *content) addInteract(ctx context.Context, userID, contentId int64, typ string) error {
|
||||
func (s *content) addInteract(ctx context.Context, tenantID, userID, contentId int64, typ string) error {
|
||||
if userID == 0 {
|
||||
return errorx.ErrUnauthorized
|
||||
}
|
||||
uid := userID
|
||||
|
||||
// Fetch content for author
|
||||
c, err := models.ContentQuery.WithContext(ctx).
|
||||
Where(models.ContentQuery.ID.Eq(contentId)).
|
||||
query := models.ContentQuery.WithContext(ctx).
|
||||
Where(models.ContentQuery.ID.Eq(contentId))
|
||||
if tenantID > 0 {
|
||||
query = query.Where(models.ContentQuery.TenantID.Eq(tenantID))
|
||||
}
|
||||
c, err := query.
|
||||
Select(models.ContentQuery.UserID, models.ContentQuery.Title).
|
||||
First()
|
||||
if err != nil {
|
||||
@@ -583,7 +639,11 @@ func (s *content) addInteract(ctx context.Context, userID, contentId int64, typ
|
||||
}
|
||||
|
||||
if typ == "like" {
|
||||
_, err := tx.Content.WithContext(ctx).Where(tx.Content.ID.Eq(contentId)).UpdateSimple(tx.Content.Likes.Add(1))
|
||||
contentQuery := tx.Content.WithContext(ctx).Where(tx.Content.ID.Eq(contentId))
|
||||
if tenantID > 0 {
|
||||
contentQuery = contentQuery.Where(tx.Content.TenantID.Eq(tenantID))
|
||||
}
|
||||
_, err := contentQuery.UpdateSimple(tx.Content.Likes.Add(1))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -605,7 +665,7 @@ func (s *content) addInteract(ctx context.Context, userID, contentId int64, typ
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *content) removeInteract(ctx context.Context, userID, contentId int64, typ string) error {
|
||||
func (s *content) removeInteract(ctx context.Context, tenantID, userID, contentId int64, typ string) error {
|
||||
if userID == 0 {
|
||||
return errorx.ErrUnauthorized
|
||||
}
|
||||
@@ -623,14 +683,18 @@ func (s *content) removeInteract(ctx context.Context, userID, contentId int64, t
|
||||
}
|
||||
|
||||
if typ == "like" {
|
||||
_, err := tx.Content.WithContext(ctx).Where(tx.Content.ID.Eq(contentId)).UpdateSimple(tx.Content.Likes.Sub(1))
|
||||
contentQuery := tx.Content.WithContext(ctx).Where(tx.Content.ID.Eq(contentId))
|
||||
if tenantID > 0 {
|
||||
contentQuery = contentQuery.Where(tx.Content.TenantID.Eq(tenantID))
|
||||
}
|
||||
_, err := contentQuery.UpdateSimple(tx.Content.Likes.Sub(1))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *content) getInteractList(ctx context.Context, userID int64, typ string) ([]user_dto.ContentItem, error) {
|
||||
func (s *content) getInteractList(ctx context.Context, tenantID, userID int64, typ string) ([]user_dto.ContentItem, error) {
|
||||
if userID == 0 {
|
||||
return nil, errorx.ErrUnauthorized
|
||||
}
|
||||
@@ -653,7 +717,11 @@ func (s *content) getInteractList(ctx context.Context, userID int64, typ string)
|
||||
|
||||
ctbl, cq := models.ContentQuery.QueryContext(ctx)
|
||||
var list []*models.Content
|
||||
err = cq.Where(ctbl.ID.In(contentIDs...)).
|
||||
cq = cq.Where(ctbl.ID.In(contentIDs...))
|
||||
if tenantID > 0 {
|
||||
cq = cq.Where(ctbl.TenantID.Eq(tenantID))
|
||||
}
|
||||
err = cq.
|
||||
UnderlyingDB().
|
||||
Preload("Author").
|
||||
Preload("ContentAssets.Asset").
|
||||
|
||||
Reference in New Issue
Block a user