Bug fixes: - Detached context for GetAccountConcurrencyBatch (prevent all-zero on request cancel) - Filter soft-deleted users in GetByGroupID - Stripe CSP policy (allow Stripe.js in script-src and frame-src) - WebSearch API key validation on save - RECHARGING status in payment result success check - Windows test fixes (logger Sync deadlock, config path escaping) Feature enhancements: - Webhook multi-instance dispatch (extractOutTradeNo + GetWebhookProvider) - EasyPay mobile H5 payment (device param + PayURL2) - SSE error propagation in WebSearch emulation - AccountStatsCost DTO field for admin usage logs - Plans sort by sort_order instead of created_at - UsageMapHook for streaming response usage data - apicompat Instructions field passthrough - EffectiveLoadFactor for ops concurrency/metrics - Usage billing RETURNING balance for notify system - BulkUpdate mixed channel warning with details - println to slog migration in auth cache - Wire ProviderSet cleanup - CI cache-dependency-path optimization Frontend: - Refund eligibility check per provider (canRequestRefund) - Plan sort_order editing - Dead code cleanup (simulate_claude_max, client_affinity) - GroupsView platform switch guard - channels features_config API type - UsageView account_stats_cost export
105 lines
3.7 KiB
Go
105 lines
3.7 KiB
Go
package routes
|
|
|
|
import (
|
|
"github.com/Wei-Shaw/sub2api/internal/handler"
|
|
"github.com/Wei-Shaw/sub2api/internal/handler/admin"
|
|
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// RegisterPaymentRoutes registers all payment-related routes:
|
|
// user-facing endpoints, webhook endpoints, and admin endpoints.
|
|
func RegisterPaymentRoutes(
|
|
v1 *gin.RouterGroup,
|
|
paymentHandler *handler.PaymentHandler,
|
|
webhookHandler *handler.PaymentWebhookHandler,
|
|
adminPaymentHandler *admin.PaymentHandler,
|
|
jwtAuth middleware.JWTAuthMiddleware,
|
|
adminAuth middleware.AdminAuthMiddleware,
|
|
settingService *service.SettingService,
|
|
) {
|
|
// --- User-facing payment endpoints (authenticated) ---
|
|
authenticated := v1.Group("/payment")
|
|
authenticated.Use(gin.HandlerFunc(jwtAuth))
|
|
authenticated.Use(middleware.BackendModeUserGuard(settingService))
|
|
{
|
|
authenticated.GET("/config", paymentHandler.GetPaymentConfig)
|
|
authenticated.GET("/checkout-info", paymentHandler.GetCheckoutInfo)
|
|
authenticated.GET("/plans", paymentHandler.GetPlans)
|
|
authenticated.GET("/channels", paymentHandler.GetChannels)
|
|
authenticated.GET("/limits", paymentHandler.GetLimits)
|
|
|
|
orders := authenticated.Group("/orders")
|
|
{
|
|
orders.POST("", paymentHandler.CreateOrder)
|
|
orders.POST("/verify", paymentHandler.VerifyOrder)
|
|
orders.GET("/my", paymentHandler.GetMyOrders)
|
|
orders.GET("/:id", paymentHandler.GetOrder)
|
|
orders.POST("/:id/cancel", paymentHandler.CancelOrder)
|
|
orders.POST("/:id/refund-request", paymentHandler.RequestRefund)
|
|
orders.GET("/refund-eligible-providers", paymentHandler.GetRefundEligibleProviders)
|
|
}
|
|
}
|
|
|
|
// --- Public payment endpoints (no auth) ---
|
|
// Payment result page needs to verify order status without login
|
|
// (user session may have expired during provider redirect).
|
|
public := v1.Group("/payment/public")
|
|
{
|
|
public.POST("/orders/verify", paymentHandler.VerifyOrderPublic)
|
|
}
|
|
|
|
// --- Webhook endpoints (no auth) ---
|
|
webhook := v1.Group("/payment/webhook")
|
|
{
|
|
// EasyPay sends GET callbacks with query params
|
|
webhook.GET("/easypay", webhookHandler.EasyPayNotify)
|
|
webhook.POST("/easypay", webhookHandler.EasyPayNotify)
|
|
webhook.POST("/alipay", webhookHandler.AlipayNotify)
|
|
webhook.POST("/wxpay", webhookHandler.WxpayNotify)
|
|
webhook.POST("/stripe", webhookHandler.StripeWebhook)
|
|
}
|
|
|
|
// --- Admin payment endpoints (admin auth) ---
|
|
adminGroup := v1.Group("/admin/payment")
|
|
adminGroup.Use(gin.HandlerFunc(adminAuth))
|
|
{
|
|
// Dashboard
|
|
adminGroup.GET("/dashboard", adminPaymentHandler.GetDashboard)
|
|
|
|
// Config
|
|
adminGroup.GET("/config", adminPaymentHandler.GetConfig)
|
|
adminGroup.PUT("/config", adminPaymentHandler.UpdateConfig)
|
|
|
|
// Orders
|
|
adminOrders := adminGroup.Group("/orders")
|
|
{
|
|
adminOrders.GET("", adminPaymentHandler.ListOrders)
|
|
adminOrders.GET("/:id", adminPaymentHandler.GetOrderDetail)
|
|
adminOrders.POST("/:id/cancel", adminPaymentHandler.CancelOrder)
|
|
adminOrders.POST("/:id/retry", adminPaymentHandler.RetryFulfillment)
|
|
adminOrders.POST("/:id/refund", adminPaymentHandler.ProcessRefund)
|
|
}
|
|
|
|
// Subscription Plans
|
|
plans := adminGroup.Group("/plans")
|
|
{
|
|
plans.GET("", adminPaymentHandler.ListPlans)
|
|
plans.POST("", adminPaymentHandler.CreatePlan)
|
|
plans.PUT("/:id", adminPaymentHandler.UpdatePlan)
|
|
plans.DELETE("/:id", adminPaymentHandler.DeletePlan)
|
|
}
|
|
|
|
// Provider Instances
|
|
providers := adminGroup.Group("/providers")
|
|
{
|
|
providers.GET("", adminPaymentHandler.ListProviders)
|
|
providers.POST("", adminPaymentHandler.CreateProvider)
|
|
providers.PUT("/:id", adminPaymentHandler.UpdateProvider)
|
|
providers.DELETE("/:id", adminPaymentHandler.DeleteProvider)
|
|
}
|
|
}
|
|
}
|