仅已吊销或已过期可删,有效授权自动跳过;单条删除同步限制。 Co-authored-by: Cursor <cursoragent@cursor.com>
264 lines
10 KiB
Go
264 lines
10 KiB
Go
package router
|
||
|
||
import (
|
||
"backend/config"
|
||
"backend/internal/controller/analytics"
|
||
"backend/internal/controller/auth"
|
||
"backend/internal/controller/customer"
|
||
"backend/internal/controller/entitlement"
|
||
"backend/internal/controller/license"
|
||
"backend/internal/controller/order"
|
||
"backend/internal/controller/plan"
|
||
"backend/internal/controller/product"
|
||
"backend/internal/controller/setting"
|
||
"backend/middleware"
|
||
"strings"
|
||
|
||
"github.com/gin-contrib/gzip"
|
||
"github.com/gin-gonic/gin"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// register 同时注册带和不带 trailing slash 的路由 // Logan.Li
|
||
func register(r gin.IRoutes, method, relativePath string, handlers ...gin.HandlerFunc) {
|
||
isParamRoute := strings.Contains(relativePath, ":")
|
||
|
||
switch method {
|
||
case "GET":
|
||
r.GET(relativePath, handlers...)
|
||
if !isParamRoute {
|
||
r.GET(relativePath+"/", handlers...)
|
||
}
|
||
case "POST":
|
||
r.POST(relativePath, handlers...)
|
||
if !isParamRoute {
|
||
r.POST(relativePath+"/", handlers...)
|
||
}
|
||
case "PUT":
|
||
r.PUT(relativePath, handlers...)
|
||
if !isParamRoute {
|
||
r.PUT(relativePath+"/", handlers...)
|
||
}
|
||
case "DELETE":
|
||
r.DELETE(relativePath, handlers...)
|
||
if !isParamRoute {
|
||
r.DELETE(relativePath+"/", handlers...)
|
||
}
|
||
case "PATCH":
|
||
r.PATCH(relativePath, handlers...)
|
||
if !isParamRoute {
|
||
r.PATCH(relativePath+"/", handlers...)
|
||
}
|
||
}
|
||
}
|
||
|
||
// SetupRouter 初始化路由 // Logan.Li
|
||
func SetupRouter(db *gorm.DB, cfg *config.Config) *gin.Engine {
|
||
gin.SetMode(cfg.Mode)
|
||
|
||
r := gin.Default()
|
||
r.RedirectTrailingSlash = false
|
||
r.RedirectFixedPath = false
|
||
|
||
// Gzip 压缩中间件 // Logan.Li
|
||
r.Use(gzip.Gzip(gzip.DefaultCompression))
|
||
|
||
// CORS 中间件 // Logan.Li
|
||
r.Use(middleware.CORSMiddleware(cfg))
|
||
|
||
// 存活探针(不查库) // Logan.Li
|
||
r.GET("/health", func(c *gin.Context) {
|
||
c.JSON(200, gin.H{"code": 0, "message": "ok", "data": nil})
|
||
})
|
||
r.GET("/healthz", func(c *gin.Context) {
|
||
c.JSON(200, gin.H{"status": "alive"})
|
||
})
|
||
// 就绪探针:检查数据库可达 // Logan.Li
|
||
r.GET("/readyz", func(c *gin.Context) {
|
||
sqlDB, err := db.DB()
|
||
if err != nil || sqlDB.Ping() != nil {
|
||
c.JSON(503, gin.H{"status": "db unreachable"})
|
||
return
|
||
}
|
||
c.JSON(200, gin.H{"status": "ready"})
|
||
})
|
||
|
||
// 初始化控制器 // Logan.Li
|
||
authController := auth.NewAuthController(db, cfg)
|
||
productController := product.NewProductController(db)
|
||
customerController := customer.NewCustomerController(db)
|
||
licenseController := license.NewLicenseController(db, cfg)
|
||
planController := plan.NewPlanController(db)
|
||
orderController := order.NewOrderController(db)
|
||
entitlementController := entitlement.NewEntitlementController(db)
|
||
analyticsController := analytics.NewAnalyticsController(db)
|
||
settingController := setting.NewSettingController(db)
|
||
|
||
api := r.Group("/api")
|
||
{
|
||
// ============ 认证路由(无需 JWT) ============
|
||
authGroup := api.Group("/auth")
|
||
{
|
||
register(authGroup, "POST", "/login", middleware.RateLimit(0.2, 5), authController.Login)
|
||
}
|
||
|
||
// ============ 客户端授权契约(无需认证,供外部工具调用) ============
|
||
clientAPI := api.Group("/v1")
|
||
{
|
||
licLimit := middleware.RateLimit(2, 30)
|
||
checkoutLimit := middleware.RateLimit(0.5, 10)
|
||
webhookLimit := middleware.RateLimit(1, 20)
|
||
|
||
// License 验证 / 激活 / 停用 / 心跳
|
||
register(clientAPI, "POST", "/license/verify", licLimit, licenseController.Verify)
|
||
register(clientAPI, "POST", "/license/activate", licLimit, licenseController.ActivateDevice)
|
||
register(clientAPI, "POST", "/license/deactivate", licLimit, licenseController.Deactivate)
|
||
register(clientAPI, "POST", "/license/heartbeat", licLimit, licenseController.Heartbeat)
|
||
register(clientAPI, "POST", "/license/devices", licLimit, licenseController.ListDevices)
|
||
|
||
// 产品定价查询(展示用)
|
||
register(clientAPI, "GET", "/products/code/:code", productController.GetByCode)
|
||
clientAPI.GET("/products/:product_id/plans", planController.GetByProduct)
|
||
|
||
// 订单与支付(客户端购买入口 + 支付回调)
|
||
register(clientAPI, "POST", "/orders", checkoutLimit, orderController.CreateOrder)
|
||
register(clientAPI, "POST", "/checkout", checkoutLimit, orderController.Checkout)
|
||
register(clientAPI, "POST", "/purchase/claim", checkoutLimit, orderController.ClaimPurchase)
|
||
register(clientAPI, "POST", "/webhooks/payment", webhookLimit, orderController.PaymentWebhook)
|
||
register(clientAPI, "GET", "/webhooks/waffo", orderController.WaffoWebhookReady)
|
||
register(clientAPI, "POST", "/webhooks/waffo", webhookLimit, orderController.WaffoWebhook)
|
||
register(clientAPI, "GET", "/purchase/success", orderController.PurchaseSuccess)
|
||
register(clientAPI, "POST", "/purchase/check", checkoutLimit, orderController.CheckDuplicatePurchase)
|
||
register(clientAPI, "POST", "/purchase/status", checkoutLimit, orderController.CheckPurchaseStatus)
|
||
|
||
// 客户权益查询(通过邮箱)
|
||
register(clientAPI, "GET", "/entitlements/my", checkoutLimit, entitlementController.GetByEmail)
|
||
}
|
||
|
||
// ============ 需要认证的管理路由 ============
|
||
protected := api.Group("", middleware.AuthMiddleware(cfg))
|
||
{
|
||
// 认证相关
|
||
register(protected, "GET", "/auth/me", authController.Me)
|
||
register(protected, "PUT", "/auth/password", authController.ChangePassword)
|
||
|
||
// 产品管理
|
||
products := protected.Group("/products")
|
||
{
|
||
register(products, "GET", "", productController.List)
|
||
register(products, "GET", "/all", productController.GetAll)
|
||
register(products, "POST", "", productController.Create)
|
||
register(products, "GET", "/:id", productController.Get)
|
||
register(products, "PUT", "/:id", productController.Update)
|
||
register(products, "DELETE", "/:id", productController.Delete)
|
||
register(products, "PATCH", "/:id/status", productController.UpdateStatus)
|
||
}
|
||
|
||
// 客户管理
|
||
customers := protected.Group("/customers")
|
||
{
|
||
register(customers, "GET", "", customerController.List)
|
||
register(customers, "GET", "/all", customerController.GetAll)
|
||
register(customers, "POST", "", customerController.Create)
|
||
register(customers, "GET", "/:id", customerController.Get)
|
||
register(customers, "PUT", "/:id", customerController.Update)
|
||
register(customers, "DELETE", "/:id", customerController.Delete)
|
||
register(customers, "PATCH", "/:id/status", customerController.UpdateStatus)
|
||
}
|
||
|
||
// License 管理
|
||
licenses := protected.Group("/licenses")
|
||
{
|
||
register(licenses, "GET", "", licenseController.List)
|
||
register(licenses, "POST", "", licenseController.Create)
|
||
register(licenses, "POST", "/offline", licenseController.IssueOffline)
|
||
register(licenses, "GET", "/offline/public-key", licenseController.OfflinePublicKey)
|
||
register(licenses, "GET", "/export", licenseController.Export)
|
||
register(licenses, "POST", "/batch-delete", licenseController.BatchDelete)
|
||
register(licenses, "GET", "/:id", licenseController.Get)
|
||
register(licenses, "PUT", "/:id", licenseController.Update)
|
||
register(licenses, "DELETE", "/:id", licenseController.Delete)
|
||
register(licenses, "POST", "/:id/renew", licenseController.Renew)
|
||
register(licenses, "POST", "/:id/revoke", licenseController.Revoke)
|
||
register(licenses, "POST", "/:id/suspend", licenseController.Suspend)
|
||
register(licenses, "POST", "/:id/activate", licenseController.Activate)
|
||
register(licenses, "GET", "/:id/activations", licenseController.GetActivations)
|
||
register(licenses, "POST", "/:id/activations/:activationId/offline", licenseController.ForceOffline)
|
||
}
|
||
|
||
// 定价计划管理
|
||
plans := protected.Group("/plans")
|
||
{
|
||
register(plans, "GET", "", planController.List)
|
||
register(plans, "POST", "", planController.Create)
|
||
register(plans, "PUT", "/:id", planController.Update)
|
||
register(plans, "DELETE", "/:id", planController.Delete)
|
||
register(plans, "PATCH", "/:id/status", planController.ToggleStatus)
|
||
}
|
||
|
||
// 订单管理
|
||
orders := protected.Group("/orders")
|
||
{
|
||
register(orders, "GET", "", orderController.List)
|
||
register(orders, "GET", "/:id", orderController.GetDetail)
|
||
register(orders, "POST", "/manual-grant", orderController.ManualGrant)
|
||
}
|
||
|
||
// 客户权益管理
|
||
entitlements := protected.Group("/entitlements")
|
||
{
|
||
register(entitlements, "GET", "", entitlementController.List)
|
||
register(entitlements, "GET", "/:id", entitlementController.Get)
|
||
register(entitlements, "POST", "/:id/revoke", entitlementController.Revoke)
|
||
register(entitlements, "POST", "/:id/renew", entitlementController.Renew)
|
||
}
|
||
|
||
// 仪表板与数据分析
|
||
dashboard := protected.Group("/dashboard")
|
||
{
|
||
register(dashboard, "GET", "/stats", analyticsController.GetDashboardStats)
|
||
register(dashboard, "GET", "/expiring", analyticsController.GetExpiringLicenses)
|
||
register(dashboard, "GET", "/activities", analyticsController.GetRecentActivities)
|
||
register(dashboard, "GET", "/online-stats", analyticsController.GetOnlineStats)
|
||
register(dashboard, "GET", "/revenue", analyticsController.GetRevenueStats)
|
||
}
|
||
|
||
analyticsGroup := protected.Group("/analytics")
|
||
{
|
||
register(analyticsGroup, "GET", "/license-growth", analyticsController.GetLicenseGrowth)
|
||
register(analyticsGroup, "GET", "/license-growth-detail", analyticsController.GetLicenseGrowthDetail)
|
||
register(analyticsGroup, "GET", "/product-distribution", analyticsController.GetProductDistribution)
|
||
register(analyticsGroup, "GET", "/geo-distribution", analyticsController.GetGeoDistribution)
|
||
register(analyticsGroup, "GET", "/platform-distribution", analyticsController.GetPlatformDistribution)
|
||
}
|
||
|
||
// 日志审计与系统设置
|
||
logs := protected.Group("/logs")
|
||
{
|
||
register(logs, "GET", "", settingController.ListAuditLogs)
|
||
register(logs, "DELETE", "/clear", settingController.ClearAuditLogs)
|
||
}
|
||
|
||
system := protected.Group("/settings")
|
||
{
|
||
register(system, "GET", "", settingController.Get)
|
||
register(system, "PUT", "", settingController.Update)
|
||
register(system, "GET", "/waffo", settingController.GetWaffo)
|
||
register(system, "PUT", "/waffo", settingController.UpdateWaffo)
|
||
register(system, "POST", "/waffo/test", settingController.DebugWaffo)
|
||
register(system, "GET", "/license-templates", settingController.ListLicenseTemplates)
|
||
register(system, "POST", "/license-templates", settingController.SaveLicenseTemplate)
|
||
register(system, "DELETE", "/license-templates/:id", settingController.DeleteLicenseTemplate)
|
||
}
|
||
|
||
// 支付调试(与 settings/waffo/test 同一 handler) // Logan.Li
|
||
paymentGroup := protected.Group("/payment")
|
||
{
|
||
register(paymentGroup, "POST", "/waffo/debug", settingController.DebugWaffo)
|
||
}
|
||
}
|
||
}
|
||
|
||
return r
|
||
}
|