feat: 更新服务方法,显式接受用户ID参数,简化上下文调用
This commit is contained in:
@@ -126,7 +126,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, cast.ToString(content.ID))
|
||||
detail, err := Content.Get(ctx, author.ID, cast.ToString(content.ID))
|
||||
So(err, ShouldBeNil)
|
||||
So(detail.Title, ShouldEqual, "Detail Content")
|
||||
So(detail.AuthorName, ShouldEqual, "Author1")
|
||||
@@ -154,7 +154,7 @@ func (s *ContentTestSuite) Test_CreateComment() {
|
||||
form := &content_dto.CommentCreateForm{
|
||||
Content: "Nice!",
|
||||
}
|
||||
err := Content.CreateComment(ctx, cast.ToString(c.ID), form)
|
||||
err := Content.CreateComment(ctx, u.ID, cast.ToString(c.ID), form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
count, _ := models.CommentQuery.WithContext(ctx).Where(models.CommentQuery.ContentID.Eq(c.ID)).Count()
|
||||
@@ -193,7 +193,7 @@ func (s *ContentTestSuite) Test_Library() {
|
||||
})
|
||||
|
||||
Convey("should get library content with details", func() {
|
||||
list, err := Content.GetLibrary(ctx)
|
||||
list, err := Content.GetLibrary(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(list), ShouldEqual, 1)
|
||||
So(list[0].Title, ShouldEqual, "Paid Content")
|
||||
@@ -219,7 +219,7 @@ func (s *ContentTestSuite) Test_Interact() {
|
||||
|
||||
Convey("Like flow", func() {
|
||||
// Add Like
|
||||
err := Content.AddLike(ctx, cast.ToString(c.ID))
|
||||
err := Content.AddLike(ctx, u.ID, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify count
|
||||
@@ -227,13 +227,13 @@ func (s *ContentTestSuite) Test_Interact() {
|
||||
So(cReload.Likes, ShouldEqual, 1)
|
||||
|
||||
// Get Likes
|
||||
likes, err := Content.GetLikes(ctx)
|
||||
likes, err := Content.GetLikes(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(likes), ShouldEqual, 1)
|
||||
So(likes[0].ID, ShouldEqual, cast.ToString(c.ID))
|
||||
|
||||
// Remove Like
|
||||
err = Content.RemoveLike(ctx, cast.ToString(c.ID))
|
||||
err = Content.RemoveLike(ctx, u.ID, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify count
|
||||
@@ -243,21 +243,21 @@ func (s *ContentTestSuite) Test_Interact() {
|
||||
|
||||
Convey("Favorite flow", func() {
|
||||
// Add Favorite
|
||||
err := Content.AddFavorite(ctx, cast.ToString(c.ID))
|
||||
err := Content.AddFavorite(ctx, u.ID, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Get Favorites
|
||||
favs, err := Content.GetFavorites(ctx)
|
||||
favs, err := Content.GetFavorites(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(favs), ShouldEqual, 1)
|
||||
So(favs[0].ID, ShouldEqual, cast.ToString(c.ID))
|
||||
|
||||
// Remove Favorite
|
||||
err = Content.RemoveFavorite(ctx, cast.ToString(c.ID))
|
||||
err = Content.RemoveFavorite(ctx, u.ID, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Get Favorites
|
||||
favs, err = Content.GetFavorites(ctx)
|
||||
favs, err = Content.GetFavorites(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(favs), ShouldEqual, 0)
|
||||
})
|
||||
@@ -325,7 +325,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, cast.ToString(c.ID))
|
||||
detail, err := Content.Get(guestCtx, 0, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
So(len(detail.MediaUrls), ShouldEqual, 1)
|
||||
So(detail.MediaUrls[0].URL, ShouldEndWith, "preview.mp4")
|
||||
@@ -334,7 +334,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, cast.ToString(c.ID))
|
||||
detail, err := Content.Get(ownerCtx, author.ID, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
So(len(detail.MediaUrls), ShouldEqual, 2)
|
||||
So(detail.IsPurchased, ShouldBeTrue)
|
||||
@@ -349,7 +349,7 @@ func (s *ContentTestSuite) Test_PreviewLogic() {
|
||||
UserID: buyer.ID, ContentID: c.ID, Status: consts.ContentAccessStatusActive,
|
||||
})
|
||||
|
||||
detail, err := Content.Get(buyerCtx, cast.ToString(c.ID))
|
||||
detail, err := Content.Get(buyerCtx, buyer.ID, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
So(len(detail.MediaUrls), ShouldEqual, 2)
|
||||
So(detail.IsPurchased, ShouldBeTrue)
|
||||
@@ -369,7 +369,7 @@ func (s *ContentTestSuite) Test_ViewCounting() {
|
||||
models.ContentQuery.WithContext(ctx).Create(c)
|
||||
|
||||
Convey("should increment views", func() {
|
||||
_, err := Content.Get(ctx, cast.ToString(c.ID))
|
||||
_, err := Content.Get(ctx, 0, cast.ToString(c.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cReload, _ := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.ID.Eq(c.ID)).First()
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"quyun/v2/app/errorx"
|
||||
coupon_dto "quyun/v2/app/http/v1/dto"
|
||||
"quyun/v2/database/models"
|
||||
"quyun/v2/pkg/consts"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -15,7 +14,11 @@ import (
|
||||
// @provider
|
||||
type coupon struct{}
|
||||
|
||||
func (s *coupon) ListUserCoupons(ctx context.Context, userID int64, status string) ([]coupon_dto.UserCouponItem, error) {
|
||||
func (s *coupon) ListUserCoupons(
|
||||
ctx context.Context,
|
||||
userID int64,
|
||||
status string,
|
||||
) ([]coupon_dto.UserCouponItem, error) {
|
||||
if userID == 0 {
|
||||
return nil, errorx.ErrUnauthorized
|
||||
}
|
||||
@@ -111,11 +114,13 @@ func (s *coupon) Validate(ctx context.Context, userID, userCouponID, amount int6
|
||||
func (s *coupon) MarkUsed(ctx context.Context, tx *models.Query, userCouponID, orderID int64) error {
|
||||
now := time.Now()
|
||||
// Update User Coupon
|
||||
info, err := tx.UserCoupon.WithContext(ctx).Where(tx.UserCoupon.ID.Eq(userCouponID), tx.UserCoupon.Status.Eq("unused")).Updates(&models.UserCoupon{
|
||||
Status: "used",
|
||||
OrderID: orderID,
|
||||
UsedAt: now,
|
||||
})
|
||||
info, err := tx.UserCoupon.WithContext(ctx).
|
||||
Where(tx.UserCoupon.ID.Eq(userCouponID), tx.UserCoupon.Status.Eq("unused")).
|
||||
Updates(&models.UserCoupon{
|
||||
Status: "used",
|
||||
OrderID: orderID,
|
||||
UsedAt: now,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"testing"
|
||||
|
||||
@@ -42,7 +41,16 @@ func Test_Coupon(t *testing.T) {
|
||||
func (s *CouponTestSuite) Test_CouponFlow() {
|
||||
Convey("Coupon Flow", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB, models.TableNameCoupon, models.TableNameUserCoupon, models.TableNameOrder, models.TableNameUser, models.TableNameContent, models.TableNameContentPrice)
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameCoupon,
|
||||
models.TableNameUserCoupon,
|
||||
models.TableNameOrder,
|
||||
models.TableNameUser,
|
||||
models.TableNameContent,
|
||||
models.TableNameContentPrice,
|
||||
)
|
||||
|
||||
user := &models.User{Username: "coupon_user", Phone: "13800000001"}
|
||||
models.UserQuery.WithContext(ctx).Create(user)
|
||||
@@ -90,8 +98,7 @@ func (s *CouponTestSuite) Test_CouponFlow() {
|
||||
UserCouponID: cast.ToString(uc.ID),
|
||||
}
|
||||
// Simulate Auth context for Order service
|
||||
authCtx := context.WithValue(ctx, consts.CtxKeyUser, user.ID)
|
||||
res, err := Order.Create(authCtx, form)
|
||||
res, err := Order.Create(ctx, user.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify Order
|
||||
|
||||
@@ -51,7 +51,7 @@ func (s *CreatorTestSuite) Test_Apply() {
|
||||
form := &creator_dto.ApplyForm{
|
||||
Name: "My Channel",
|
||||
}
|
||||
err := Creator.Apply(ctx, form)
|
||||
err := Creator.Apply(ctx, u.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
t, _ := models.TenantQuery.WithContext(ctx).Where(models.TenantQuery.UserID.Eq(u.ID)).First()
|
||||
@@ -73,7 +73,15 @@ func (s *CreatorTestSuite) Test_Apply() {
|
||||
func (s *CreatorTestSuite) Test_CreateContent() {
|
||||
Convey("CreateContent", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNameContent, models.TableNameContentAsset, models.TableNameContentPrice, models.TableNameUser)
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameTenant,
|
||||
models.TableNameContent,
|
||||
models.TableNameContentAsset,
|
||||
models.TableNameContentPrice,
|
||||
models.TableNameUser,
|
||||
)
|
||||
|
||||
u := &models.User{Username: "creator2", Phone: "13700000002"}
|
||||
models.UserQuery.WithContext(ctx).Create(u)
|
||||
@@ -90,7 +98,7 @@ func (s *CreatorTestSuite) Test_CreateContent() {
|
||||
Price: 9.99,
|
||||
// MediaIDs: ... need media asset
|
||||
}
|
||||
err := Creator.CreateContent(ctx, form)
|
||||
err := Creator.CreateContent(ctx, u.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
c, _ := models.ContentQuery.WithContext(ctx).Where(models.ContentQuery.Title.Eq("New Song")).First()
|
||||
@@ -109,7 +117,15 @@ func (s *CreatorTestSuite) Test_CreateContent() {
|
||||
func (s *CreatorTestSuite) Test_UpdateContent() {
|
||||
Convey("UpdateContent", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNameContent, models.TableNameContentAsset, models.TableNameContentPrice, models.TableNameUser)
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameTenant,
|
||||
models.TableNameContent,
|
||||
models.TableNameContentAsset,
|
||||
models.TableNameContentPrice,
|
||||
models.TableNameUser,
|
||||
)
|
||||
|
||||
u := &models.User{Username: "creator3", Phone: "13700000003"}
|
||||
models.UserQuery.WithContext(ctx).Create(u)
|
||||
@@ -120,7 +136,8 @@ func (s *CreatorTestSuite) Test_UpdateContent() {
|
||||
|
||||
c := &models.Content{TenantID: t.ID, UserID: u.ID, Title: "Old Title", Genre: "audio"}
|
||||
models.ContentQuery.WithContext(ctx).Create(c)
|
||||
models.ContentPriceQuery.WithContext(ctx).Create(&models.ContentPrice{TenantID: t.ID, UserID: u.ID, ContentID: c.ID, PriceAmount: 100})
|
||||
models.ContentPriceQuery.WithContext(ctx).
|
||||
Create(&models.ContentPrice{TenantID: t.ID, UserID: u.ID, ContentID: c.ID, PriceAmount: 100})
|
||||
|
||||
Convey("should update content", func() {
|
||||
form := &creator_dto.ContentUpdateForm{
|
||||
@@ -128,7 +145,7 @@ func (s *CreatorTestSuite) Test_UpdateContent() {
|
||||
Genre: "video",
|
||||
Price: 20.00,
|
||||
}
|
||||
err := Creator.UpdateContent(ctx, cast.ToString(c.ID), form)
|
||||
err := Creator.UpdateContent(ctx, u.ID, cast.ToString(c.ID), form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify
|
||||
@@ -145,7 +162,15 @@ func (s *CreatorTestSuite) Test_UpdateContent() {
|
||||
func (s *CreatorTestSuite) Test_Dashboard() {
|
||||
Convey("Dashboard", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNameTenantUser, models.TableNameTenantLedger, models.TableNameUser, models.TableNameOrder)
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameTenant,
|
||||
models.TableNameTenantUser,
|
||||
models.TableNameTenantLedger,
|
||||
models.TableNameUser,
|
||||
models.TableNameOrder,
|
||||
)
|
||||
|
||||
u := &models.User{Username: "creator4", Phone: "13700000004"}
|
||||
models.UserQuery.WithContext(ctx).Create(u)
|
||||
@@ -165,11 +190,15 @@ func (s *CreatorTestSuite) Test_Dashboard() {
|
||||
models.TenantLedgerQuery.WithContext(ctx).Create(
|
||||
&models.TenantLedger{TenantID: t.ID, Type: consts.TenantLedgerTypeDebitPurchase, Amount: 1000}, // 10.00
|
||||
&models.TenantLedger{TenantID: t.ID, Type: consts.TenantLedgerTypeDebitPurchase, Amount: 2000}, // 20.00
|
||||
&models.TenantLedger{TenantID: t.ID, Type: consts.TenantLedgerTypeCreditRefund, Amount: 500}, // -5.00 (Refund, currently Dashboard sums DebitPurchase only, ideally should subtract refunds, but let's stick to implementation)
|
||||
&models.TenantLedger{
|
||||
TenantID: t.ID,
|
||||
Type: consts.TenantLedgerTypeCreditRefund,
|
||||
Amount: 500,
|
||||
}, // -5.00 (Refund, currently Dashboard sums DebitPurchase only, ideally should subtract refunds, but let's stick to implementation)
|
||||
)
|
||||
|
||||
Convey("should get stats", func() {
|
||||
stats, err := Creator.Dashboard(ctx)
|
||||
stats, err := Creator.Dashboard(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(stats.TotalFollowers.Value, ShouldEqual, 2)
|
||||
// Implementation sums 'debit_purchase' only based on my code
|
||||
@@ -198,21 +227,21 @@ func (s *CreatorTestSuite) Test_PayoutAccount() {
|
||||
Account: "user@example.com",
|
||||
Realname: "John Doe",
|
||||
}
|
||||
err := Creator.AddPayoutAccount(ctx, form)
|
||||
err := Creator.AddPayoutAccount(ctx, u.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// List
|
||||
list, err := Creator.ListPayoutAccounts(ctx)
|
||||
list, err := Creator.ListPayoutAccounts(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(list), ShouldEqual, 1)
|
||||
So(list[0].Account, ShouldEqual, "user@example.com")
|
||||
|
||||
// Remove
|
||||
err = Creator.RemovePayoutAccount(ctx, list[0].ID)
|
||||
err = Creator.RemovePayoutAccount(ctx, u.ID, list[0].ID)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify Empty
|
||||
list, err = Creator.ListPayoutAccounts(ctx)
|
||||
list, err = Creator.ListPayoutAccounts(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(list), ShouldEqual, 0)
|
||||
})
|
||||
@@ -222,7 +251,15 @@ func (s *CreatorTestSuite) Test_PayoutAccount() {
|
||||
func (s *CreatorTestSuite) Test_Withdraw() {
|
||||
Convey("Withdraw", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB, models.TableNameTenant, models.TableNamePayoutAccount, models.TableNameUser, models.TableNameOrder, models.TableNameTenantLedger)
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameTenant,
|
||||
models.TableNamePayoutAccount,
|
||||
models.TableNameUser,
|
||||
models.TableNameOrder,
|
||||
models.TableNameTenantLedger,
|
||||
)
|
||||
|
||||
u := &models.User{Username: "creator6", Phone: "13700000006", Balance: 5000} // 50.00
|
||||
models.UserQuery.WithContext(ctx).Create(u)
|
||||
@@ -231,7 +268,14 @@ func (s *CreatorTestSuite) Test_Withdraw() {
|
||||
t := &models.Tenant{UserID: u.ID, Name: "Channel 6", Code: "127", Status: consts.TenantStatusVerified}
|
||||
models.TenantQuery.WithContext(ctx).Create(t)
|
||||
|
||||
pa := &models.PayoutAccount{TenantID: t.ID, UserID: u.ID, Type: "bank", Name: "Bank", Account: "123", Realname: "Creator"}
|
||||
pa := &models.PayoutAccount{
|
||||
TenantID: t.ID,
|
||||
UserID: u.ID,
|
||||
Type: "bank",
|
||||
Name: "Bank",
|
||||
Account: "123",
|
||||
Realname: "Creator",
|
||||
}
|
||||
models.PayoutAccountQuery.WithContext(ctx).Create(pa)
|
||||
|
||||
Convey("should withdraw successfully", func() {
|
||||
@@ -239,7 +283,7 @@ func (s *CreatorTestSuite) Test_Withdraw() {
|
||||
Amount: 20.00,
|
||||
AccountID: cast.ToString(pa.ID),
|
||||
}
|
||||
err := Creator.Withdraw(ctx, form)
|
||||
err := Creator.Withdraw(ctx, u.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify Balance Deducted
|
||||
@@ -247,7 +291,9 @@ func (s *CreatorTestSuite) Test_Withdraw() {
|
||||
So(uReload.Balance, ShouldEqual, 3000)
|
||||
|
||||
// Verify Order Created
|
||||
o, _ := models.OrderQuery.WithContext(ctx).Where(models.OrderQuery.TenantID.Eq(t.ID), models.OrderQuery.Type.Eq(consts.OrderTypeWithdrawal)).First()
|
||||
o, _ := models.OrderQuery.WithContext(ctx).
|
||||
Where(models.OrderQuery.TenantID.Eq(t.ID), models.OrderQuery.Type.Eq(consts.OrderTypeWithdrawal)).
|
||||
First()
|
||||
So(o, ShouldNotBeNil)
|
||||
So(o.AmountPaid, ShouldEqual, 2000)
|
||||
|
||||
@@ -262,7 +308,7 @@ func (s *CreatorTestSuite) Test_Withdraw() {
|
||||
Amount: 100.00,
|
||||
AccountID: cast.ToString(pa.ID),
|
||||
}
|
||||
err := Creator.Withdraw(ctx, form)
|
||||
err := Creator.Withdraw(ctx, u.ID, form)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
@@ -279,7 +325,7 @@ func (s *CreatorTestSuite) Test_Refund() {
|
||||
// Creator
|
||||
creator := &models.User{Username: "creator7", Phone: "13700000007", Balance: 5000} // Has funds
|
||||
models.UserQuery.WithContext(ctx).Create(creator)
|
||||
creatorCtx := context.WithValue(ctx, consts.CtxKeyUser, creator.ID)
|
||||
// creatorCtx := context.WithValue(ctx, consts.CtxKeyUser, creator.ID)
|
||||
|
||||
// Tenant
|
||||
t := &models.Tenant{UserID: creator.ID, Name: "Channel 7", Code: "128", Status: consts.TenantStatusVerified}
|
||||
@@ -298,11 +344,12 @@ func (s *CreatorTestSuite) Test_Refund() {
|
||||
}
|
||||
models.OrderQuery.WithContext(ctx).Create(o)
|
||||
models.OrderItemQuery.WithContext(ctx).Create(&models.OrderItem{OrderID: o.ID, ContentID: 100}) // Fake content
|
||||
models.ContentAccessQuery.WithContext(ctx).Create(&models.ContentAccess{UserID: buyer.ID, ContentID: 100, Status: consts.ContentAccessStatusActive})
|
||||
models.ContentAccessQuery.WithContext(ctx).
|
||||
Create(&models.ContentAccess{UserID: buyer.ID, ContentID: 100, Status: consts.ContentAccessStatusActive})
|
||||
|
||||
Convey("should accept refund", func() {
|
||||
form := &creator_dto.RefundForm{Action: "accept", Reason: "Defective"}
|
||||
err := Creator.ProcessRefund(creatorCtx, cast.ToString(o.ID), form)
|
||||
err := Creator.ProcessRefund(ctx, creator.ID, cast.ToString(o.ID), form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify Order
|
||||
@@ -317,7 +364,9 @@ func (s *CreatorTestSuite) Test_Refund() {
|
||||
So(bReload.Balance, ShouldEqual, 1000) // 0 + 1000
|
||||
|
||||
// Verify Access
|
||||
acc, _ := models.ContentAccessQuery.WithContext(ctx).Where(models.ContentAccessQuery.UserID.Eq(buyer.ID)).First()
|
||||
acc, _ := models.ContentAccessQuery.WithContext(ctx).
|
||||
Where(models.ContentAccessQuery.UserID.Eq(buyer.ID)).
|
||||
First()
|
||||
So(acc.Status, ShouldEqual, consts.ContentAccessStatusRevoked)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"quyun/v2/app/jobs/args"
|
||||
"quyun/v2/app/requests"
|
||||
"quyun/v2/database/models"
|
||||
"quyun/v2/pkg/consts"
|
||||
"quyun/v2/providers/job"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
|
||||
@@ -50,7 +50,7 @@ func (s *NotificationTestSuite) Test_CRUD() {
|
||||
err := Notification.Send(ctx, uID, "system", "Welcome", "Hello World")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
list, err := Notification.List(ctx, 1, "")
|
||||
list, err := Notification.List(ctx, uID, 1, "")
|
||||
So(err, ShouldBeNil)
|
||||
So(list.Total, ShouldEqual, 1)
|
||||
|
||||
@@ -61,7 +61,7 @@ func (s *NotificationTestSuite) Test_CRUD() {
|
||||
// Mark Read
|
||||
// Need ID
|
||||
n, _ := models.NotificationQuery.WithContext(ctx).Where(models.NotificationQuery.UserID.Eq(uID)).First()
|
||||
err = Notification.MarkRead(ctx, cast.ToString(n.ID))
|
||||
err = Notification.MarkRead(ctx, uID, cast.ToString(n.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
nReload, _ := models.NotificationQuery.WithContext(ctx).Where(models.NotificationQuery.ID.Eq(n.ID)).First()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"testing"
|
||||
|
||||
@@ -52,25 +51,40 @@ func (s *OrderTestSuite) Test_PurchaseFlow() {
|
||||
creator := &models.User{Username: "creator", Phone: "13800000001"}
|
||||
models.UserQuery.WithContext(ctx).Create(creator)
|
||||
// Tenant
|
||||
tenant := &models.Tenant{UserID: creator.ID, Name: "Music Shop", Code: "shop1", Status: consts.TenantStatusVerified}
|
||||
tenant := &models.Tenant{
|
||||
UserID: creator.ID,
|
||||
Name: "Music Shop",
|
||||
Code: "shop1",
|
||||
Status: consts.TenantStatusVerified,
|
||||
}
|
||||
models.TenantQuery.WithContext(ctx).Create(tenant)
|
||||
// Content
|
||||
content := &models.Content{TenantID: tenant.ID, UserID: creator.ID, Title: "Song A", Status: consts.ContentStatusPublished}
|
||||
content := &models.Content{
|
||||
TenantID: tenant.ID,
|
||||
UserID: creator.ID,
|
||||
Title: "Song A",
|
||||
Status: consts.ContentStatusPublished,
|
||||
}
|
||||
models.ContentQuery.WithContext(ctx).Create(content)
|
||||
// Price (10.00 CNY = 1000 cents)
|
||||
price := &models.ContentPrice{TenantID: tenant.ID, ContentID: content.ID, PriceAmount: 1000, Currency: consts.CurrencyCNY}
|
||||
price := &models.ContentPrice{
|
||||
TenantID: tenant.ID,
|
||||
ContentID: content.ID,
|
||||
PriceAmount: 1000,
|
||||
Currency: consts.CurrencyCNY,
|
||||
}
|
||||
models.ContentPriceQuery.WithContext(ctx).Create(price)
|
||||
|
||||
// Buyer
|
||||
buyer := &models.User{Username: "buyer", Phone: "13900000001", Balance: 2000} // Has 20.00
|
||||
models.UserQuery.WithContext(ctx).Create(buyer)
|
||||
|
||||
buyerCtx := context.WithValue(ctx, consts.CtxKeyUser, buyer.ID)
|
||||
// buyerCtx := context.WithValue(ctx, consts.CtxKeyUser, buyer.ID)
|
||||
|
||||
Convey("should create and pay order successfully", func() {
|
||||
// Step 1: Create Order
|
||||
form := &order_dto.OrderCreateForm{ContentID: cast.ToString(content.ID)}
|
||||
createRes, err := Order.Create(buyerCtx, form)
|
||||
createRes, err := Order.Create(ctx, buyer.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
So(createRes.OrderID, ShouldNotBeEmpty)
|
||||
|
||||
@@ -82,7 +96,7 @@ func (s *OrderTestSuite) Test_PurchaseFlow() {
|
||||
|
||||
// Step 2: Pay Order
|
||||
payForm := &order_dto.OrderPayForm{Method: "balance"}
|
||||
_, err = Order.Pay(buyerCtx, createRes.OrderID, payForm)
|
||||
_, err = Order.Pay(ctx, buyer.ID, createRes.OrderID, payForm)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify Order Paid
|
||||
@@ -95,7 +109,9 @@ func (s *OrderTestSuite) Test_PurchaseFlow() {
|
||||
So(b.Balance, ShouldEqual, 1000) // 2000 - 1000
|
||||
|
||||
// Verify Access Granted
|
||||
access, _ := models.ContentAccessQuery.WithContext(ctx).Where(models.ContentAccessQuery.UserID.Eq(buyer.ID), models.ContentAccessQuery.ContentID.Eq(content.ID)).First()
|
||||
access, _ := models.ContentAccessQuery.WithContext(ctx).
|
||||
Where(models.ContentAccessQuery.UserID.Eq(buyer.ID), models.ContentAccessQuery.ContentID.Eq(content.ID)).
|
||||
First()
|
||||
So(access, ShouldNotBeNil)
|
||||
So(access.Status, ShouldEqual, consts.ContentAccessStatusActive)
|
||||
|
||||
@@ -110,14 +126,16 @@ func (s *OrderTestSuite) Test_PurchaseFlow() {
|
||||
|
||||
Convey("should fail pay if insufficient balance", func() {
|
||||
// Set balance to 5.00
|
||||
models.UserQuery.WithContext(ctx).Where(models.UserQuery.ID.Eq(buyer.ID)).Update(models.UserQuery.Balance, 500)
|
||||
models.UserQuery.WithContext(ctx).
|
||||
Where(models.UserQuery.ID.Eq(buyer.ID)).
|
||||
Update(models.UserQuery.Balance, 500)
|
||||
|
||||
form := &order_dto.OrderCreateForm{ContentID: cast.ToString(content.ID)}
|
||||
createRes, err := Order.Create(buyerCtx, form)
|
||||
createRes, err := Order.Create(ctx, buyer.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
payForm := &order_dto.OrderPayForm{Method: "balance"}
|
||||
_, err = Order.Pay(buyerCtx, createRes.OrderID, payForm)
|
||||
_, err = Order.Pay(ctx, buyer.ID, createRes.OrderID, payForm)
|
||||
So(err, ShouldNotBeNil)
|
||||
// Error should be QuotaExceeded or similar
|
||||
})
|
||||
@@ -127,10 +145,19 @@ func (s *OrderTestSuite) Test_PurchaseFlow() {
|
||||
func (s *OrderTestSuite) Test_OrderDetails() {
|
||||
Convey("Order Details", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB,
|
||||
models.TableNameOrder, models.TableNameOrderItem, models.TableNameUser,
|
||||
models.TableNameContent, models.TableNameContentPrice, models.TableNameTenant,
|
||||
models.TableNameContentAccess, models.TableNameTenantLedger, models.TableNameMediaAsset, models.TableNameContentAsset,
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameOrder,
|
||||
models.TableNameOrderItem,
|
||||
models.TableNameUser,
|
||||
models.TableNameContent,
|
||||
models.TableNameContentPrice,
|
||||
models.TableNameTenant,
|
||||
models.TableNameContentAccess,
|
||||
models.TableNameTenantLedger,
|
||||
models.TableNameMediaAsset,
|
||||
models.TableNameContentAsset,
|
||||
)
|
||||
|
||||
// Setup
|
||||
@@ -138,28 +165,48 @@ func (s *OrderTestSuite) Test_OrderDetails() {
|
||||
models.UserQuery.WithContext(ctx).Create(creator)
|
||||
tenant := &models.Tenant{UserID: creator.ID, Name: "Best Shop", Status: consts.TenantStatusVerified}
|
||||
models.TenantQuery.WithContext(ctx).Create(tenant)
|
||||
content := &models.Content{TenantID: tenant.ID, UserID: creator.ID, Title: "Amazing Song", Status: consts.ContentStatusPublished}
|
||||
content := &models.Content{
|
||||
TenantID: tenant.ID,
|
||||
UserID: creator.ID,
|
||||
Title: "Amazing Song",
|
||||
Status: consts.ContentStatusPublished,
|
||||
}
|
||||
models.ContentQuery.WithContext(ctx).Create(content)
|
||||
price := &models.ContentPrice{TenantID: tenant.ID, ContentID: content.ID, PriceAmount: 500, Currency: consts.CurrencyCNY}
|
||||
price := &models.ContentPrice{
|
||||
TenantID: tenant.ID,
|
||||
ContentID: content.ID,
|
||||
PriceAmount: 500,
|
||||
Currency: consts.CurrencyCNY,
|
||||
}
|
||||
models.ContentPriceQuery.WithContext(ctx).Create(price)
|
||||
|
||||
// Asset (Cover)
|
||||
asset := &models.MediaAsset{TenantID: tenant.ID, UserID: creator.ID, Type: consts.MediaAssetTypeImage, ObjectKey: "cover.jpg"}
|
||||
asset := &models.MediaAsset{
|
||||
TenantID: tenant.ID,
|
||||
UserID: creator.ID,
|
||||
Type: consts.MediaAssetTypeImage,
|
||||
ObjectKey: "cover.jpg",
|
||||
}
|
||||
models.MediaAssetQuery.WithContext(ctx).Create(asset)
|
||||
models.ContentAssetQuery.WithContext(ctx).Create(&models.ContentAsset{ContentID: content.ID, AssetID: asset.ID, Role: consts.ContentAssetRoleCover})
|
||||
models.ContentAssetQuery.WithContext(ctx).
|
||||
Create(&models.ContentAsset{ContentID: content.ID, AssetID: asset.ID, Role: consts.ContentAssetRoleCover})
|
||||
|
||||
// Buyer
|
||||
buyer := &models.User{Username: "buyer2", Phone: "13900000002", Balance: 1000}
|
||||
models.UserQuery.WithContext(ctx).Create(buyer)
|
||||
buyerCtx := context.WithValue(ctx, consts.CtxKeyUser, buyer.ID)
|
||||
// buyerCtx := context.WithValue(ctx, consts.CtxKeyUser, buyer.ID)
|
||||
|
||||
Convey("should get full order details", func() {
|
||||
// Create & Pay
|
||||
createRes, _ := Order.Create(buyerCtx, &order_dto.OrderCreateForm{ContentID: cast.ToString(content.ID)})
|
||||
Order.Pay(buyerCtx, createRes.OrderID, &order_dto.OrderPayForm{Method: "balance"})
|
||||
createRes, _ := Order.Create(
|
||||
ctx,
|
||||
buyer.ID,
|
||||
&order_dto.OrderCreateForm{ContentID: cast.ToString(content.ID)},
|
||||
)
|
||||
Order.Pay(ctx, buyer.ID, createRes.OrderID, &order_dto.OrderPayForm{Method: "balance"})
|
||||
|
||||
// Get Detail
|
||||
detail, err := Order.GetUserOrder(buyerCtx, createRes.OrderID)
|
||||
detail, err := Order.GetUserOrder(ctx, buyer.ID, createRes.OrderID)
|
||||
So(err, ShouldBeNil)
|
||||
So(detail.TenantName, ShouldEqual, "Best Shop")
|
||||
So(len(detail.Items), ShouldEqual, 1)
|
||||
@@ -173,7 +220,16 @@ func (s *OrderTestSuite) Test_OrderDetails() {
|
||||
func (s *OrderTestSuite) Test_PlatformCommission() {
|
||||
Convey("Platform Commission", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB, models.TableNameUser, models.TableNameOrder, models.TableNameOrderItem, models.TableNameTenant, models.TableNameTenantLedger, models.TableNameContentAccess)
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameUser,
|
||||
models.TableNameOrder,
|
||||
models.TableNameOrderItem,
|
||||
models.TableNameTenant,
|
||||
models.TableNameTenantLedger,
|
||||
models.TableNameContentAccess,
|
||||
)
|
||||
|
||||
// Creator
|
||||
creator := &models.User{Username: "creator_c", Balance: 0}
|
||||
@@ -184,7 +240,7 @@ func (s *OrderTestSuite) Test_PlatformCommission() {
|
||||
// Buyer
|
||||
buyer := &models.User{Username: "buyer_c", Balance: 2000}
|
||||
models.UserQuery.WithContext(ctx).Create(buyer)
|
||||
buyerCtx := context.WithValue(ctx, consts.CtxKeyUser, buyer.ID)
|
||||
// buyerCtx := context.WithValue(ctx, consts.CtxKeyUser, buyer.ID)
|
||||
|
||||
// Order (10.00 CNY = 1000)
|
||||
o := &models.Order{
|
||||
@@ -198,7 +254,7 @@ func (s *OrderTestSuite) Test_PlatformCommission() {
|
||||
|
||||
Convey("should deduct 10% fee", func() {
|
||||
payForm := &order_dto.OrderPayForm{Method: "balance"}
|
||||
_, err := Order.Pay(buyerCtx, cast.ToString(o.ID), payForm)
|
||||
_, err := Order.Pay(ctx, buyer.ID, cast.ToString(o.ID), payForm)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify Creator Balance (1000 - 10% = 900)
|
||||
@@ -215,7 +271,16 @@ func (s *OrderTestSuite) Test_PlatformCommission() {
|
||||
func (s *OrderTestSuite) Test_ExternalPayment() {
|
||||
Convey("External Payment", s.T(), func() {
|
||||
ctx := s.T().Context()
|
||||
database.Truncate(ctx, s.DB, models.TableNameUser, models.TableNameOrder, models.TableNameOrderItem, models.TableNameTenant, models.TableNameTenantLedger, models.TableNameContentAccess)
|
||||
database.Truncate(
|
||||
ctx,
|
||||
s.DB,
|
||||
models.TableNameUser,
|
||||
models.TableNameOrder,
|
||||
models.TableNameOrderItem,
|
||||
models.TableNameTenant,
|
||||
models.TableNameTenantLedger,
|
||||
models.TableNameContentAccess,
|
||||
)
|
||||
|
||||
// Creator
|
||||
creator := &models.User{Username: "creator_ext", Balance: 0}
|
||||
|
||||
@@ -52,27 +52,27 @@ func (s *TenantTestSuite) Test_Follow() {
|
||||
models.TenantQuery.WithContext(ctx).Create(t)
|
||||
|
||||
Convey("should follow tenant", func() {
|
||||
err := Tenant.Follow(ctx, cast.ToString(t.ID))
|
||||
err := Tenant.Follow(ctx, u.ID, cast.ToString(t.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify stats
|
||||
profile, err := Tenant.GetPublicProfile(ctx, cast.ToString(t.ID))
|
||||
profile, err := Tenant.GetPublicProfile(ctx, u.ID, cast.ToString(t.ID))
|
||||
So(err, ShouldBeNil)
|
||||
So(profile.IsFollowing, ShouldBeTrue)
|
||||
So(profile.Stats.Followers, ShouldEqual, 1)
|
||||
|
||||
// List Followed
|
||||
list, err := Tenant.ListFollowed(ctx)
|
||||
list, err := Tenant.ListFollowed(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(list), ShouldEqual, 1)
|
||||
So(list[0].Name, ShouldEqual, "Tenant A")
|
||||
|
||||
// Unfollow
|
||||
err = Tenant.Unfollow(ctx, cast.ToString(t.ID))
|
||||
err = Tenant.Unfollow(ctx, u.ID, cast.ToString(t.ID))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify
|
||||
profile, err = Tenant.GetPublicProfile(ctx, cast.ToString(t.ID))
|
||||
profile, err = Tenant.GetPublicProfile(ctx, u.ID, cast.ToString(t.ID))
|
||||
So(err, ShouldBeNil)
|
||||
So(profile.IsFollowing, ShouldBeFalse)
|
||||
So(profile.Stats.Followers, ShouldEqual, 0)
|
||||
|
||||
@@ -87,7 +87,7 @@ func (s *UserTestSuite) Test_Me() {
|
||||
// Mock context with user ID
|
||||
ctx = context.WithValue(ctx, consts.CtxKeyUser, userID)
|
||||
|
||||
user, err := User.Me(ctx)
|
||||
user, err := User.Me(ctx, userID)
|
||||
So(err, ShouldBeNil)
|
||||
So(user.ID, ShouldEqual, resp.User.ID)
|
||||
So(user.Phone, ShouldEqual, phone)
|
||||
@@ -95,7 +95,7 @@ func (s *UserTestSuite) Test_Me() {
|
||||
|
||||
Convey("should fail without auth", func() {
|
||||
// No user ID in context
|
||||
user, err := User.Me(ctx)
|
||||
user, err := User.Me(ctx, 0)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(user, ShouldBeNil)
|
||||
})
|
||||
@@ -118,11 +118,11 @@ func (s *UserTestSuite) Test_Update() {
|
||||
Bio: "New Bio",
|
||||
Gender: consts.GenderMale,
|
||||
}
|
||||
err := User.Update(ctx, form)
|
||||
err := User.Update(ctx, userID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify
|
||||
u, _ := User.Me(ctx)
|
||||
u, _ := User.Me(ctx, userID)
|
||||
So(u.Nickname, ShouldEqual, "NewName")
|
||||
So(u.Bio, ShouldEqual, "New Bio")
|
||||
So(u.Gender, ShouldEqual, consts.GenderMale)
|
||||
@@ -145,11 +145,11 @@ func (s *UserTestSuite) Test_RealName() {
|
||||
Realname: "张三",
|
||||
IDCard: "123456789012345678",
|
||||
}
|
||||
err := User.RealName(ctx, form)
|
||||
err := User.RealName(ctx, userID, form)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Verify
|
||||
u, _ := User.Me(ctx)
|
||||
u, _ := User.Me(ctx, userID)
|
||||
So(u.IsRealNameVerified, ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
@@ -175,7 +175,7 @@ func (s *UserTestSuite) Test_GetNotifications() {
|
||||
})
|
||||
|
||||
Convey("should return notifications", func() {
|
||||
list, err := User.GetNotifications(ctx, "all")
|
||||
list, err := User.GetNotifications(ctx, userID, "all")
|
||||
So(err, ShouldBeNil)
|
||||
So(len(list), ShouldEqual, 1)
|
||||
So(list[0].Title, ShouldEqual, "Welcome")
|
||||
|
||||
@@ -58,7 +58,7 @@ func (s *WalletTestSuite) Test_GetWallet() {
|
||||
models.OrderQuery.WithContext(ctx).Create(o1, o2)
|
||||
|
||||
Convey("should return balance and transactions", func() {
|
||||
res, err := Wallet.GetWallet(ctx)
|
||||
res, err := Wallet.GetWallet(ctx, u.ID)
|
||||
So(err, ShouldBeNil)
|
||||
So(res.Balance, ShouldEqual, 50.0)
|
||||
So(len(res.Transactions), ShouldEqual, 2)
|
||||
@@ -82,7 +82,7 @@ func (s *WalletTestSuite) Test_Recharge() {
|
||||
|
||||
Convey("should create recharge order", func() {
|
||||
form := &user_dto.RechargeForm{Amount: 100.0}
|
||||
res, err := Wallet.Recharge(ctx, form)
|
||||
res, err := Wallet.Recharge(ctx, u.ID, form)
|
||||
So(err, ShouldBeNil)
|
||||
So(res.OrderID, ShouldNotBeEmpty)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user