| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- package handler
- import (
- "github.com/Wei-Shaw/sub2api/internal/handler/dto"
- "github.com/Wei-Shaw/sub2api/internal/pkg/response"
- middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- )
- // SubscriptionSummaryItem represents a subscription item in summary
- type SubscriptionSummaryItem struct {
- ID int64 `json:"id"`
- GroupID int64 `json:"group_id"`
- GroupName string `json:"group_name"`
- Status string `json:"status"`
- DailyUsedUSD float64 `json:"daily_used_usd,omitempty"`
- DailyLimitUSD float64 `json:"daily_limit_usd,omitempty"`
- WeeklyUsedUSD float64 `json:"weekly_used_usd,omitempty"`
- WeeklyLimitUSD float64 `json:"weekly_limit_usd,omitempty"`
- MonthlyUsedUSD float64 `json:"monthly_used_usd,omitempty"`
- MonthlyLimitUSD float64 `json:"monthly_limit_usd,omitempty"`
- ExpiresAt *string `json:"expires_at,omitempty"`
- }
- // SubscriptionProgressInfo represents subscription with progress info
- type SubscriptionProgressInfo struct {
- Subscription *dto.UserSubscription `json:"subscription"`
- Progress *service.SubscriptionProgress `json:"progress"`
- }
- // SubscriptionHandler handles user subscription operations
- type SubscriptionHandler struct {
- subscriptionService *service.SubscriptionService
- }
- // NewSubscriptionHandler creates a new user subscription handler
- func NewSubscriptionHandler(subscriptionService *service.SubscriptionService) *SubscriptionHandler {
- return &SubscriptionHandler{
- subscriptionService: subscriptionService,
- }
- }
- // List handles listing current user's subscriptions
- // GET /api/v1/subscriptions
- func (h *SubscriptionHandler) List(c *gin.Context) {
- subject, ok := middleware2.GetAuthSubjectFromContext(c)
- if !ok {
- response.Unauthorized(c, "User not found in context")
- return
- }
- subscriptions, err := h.subscriptionService.ListUserSubscriptions(c.Request.Context(), subject.UserID)
- if err != nil {
- response.ErrorFrom(c, err)
- return
- }
- out := make([]dto.UserSubscription, 0, len(subscriptions))
- for i := range subscriptions {
- out = append(out, *dto.UserSubscriptionFromService(&subscriptions[i]))
- }
- response.Success(c, out)
- }
- // GetActive handles getting current user's active subscriptions
- // GET /api/v1/subscriptions/active
- func (h *SubscriptionHandler) GetActive(c *gin.Context) {
- subject, ok := middleware2.GetAuthSubjectFromContext(c)
- if !ok {
- response.Unauthorized(c, "User not found in context")
- return
- }
- subscriptions, err := h.subscriptionService.ListActiveUserSubscriptions(c.Request.Context(), subject.UserID)
- if err != nil {
- response.ErrorFrom(c, err)
- return
- }
- out := make([]dto.UserSubscription, 0, len(subscriptions))
- for i := range subscriptions {
- out = append(out, *dto.UserSubscriptionFromService(&subscriptions[i]))
- }
- response.Success(c, out)
- }
- // GetProgress handles getting subscription progress for current user
- // GET /api/v1/subscriptions/progress
- func (h *SubscriptionHandler) GetProgress(c *gin.Context) {
- subject, ok := middleware2.GetAuthSubjectFromContext(c)
- if !ok {
- response.Unauthorized(c, "User not found in context")
- return
- }
- // Get all active subscriptions with progress
- subscriptions, err := h.subscriptionService.ListActiveUserSubscriptions(c.Request.Context(), subject.UserID)
- if err != nil {
- response.ErrorFrom(c, err)
- return
- }
- result := make([]SubscriptionProgressInfo, 0, len(subscriptions))
- for i := range subscriptions {
- sub := &subscriptions[i]
- progress, err := h.subscriptionService.GetSubscriptionProgress(c.Request.Context(), sub.ID)
- if err != nil {
- // Skip subscriptions with errors
- continue
- }
- result = append(result, SubscriptionProgressInfo{
- Subscription: dto.UserSubscriptionFromService(sub),
- Progress: progress,
- })
- }
- response.Success(c, result)
- }
- // GetSummary handles getting a summary of current user's subscription status
- // GET /api/v1/subscriptions/summary
- func (h *SubscriptionHandler) GetSummary(c *gin.Context) {
- subject, ok := middleware2.GetAuthSubjectFromContext(c)
- if !ok {
- response.Unauthorized(c, "User not found in context")
- return
- }
- // Get all active subscriptions
- subscriptions, err := h.subscriptionService.ListActiveUserSubscriptions(c.Request.Context(), subject.UserID)
- if err != nil {
- response.ErrorFrom(c, err)
- return
- }
- var totalUsed float64
- items := make([]SubscriptionSummaryItem, 0, len(subscriptions))
- for _, sub := range subscriptions {
- item := SubscriptionSummaryItem{
- ID: sub.ID,
- GroupID: sub.GroupID,
- Status: sub.Status,
- DailyUsedUSD: sub.DailyUsageUSD,
- WeeklyUsedUSD: sub.WeeklyUsageUSD,
- MonthlyUsedUSD: sub.MonthlyUsageUSD,
- }
- // Add group info if preloaded
- if sub.Group != nil {
- item.GroupName = sub.Group.Name
- if sub.Group.DailyLimitUSD != nil {
- item.DailyLimitUSD = *sub.Group.DailyLimitUSD
- }
- if sub.Group.WeeklyLimitUSD != nil {
- item.WeeklyLimitUSD = *sub.Group.WeeklyLimitUSD
- }
- if sub.Group.MonthlyLimitUSD != nil {
- item.MonthlyLimitUSD = *sub.Group.MonthlyLimitUSD
- }
- }
- // Format expiration time
- if !sub.ExpiresAt.IsZero() {
- formatted := sub.ExpiresAt.Format("2006-01-02T15:04:05Z07:00")
- item.ExpiresAt = &formatted
- }
- // Track total usage (use monthly as the most comprehensive)
- totalUsed += sub.MonthlyUsageUSD
- items = append(items, item)
- }
- summary := struct {
- ActiveCount int `json:"active_count"`
- TotalUsedUSD float64 `json:"total_used_usd"`
- Subscriptions []SubscriptionSummaryItem `json:"subscriptions"`
- }{
- ActiveCount: len(subscriptions),
- TotalUsedUSD: totalUsed,
- Subscriptions: items,
- }
- response.Success(c, summary)
- }
|