fix: populate dataUsedBytes in subscription list endpoints

The list subscription endpoints (user and admin) were returning
dataUsedBytes as 0 because ListUserSubscriptionsUseCase lacked
QuotaService integration. Added GetSubscriptionQuotaPreloaded to
the QuotaService interface to avoid redundant DB lookups when
subscription and plan are already fetched, and wired it into the
list use case to populate traffic usage data in DTOs.
This commit is contained in:
orris-inc
2026-03-02 14:22:41 +08:00
parent 68030af644
commit 53482ab6ad
3 changed files with 33 additions and 0 deletions

View File

@@ -38,10 +38,16 @@ type ListUserSubscriptionsUseCase struct {
planRepo subscription.PlanRepository
userRepo user.Repository
onlineDeviceCounter OnlineDeviceCounter // optional, nil-safe
quotaService QuotaService // optional, nil-safe
logger logger.Interface
baseURL string
}
// SetQuotaService sets the quota service for data usage reporting (optional).
func (uc *ListUserSubscriptionsUseCase) SetQuotaService(qs QuotaService) {
uc.quotaService = qs
}
func NewListUserSubscriptionsUseCase(
subscriptionRepo subscription.SubscriptionRepository,
planRepo subscription.PlanRepository,
@@ -169,6 +175,15 @@ func (uc *ListUserSubscriptionsUseCase) Execute(ctx context.Context, query ListU
if count, ok := onlineCounts[sub.ID()]; ok {
opts = append(opts, dto.WithOnlineDeviceCount(count))
}
// Set data usage from QuotaService
if uc.quotaService != nil && plan != nil {
quota, err := uc.quotaService.GetSubscriptionQuotaPreloaded(ctx, sub, plan)
if err != nil {
uc.logger.Warnw("failed to get subscription quota", "error", err, "subscription_id", sub.ID())
} else if quota != nil {
opts = append(opts, dto.WithDataUsage(quota.UsedBytes, quota.LimitBytes))
}
}
result := dto.ToSubscriptionDTO(sub, plan, subscriptionUser, uc.baseURL, opts...)
dtos = append(dtos, result)

View File

@@ -31,6 +31,10 @@ type QuotaService interface {
// GetSubscriptionQuota returns the quota usage for a single subscription.
GetSubscriptionQuota(ctx context.Context, subscriptionID uint) (*QuotaCheckResult, error)
// GetSubscriptionQuotaPreloaded returns quota usage using pre-fetched subscription and plan.
// This avoids redundant DB lookups when subscription and plan are already available (e.g., in list endpoints).
GetSubscriptionQuotaPreloaded(ctx context.Context, sub *subscription.Subscription, plan *subscription.Plan) (*QuotaCheckResult, error)
// GetUserForwardQuota returns quota usage for all Forward-type subscriptions of a user.
GetUserForwardQuota(ctx context.Context, userID uint) ([]*QuotaCheckResult, error)
@@ -119,6 +123,19 @@ func (s *QuotaServiceImpl) GetSubscriptionQuota(ctx context.Context, subscriptio
return s.buildQuotaResult(ctx, sub, plan)
}
// GetSubscriptionQuotaPreloaded returns quota usage using pre-fetched subscription and plan.
func (s *QuotaServiceImpl) GetSubscriptionQuotaPreloaded(ctx context.Context, sub *subscription.Subscription, plan *subscription.Plan) (*QuotaCheckResult, error) {
if sub == nil || plan == nil {
return nil, nil
}
if sub.Status() == vo.StatusSuspended {
return nil, nil
}
return s.buildQuotaResult(ctx, sub, plan)
}
// GetUserForwardQuota returns quota usage for all Forward-type subscriptions of a user.
func (s *QuotaServiceImpl) GetUserForwardQuota(ctx context.Context, userID uint) ([]*QuotaCheckResult, error) {
return s.getUserQuotaByPlanType(ctx, userID, vo.PlanTypeForward)

View File

@@ -1379,6 +1379,7 @@ func (c *Container) initRemainingHandlers() {
// Set QuotaService on use cases that need real-time usage data
ucs.getSubscriptionUC.SetQuotaService(ucs.quotaService)
ucs.listUserSubscriptionsUC.SetQuotaService(ucs.quotaService)
ucs.updateSubscriptionUC.SetQuotaService(ucs.quotaService)
// Initialize forward quota middleware with QuotaService