feat: Implement notification service and integrate with user interactions
- Added notification service to handle sending and listing notifications. - Integrated notification sending on user follow and order payment events. - Updated user service to include fetching followed tenants. - Enhanced content service to manage access control for content assets. - Implemented logic for listing content topics based on genre. - Updated creator service to manage content updates and pricing. - Improved order service to include detailed order information and notifications. - Added tests for notification CRUD operations and order details.
This commit is contained in:
@@ -67,14 +67,28 @@ func (s *creator) Dashboard(ctx context.Context) (*creator_dto.DashboardStats, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Mock stats for now or query
|
||||
// Followers: count tenant_users
|
||||
followers, _ := models.TenantUserQuery.WithContext(ctx).Where(models.TenantUserQuery.TenantID.Eq(tid)).Count()
|
||||
|
||||
// Revenue: sum tenant_ledgers (income)
|
||||
var revenue float64
|
||||
// GORM doesn't have a direct Sum method in Gen yet easily accessible without raw SQL or result mapping
|
||||
// But we can use underlying DB
|
||||
models.TenantLedgerQuery.WithContext(ctx).UnderlyingDB().
|
||||
Model(&models.TenantLedger{}).
|
||||
Where("tenant_id = ? AND type = ?", tid, consts.TenantLedgerTypeDebitPurchase).
|
||||
Select("COALESCE(SUM(amount), 0)").
|
||||
Scan(&revenue)
|
||||
|
||||
// Pending Refunds: count orders in refunding
|
||||
pendingRefunds, _ := models.OrderQuery.WithContext(ctx).
|
||||
Where(models.OrderQuery.TenantID.Eq(tid), models.OrderQuery.Status.Eq(consts.OrderStatusRefunding)).
|
||||
Count()
|
||||
|
||||
stats := &creator_dto.DashboardStats{
|
||||
TotalFollowers: creator_dto.IntStatItem{Value: int(followers)},
|
||||
TotalRevenue: creator_dto.FloatStatItem{Value: 0},
|
||||
PendingRefunds: 0,
|
||||
TotalRevenue: creator_dto.FloatStatItem{Value: revenue / 100.0},
|
||||
PendingRefunds: int(pendingRefunds),
|
||||
NewMessages: 0,
|
||||
}
|
||||
return stats, nil
|
||||
@@ -173,7 +187,73 @@ func (s *creator) CreateContent(ctx context.Context, form *creator_dto.ContentCr
|
||||
}
|
||||
|
||||
func (s *creator) UpdateContent(ctx context.Context, id string, form *creator_dto.ContentUpdateForm) error {
|
||||
return nil
|
||||
tid, err := s.getTenantID(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cid := cast.ToInt64(id)
|
||||
uid := cast.ToInt64(ctx.Value(consts.CtxKeyUser))
|
||||
|
||||
return models.Q.Transaction(func(tx *models.Query) error {
|
||||
// 1. Check Ownership
|
||||
c, err := tx.Content.WithContext(ctx).Where(tx.Content.ID.Eq(cid), tx.Content.TenantID.Eq(tid)).First()
|
||||
if err != nil {
|
||||
return errorx.ErrRecordNotFound
|
||||
}
|
||||
|
||||
// 2. Update Content
|
||||
_, err = tx.Content.WithContext(ctx).Where(tx.Content.ID.Eq(cid)).Updates(&models.Content{
|
||||
Title: form.Title,
|
||||
Genre: form.Genre,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 3. Update Price
|
||||
// Check if price exists
|
||||
count, _ := tx.ContentPrice.WithContext(ctx).Where(tx.ContentPrice.ContentID.Eq(cid)).Count()
|
||||
newPrice := int64(form.Price * 100)
|
||||
if count > 0 {
|
||||
_, err = tx.ContentPrice.WithContext(ctx).Where(tx.ContentPrice.ContentID.Eq(cid)).UpdateSimple(tx.ContentPrice.PriceAmount.Value(newPrice))
|
||||
} else {
|
||||
err = tx.ContentPrice.WithContext(ctx).Create(&models.ContentPrice{
|
||||
TenantID: tid,
|
||||
UserID: c.UserID,
|
||||
ContentID: cid,
|
||||
PriceAmount: newPrice,
|
||||
Currency: consts.CurrencyCNY,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 4. Update Assets (Full replacement strategy)
|
||||
if len(form.MediaIDs) > 0 {
|
||||
_, err = tx.ContentAsset.WithContext(ctx).Where(tx.ContentAsset.ContentID.Eq(cid)).Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var assets []*models.ContentAsset
|
||||
for i, mid := range form.MediaIDs {
|
||||
assets = append(assets, &models.ContentAsset{
|
||||
TenantID: tid,
|
||||
UserID: uid,
|
||||
ContentID: cid,
|
||||
AssetID: cast.ToInt64(mid),
|
||||
Sort: int32(i),
|
||||
Role: consts.ContentAssetRoleMain, // Default to main
|
||||
})
|
||||
}
|
||||
if err := tx.ContentAsset.WithContext(ctx).Create(assets...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *creator) DeleteContent(ctx context.Context, id string) error {
|
||||
|
||||
Reference in New Issue
Block a user