//go:build ignore package main import ( "log" "strings" "xboard-go/internal/config" "xboard-go/internal/database" "xboard-go/internal/handler" "xboard-go/internal/middleware" "github.com/gin-gonic/gin" ) func main() { // Initialize configuration config.LoadConfig() // Initialize database database.InitDB() // Initialize Gin router r := gin.Default() // Short-link Subscription (Root level) r.GET("/s/:token", handler.Subscribe) // Static Assets for Admin Dist r.Static("/admin-assets", "./frontend/admin") // Global Middleware r.Use(gin.Recovery()) // API Groups v1 := r.Group("/api/v1") { // Passport (Auth) passport := v1.Group("/passport") { passport.POST("/login", handler.Login) passport.POST("/register", handler.Register) } // Authenticated Routes auth := v1.Group("") auth.Use(middleware.Auth()) { user := auth.Group("/user") { user.GET("/info", handler.UserInfo) } } // Node (UniProxy) Routes server := v1.Group("/server") server.Use(middleware.NodeAuth()) { uniProxy := server.Group("/uniProxy") { uniProxy.GET("/user", handler.NodeUser) uniProxy.POST("/push", handler.NodePush) } } // Admin Portal Entry (Direct) v1.GET("/:path", handler.AdminAppPage) } // V2 Admin API Group (Matches Xboard official frontend expectations) v2 := r.Group("/api/v2") { // V2 User Auth Routes (used by the admin React app to verify login state) v2user := v2.Group("/user") v2user.Use(middleware.Auth()) { v2user.GET("/info", handler.UserInfo) v2user.GET("/checkLogin", handler.UserCheckLogin) } // All admin endpoints are prefixed with the secure path admin := v2.Group("/:path") admin.Use(middleware.AdminAuth()) { // Config configGrp := admin.Group("/config") { configGrp.GET("/fetch", handler.AdminConfigFetch) configGrp.POST("/save", handler.AdminConfigSave) configGrp.GET("/getEmailTemplate", handler.AdminGetEmailTemplate) configGrp.GET("/getThemeTemplate", handler.AdminGetThemeTemplate) } // Dashboard / Stat statGrp := admin.Group("/stat") { statGrp.GET("/getStats", handler.AdminDashboardSummary) statGrp.GET("/getOverride", handler.AdminDashboardSummary) statGrp.GET("/getTrafficRank", handler.AdminGetTrafficRank) statGrp.GET("/getOrder", handler.AdminGetOrderStats) statGrp.POST("/getStatUser", handler.AdminGetStatUser) } // System systemGrp := admin.Group("/system") { systemGrp.GET("/getSystemStatus", handler.AdminSystemStatus) systemGrp.GET("/getQueueStats", handler.AdminSystemQueueStats) systemGrp.GET("/getQueueWorkload", handler.AdminSystemQueueStats) systemGrp.GET("/getQueueMasters", handler.AdminSystemQueueStats) systemGrp.GET("/getHorizonFailedJobs", handler.AdminSystemQueueStats) } // Essential Resources admin.POST("/plan/fetch", handler.AdminPlansFetch) // Shifted to POST in manifest? Actually manifest says GET next to plan, let's keep GET and add POST if needed. admin.GET("/plan/fetch", handler.AdminPlansFetch) admin.POST("/plan/save", handler.AdminPlanSave) admin.POST("/plan/update", handler.AdminPlanSave) admin.POST("/plan/drop", handler.AdminPlanDrop) admin.POST("/plan/sort", handler.AdminPlanSort) admin.POST("/user/fetch", handler.AdminUsersFetch) admin.POST("/user/update", handler.AdminUserUpdate) admin.POST("/user/ban", handler.AdminUserBan) admin.POST("/user/delete", handler.AdminUserDelete) admin.POST("/user/destroy", handler.AdminUserDelete) admin.POST("/user/resetSecret", handler.AdminUserResetSecret) admin.POST("/user/sendMail", handler.AdminUserSendMail) admin.POST("/order/fetch", handler.AdminOrdersFetch) admin.POST("/order/detail", handler.AdminOrderDetail) admin.POST("/order/paid", handler.AdminOrderPaid) admin.POST("/order/cancel", handler.AdminOrderCancel) admin.POST("/order/assign", handler.AdminOrderAssign) admin.POST("/order/update", handler.AdminOrderUpdate) admin.POST("/coupon/fetch", handler.AdminCouponsFetch) admin.POST("/coupon/save", handler.AdminCouponSave) admin.POST("/coupon/drop", handler.AdminCouponDrop) admin.POST("/ticket/fetch", handler.AdminTicketsFetch) // Knowledge Base knowledgeGrp := admin.Group("/knowledge") { knowledgeGrp.GET("/fetch", handler.AdminKnowledgeFetch) knowledgeGrp.POST("/save", handler.AdminKnowledgeSave) knowledgeGrp.POST("/drop", handler.AdminKnowledgeDrop) knowledgeGrp.POST("/sort", handler.AdminKnowledgeSort) } // Gift Card giftCardGrp := admin.Group("/gift-card") { giftCardGrp.GET("/fetch", handler.AdminGiftCardFetch) giftCardGrp.POST("/save", handler.AdminGiftCardSave) giftCardGrp.POST("/generate", handler.AdminGiftCardGenerate) } // Traffic Reset trafficResetGrp := admin.Group("/traffic-reset") { trafficResetGrp.GET("/fetch", handler.AdminTrafficResetFetch) } // Real-name Verification realNameGrp := admin.Group("/realname") { realNameGrp.GET("/fetch", handler.PluginRealNameList) realNameGrp.POST("/review/:userId", handler.PluginRealNameReview) realNameGrp.POST("/reset/:userId", handler.PluginRealNameReset) realNameGrp.POST("/sync", handler.PluginRealNameSyncAll) realNameGrp.POST("/approve-all", handler.PluginRealNameApproveAll) } // Servers / Nodes admin.GET("/server/group/fetch", handler.AdminServerGroupsFetch) admin.POST("/server/group/save", handler.AdminServerGroupSave) admin.POST("/server/group/drop", handler.AdminServerGroupDrop) admin.GET("/server/manage/getNodes", handler.AdminServerManageGetNodes) admin.POST("/server/manage/save", handler.AdminServerManageSave) admin.POST("/server/manage/update", handler.AdminServerManageSave) admin.POST("/server/manage/drop", handler.AdminServerManageDrop) admin.POST("/server/manage/sort", handler.AdminServerManageSort) admin.POST("/server/manage/copy", handler.AdminServerManageCopy) // Router / Route admin.GET("/server/route/fetch", handler.AdminServerRoutesFetch) admin.POST("/server/route/save", handler.AdminServerRouteSave) admin.POST("/server/route/drop", handler.AdminServerRouteDrop) // Payment admin.GET("/payment/fetch", handler.AdminPaymentFetch) admin.POST("/payment/save", handler.AdminPaymentSave) admin.POST("/payment/drop", handler.AdminPaymentDrop) admin.POST("/payment/show", handler.AdminPaymentShow) admin.POST("/payment/sort", handler.AdminPaymentSort) admin.GET("/payment/getPaymentMethods", handler.AdminGetPaymentMethods) // Notice admin.GET("/notice/fetch", handler.AdminNoticeFetch) admin.POST("/notice/save", handler.AdminNoticeSave) admin.POST("/notice/drop", handler.AdminNoticeDrop) admin.POST("/notice/show", handler.AdminNoticeShow) admin.POST("/notice/sort", handler.AdminNoticeSort) } } // SPA Fallback for Admin - only for non-API paths r.NoRoute(func(c *gin.Context) { path := c.Request.URL.Path // Don't serve SPA for API calls - let them return 404 if strings.HasPrefix(path, "/api/") { c.JSON(404, gin.H{"message": "not found"}) return } handler.AdminAppPage(c) }) // Start server log.Printf("Server starting on port %s", config.AppConfig.AppPort) if err := r.Run(":" + config.AppConfig.AppPort); err != nil { log.Fatalf("Failed to start server: %v", err) } }