feat: tenant-scoped routing and portal navigation

This commit is contained in:
2026-01-08 21:30:46 +08:00
parent f3aa92078a
commit 3e095c57f3
52 changed files with 1111 additions and 670 deletions

View File

@@ -41,6 +41,7 @@ func Test_Content(t *testing.T) {
func (s *ContentTestSuite) Test_List() {
Convey("List", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameUser)
// Create Author
@@ -73,7 +74,7 @@ func (s *ContentTestSuite) Test_List() {
Limit: 10,
},
}
res, err := Content.List(ctx, filter)
res, err := Content.List(ctx, tenantID, filter)
So(err, ShouldBeNil)
So(res.Total, ShouldEqual, 1)
items := res.Items.([]content_dto.ContentItem)
@@ -86,6 +87,7 @@ func (s *ContentTestSuite) Test_List() {
func (s *ContentTestSuite) Test_Get() {
Convey("Get", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameMediaAsset, models.TableNameContentAsset, models.TableNameUser)
// Author
@@ -125,7 +127,7 @@ func (s *ContentTestSuite) Test_Get() {
ctx = context.WithValue(ctx, consts.CtxKeyUser, author.ID)
Convey("should get detail with assets", func() {
detail, err := Content.Get(ctx, author.ID, content.ID)
detail, err := Content.Get(ctx, tenantID, author.ID, content.ID)
So(err, ShouldBeNil)
So(detail.Title, ShouldEqual, "Detail Content")
So(detail.AuthorName, ShouldEqual, "Author1")
@@ -138,6 +140,7 @@ func (s *ContentTestSuite) Test_Get() {
func (s *ContentTestSuite) Test_CreateComment() {
Convey("CreateComment", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameComment, models.TableNameUser)
// User & Content
@@ -153,7 +156,7 @@ func (s *ContentTestSuite) Test_CreateComment() {
form := &content_dto.CommentCreateForm{
Content: "Nice!",
}
err := Content.CreateComment(ctx, u.ID, c.ID, form)
err := Content.CreateComment(ctx, tenantID, u.ID, c.ID, form)
So(err, ShouldBeNil)
count, _ := models.CommentQuery.WithContext(ctx).Where(models.CommentQuery.ContentID.Eq(c.ID)).Count()
@@ -165,6 +168,7 @@ func (s *ContentTestSuite) Test_CreateComment() {
func (s *ContentTestSuite) Test_Library() {
Convey("Library", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameContentAccess, models.TableNameUser, models.TableNameContentAsset, models.TableNameMediaAsset)
// User
@@ -192,7 +196,7 @@ func (s *ContentTestSuite) Test_Library() {
})
Convey("should get library content with details", func() {
list, err := Content.GetLibrary(ctx, u.ID)
list, err := Content.GetLibrary(ctx, tenantID, u.ID)
So(err, ShouldBeNil)
So(len(list), ShouldEqual, 1)
So(list[0].Title, ShouldEqual, "Paid Content")
@@ -206,6 +210,7 @@ func (s *ContentTestSuite) Test_Library() {
func (s *ContentTestSuite) Test_Interact() {
Convey("Interact", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameUserContentAction, models.TableNameUser)
// User & Content
@@ -218,7 +223,7 @@ func (s *ContentTestSuite) Test_Interact() {
Convey("Like flow", func() {
// Add Like
err := Content.AddLike(ctx, u.ID, c.ID)
err := Content.AddLike(ctx, tenantID, u.ID, c.ID)
So(err, ShouldBeNil)
// Verify count
@@ -226,13 +231,13 @@ func (s *ContentTestSuite) Test_Interact() {
So(cReload.Likes, ShouldEqual, 1)
// Get Likes
likes, err := Content.GetLikes(ctx, u.ID)
likes, err := Content.GetLikes(ctx, tenantID, u.ID)
So(err, ShouldBeNil)
So(len(likes), ShouldEqual, 1)
So(likes[0].ID, ShouldEqual, c.ID)
// Remove Like
err = Content.RemoveLike(ctx, u.ID, c.ID)
err = Content.RemoveLike(ctx, tenantID, u.ID, c.ID)
So(err, ShouldBeNil)
// Verify count
@@ -242,21 +247,21 @@ func (s *ContentTestSuite) Test_Interact() {
Convey("Favorite flow", func() {
// Add Favorite
err := Content.AddFavorite(ctx, u.ID, c.ID)
err := Content.AddFavorite(ctx, tenantID, u.ID, c.ID)
So(err, ShouldBeNil)
// Get Favorites
favs, err := Content.GetFavorites(ctx, u.ID)
favs, err := Content.GetFavorites(ctx, tenantID, u.ID)
So(err, ShouldBeNil)
So(len(favs), ShouldEqual, 1)
So(favs[0].ID, ShouldEqual, c.ID)
// Remove Favorite
err = Content.RemoveFavorite(ctx, u.ID, c.ID)
err = Content.RemoveFavorite(ctx, tenantID, u.ID, c.ID)
So(err, ShouldBeNil)
// Get Favorites
favs, err = Content.GetFavorites(ctx, u.ID)
favs, err = Content.GetFavorites(ctx, tenantID, u.ID)
So(err, ShouldBeNil)
So(len(favs), ShouldEqual, 0)
})
@@ -266,6 +271,7 @@ func (s *ContentTestSuite) Test_Interact() {
func (s *ContentTestSuite) Test_ListTopics() {
Convey("ListTopics", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameUser)
u := &models.User{Username: "user_t", Phone: "13900000005"}
@@ -280,7 +286,7 @@ func (s *ContentTestSuite) Test_ListTopics() {
)
Convey("should aggregate topics", func() {
topics, err := Content.ListTopics(ctx)
topics, err := Content.ListTopics(ctx, tenantID)
So(err, ShouldBeNil)
So(len(topics), ShouldBeGreaterThanOrEqualTo, 2)
@@ -302,6 +308,7 @@ func (s *ContentTestSuite) Test_ListTopics() {
func (s *ContentTestSuite) Test_PreviewLogic() {
Convey("Preview Logic", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameContentAsset, models.TableNameContentAccess, models.TableNameUser, models.TableNameMediaAsset)
author := &models.User{Username: "author_p", Phone: "13900000006"}
@@ -324,7 +331,7 @@ func (s *ContentTestSuite) Test_PreviewLogic() {
models.UserQuery.WithContext(ctx).Create(guest)
guestCtx := context.WithValue(ctx, consts.CtxKeyUser, guest.ID)
detail, err := Content.Get(guestCtx, 0, c.ID)
detail, err := Content.Get(guestCtx, tenantID, 0, c.ID)
So(err, ShouldBeNil)
So(len(detail.MediaUrls), ShouldEqual, 1)
So(detail.MediaUrls[0].URL, ShouldContainSubstring, "preview.mp4")
@@ -333,7 +340,7 @@ func (s *ContentTestSuite) Test_PreviewLogic() {
Convey("owner should see all", func() {
ownerCtx := context.WithValue(ctx, consts.CtxKeyUser, author.ID)
detail, err := Content.Get(ownerCtx, author.ID, c.ID)
detail, err := Content.Get(ownerCtx, tenantID, author.ID, c.ID)
So(err, ShouldBeNil)
So(len(detail.MediaUrls), ShouldEqual, 2)
So(detail.IsPurchased, ShouldBeTrue)
@@ -348,7 +355,7 @@ func (s *ContentTestSuite) Test_PreviewLogic() {
UserID: buyer.ID, ContentID: c.ID, Status: consts.ContentAccessStatusActive,
})
detail, err := Content.Get(buyerCtx, buyer.ID, c.ID)
detail, err := Content.Get(buyerCtx, tenantID, buyer.ID, c.ID)
So(err, ShouldBeNil)
So(len(detail.MediaUrls), ShouldEqual, 2)
So(detail.IsPurchased, ShouldBeTrue)
@@ -359,6 +366,7 @@ func (s *ContentTestSuite) Test_PreviewLogic() {
func (s *ContentTestSuite) Test_ViewCounting() {
Convey("ViewCounting", s.T(), func() {
ctx := s.T().Context()
tenantID := int64(1)
database.Truncate(ctx, s.DB, models.TableNameContent, models.TableNameUser)
author := &models.User{Username: "author_v", Phone: "13900000009"}
@@ -368,7 +376,7 @@ func (s *ContentTestSuite) Test_ViewCounting() {
models.ContentQuery.WithContext(ctx).Create(c)
Convey("should increment views", func() {
_, err := Content.Get(ctx, 0, c.ID)
_, err := Content.Get(ctx, tenantID, 0, c.ID)
So(err, ShouldBeNil)
cReload, _ := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(c.ID)).First()