mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
402 lines
11 KiB
Go
402 lines
11 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
"bugulma/backend/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type SubscriptionHandler struct {
|
|
subscriptionService *service.SubscriptionService
|
|
}
|
|
|
|
func NewSubscriptionHandler(subscriptionService *service.SubscriptionService) *SubscriptionHandler {
|
|
return &SubscriptionHandler{
|
|
subscriptionService: subscriptionService,
|
|
}
|
|
}
|
|
|
|
// GetSubscription returns the current user's subscription
|
|
// @Summary Get current subscription
|
|
// @Tags subscription
|
|
// @Produce json
|
|
// @Success 200 {object} domain.Subscription
|
|
// @Router /api/v1/subscription [get]
|
|
func (h *SubscriptionHandler) GetSubscription(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
subscription, err := h.subscriptionService.GetSubscription(c.Request.Context(), userID.(string))
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, subscription)
|
|
}
|
|
|
|
// CreateSubscription creates a new subscription
|
|
// @Summary Create subscription
|
|
// @Tags subscription
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body CreateSubscriptionRequest true "Subscription request"
|
|
// @Success 201 {object} domain.Subscription
|
|
// @Router /api/v1/subscription [post]
|
|
func (h *SubscriptionHandler) CreateSubscription(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
var req CreateSubscriptionRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
subscription, err := h.subscriptionService.CreateSubscription(
|
|
c.Request.Context(),
|
|
userID.(string),
|
|
domain.SubscriptionPlan(req.Plan),
|
|
domain.BillingPeriod(req.BillingPeriod),
|
|
)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, subscription)
|
|
}
|
|
|
|
type CreateSubscriptionRequest struct {
|
|
Plan string `json:"plan" binding:"required"`
|
|
BillingPeriod string `json:"billingPeriod" binding:"required"`
|
|
}
|
|
|
|
// GetPlans returns available subscription plans
|
|
// @Summary Get available plans
|
|
// @Tags subscription
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/subscription/plans [get]
|
|
func (h *SubscriptionHandler) GetPlans(c *gin.Context) {
|
|
plans := map[string]interface{}{
|
|
"free": map[string]interface{}{
|
|
"id": "free",
|
|
"name": "Free",
|
|
"description": "Perfect for getting started",
|
|
"price": map[string]int{
|
|
"monthly": 0,
|
|
"yearly": 0,
|
|
},
|
|
"features": []string{},
|
|
"limits": map[string]interface{}{
|
|
"organizations": 3,
|
|
"users": 1,
|
|
"storage": 100,
|
|
"apiCalls": 1000,
|
|
},
|
|
},
|
|
"basic": map[string]interface{}{
|
|
"id": "basic",
|
|
"name": "Basic",
|
|
"description": "For small businesses",
|
|
"price": map[string]int{
|
|
"monthly": 29,
|
|
"yearly": 290,
|
|
},
|
|
"features": []string{"team_collaboration"},
|
|
"limits": map[string]interface{}{
|
|
"organizations": 10,
|
|
"users": 5,
|
|
"storage": 1000,
|
|
"apiCalls": 10000,
|
|
},
|
|
},
|
|
"professional": map[string]interface{}{
|
|
"id": "professional",
|
|
"name": "Professional",
|
|
"description": "For growing businesses",
|
|
"price": map[string]int{
|
|
"monthly": 99,
|
|
"yearly": 990,
|
|
},
|
|
"features": []string{
|
|
"unlimited_organizations",
|
|
"advanced_analytics",
|
|
"api_access",
|
|
"team_collaboration",
|
|
"priority_support",
|
|
},
|
|
"limits": map[string]interface{}{
|
|
"organizations": -1,
|
|
"users": 20,
|
|
"storage": 10000,
|
|
"apiCalls": 100000,
|
|
},
|
|
"popular": true,
|
|
},
|
|
"enterprise": map[string]interface{}{
|
|
"id": "enterprise",
|
|
"name": "Enterprise",
|
|
"description": "For large organizations",
|
|
"price": map[string]int{
|
|
"monthly": 499,
|
|
"yearly": 4990,
|
|
},
|
|
"features": []string{
|
|
"unlimited_organizations",
|
|
"advanced_analytics",
|
|
"api_access",
|
|
"custom_domain",
|
|
"sso",
|
|
"team_collaboration",
|
|
"dedicated_support",
|
|
"white_label",
|
|
},
|
|
"limits": map[string]interface{}{
|
|
"organizations": -1,
|
|
"users": -1,
|
|
"storage": -1,
|
|
"apiCalls": -1,
|
|
"customDomains": 5,
|
|
},
|
|
},
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"plans": plans})
|
|
}
|
|
|
|
// UpgradeSubscription upgrades a subscription
|
|
// @Summary Upgrade subscription
|
|
// @Tags subscription
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body UpgradeSubscriptionRequest true "Upgrade request"
|
|
// @Success 200 {object} domain.Subscription
|
|
// @Router /api/v1/subscription/upgrade [post]
|
|
func (h *SubscriptionHandler) UpgradeSubscription(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
var req UpgradeSubscriptionRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
subscription, err := h.subscriptionService.GetSubscription(c.Request.Context(), userID.(string))
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
updated, err := h.subscriptionService.UpdateSubscription(
|
|
c.Request.Context(),
|
|
subscription.ID,
|
|
domain.SubscriptionPlan(req.Plan),
|
|
)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, updated)
|
|
}
|
|
|
|
type UpgradeSubscriptionRequest struct {
|
|
Plan string `json:"plan" binding:"required"`
|
|
}
|
|
|
|
// CancelSubscription cancels a subscription
|
|
// @Summary Cancel subscription
|
|
// @Tags subscription
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/subscription/cancel [post]
|
|
func (h *SubscriptionHandler) CancelSubscription(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
subscription, err := h.subscriptionService.GetSubscription(c.Request.Context(), userID.(string))
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
if err := h.subscriptionService.CancelSubscription(c.Request.Context(), subscription.ID); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Subscription canceled"})
|
|
}
|
|
|
|
// GetInvoices returns invoices for the current user
|
|
// @Summary Get invoices
|
|
// @Tags subscription
|
|
// @Produce json
|
|
// @Param limit query int false "Limit" default(10)
|
|
// @Param offset query int false "Offset" default(0)
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/subscription/invoices [get]
|
|
func (h *SubscriptionHandler) GetInvoices(c *gin.Context) {
|
|
// TODO: Implement invoice retrieval
|
|
c.JSON(http.StatusOK, gin.H{"invoices": []interface{}{}, "total": 0})
|
|
}
|
|
|
|
// GetPaymentMethods returns payment methods for the current user
|
|
// @Summary Get payment methods
|
|
// @Tags subscription
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/subscription/payment-methods [get]
|
|
func (h *SubscriptionHandler) GetPaymentMethods(c *gin.Context) {
|
|
// TODO: Implement payment method retrieval
|
|
c.JSON(http.StatusOK, gin.H{"paymentMethods": []interface{}{}})
|
|
}
|
|
|
|
// AddPaymentMethod adds a payment method
|
|
// @Summary Add payment method
|
|
// @Tags subscription
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body AddPaymentMethodRequest true "Payment method request"
|
|
// @Success 201 {object} domain.PaymentMethod
|
|
// @Router /api/v1/subscription/payment-methods [post]
|
|
func (h *SubscriptionHandler) AddPaymentMethod(c *gin.Context) {
|
|
// TODO: Implement payment method addition
|
|
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
|
}
|
|
|
|
type AddPaymentMethodRequest struct {
|
|
Type string `json:"type" binding:"required"`
|
|
}
|
|
|
|
// Webhook handles payment provider webhooks
|
|
// @Summary Handle webhook
|
|
// @Tags subscription
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]string
|
|
// @Router /api/v1/subscription/webhook [post]
|
|
func (h *SubscriptionHandler) Webhook(c *gin.Context) {
|
|
// TODO: Implement webhook handling
|
|
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
|
}
|
|
|
|
// GetUsageStats returns usage statistics for the current user
|
|
// @Summary Get usage statistics
|
|
// @Tags subscription
|
|
// @Produce json
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/subscription/usage [get]
|
|
func (h *SubscriptionHandler) GetUsageStats(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
stats, err := h.subscriptionService.GetUsageStats(c.Request.Context(), userID.(string))
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"usage": stats})
|
|
}
|
|
|
|
// CheckFeature checks if user has access to a feature
|
|
// @Summary Check feature access
|
|
// @Tags subscription
|
|
// @Produce json
|
|
// @Param feature query string true "Feature name"
|
|
// @Success 200 {object} map[string]bool
|
|
// @Router /api/v1/subscription/check-feature [get]
|
|
func (h *SubscriptionHandler) CheckFeature(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
feature := c.Query("feature")
|
|
if feature == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Feature parameter required"})
|
|
return
|
|
}
|
|
|
|
hasAccess, err := h.subscriptionService.CheckFeatureAccess(
|
|
c.Request.Context(),
|
|
userID.(string),
|
|
service.SubscriptionFeature(feature),
|
|
)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"hasAccess": hasAccess})
|
|
}
|
|
|
|
// CheckLimits checks if user is within limits
|
|
// @Summary Check limits
|
|
// @Tags subscription
|
|
// @Produce json
|
|
// @Param limitType query string true "Limit type"
|
|
// @Param current query int true "Current usage"
|
|
// @Success 200 {object} map[string]interface{}
|
|
// @Router /api/v1/subscription/check-limits [get]
|
|
func (h *SubscriptionHandler) CheckLimits(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
|
|
return
|
|
}
|
|
|
|
limitTypeStr := c.Query("limitType")
|
|
currentStr := c.Query("current")
|
|
|
|
if limitTypeStr == "" || currentStr == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "limitType and current parameters required"})
|
|
return
|
|
}
|
|
|
|
current, err := strconv.ParseInt(currentStr, 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid current value"})
|
|
return
|
|
}
|
|
|
|
withinLimits, remaining, err := h.subscriptionService.CheckLimits(
|
|
c.Request.Context(),
|
|
userID.(string),
|
|
domain.UsageLimitType(limitTypeStr),
|
|
current,
|
|
)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"withinLimits": withinLimits,
|
|
"remaining": remaining,
|
|
})
|
|
}
|