package api import ( "net/http" "time" "github.com/gin-gonic/gin" "gorm.io/gorm" "everypublish/server/internal/api/handlers" "everypublish/server/internal/api/middleware" "everypublish/server/internal/cache" "everypublish/server/internal/config" "everypublish/server/internal/credentials" "everypublish/server/internal/platform" "everypublish/server/internal/ws" ) // Router 装配 gin 路由 func Router(cfg *config.Config, db *gorm.DB, rds *cache.Redis, hub *ws.Hub, dsp *ws.Dispatcher) *gin.Engine { r := gin.New() r.Use(gin.Logger(), gin.Recovery()) r.GET("/health", func(c *gin.Context) { dbOK := false if sqlDB, err := db.DB(); err == nil { dbOK = sqlDB.Ping() == nil } redisOK := rds.Ping() == nil c.JSON(http.StatusOK, gin.H{ "status": "ok", "service": "everypublish-server", "time": time.Now().Format(time.RFC3339), "db": dbOK, "redis": redisOK, }) }) r.GET("/ws/browser", ws.HandleBrowser(cfg, hub)) api := r.Group("/api/v1") api.Use(middleware.Audit(db)) api.GET("/runtime/status", middleware.AuthRequired(cfg), func(c *gin.Context) { mode := cfg.ExecutorMode adapters := []string(nil) if dsp != nil && dsp.Registry != nil { adapters = dsp.Registry.Names() } dbOK := false if sqlDB, err := db.DB(); err == nil { dbOK = sqlDB.Ping() == nil } c.JSON(http.StatusOK, gin.H{"code": 0, "message": "ok", "data": gin.H{ "executorMode": mode, "adapters": adapters, "db": dbOK, "redis": rds.Ping() == nil, }}) }) authH := &handlers.AuthHandler{DB: db, Rds: rds, Cfg: cfg} wsH := &handlers.WorkspaceHandler{DB: db} mbH := &handlers.MemberHandler{DB: db, Cfg: cfg} adH := &handlers.AuditHandler{DB: db} var registry *platform.Registry var credentialStore *credentials.Store if dsp != nil { registry = dsp.Registry credentialStore = dsp.Credentials } accH := &handlers.AccountHandler{DB: db, Hub: hub, Registry: registry, Credentials: credentialStore, ExecutorMode: cfg.ExecutorMode} matH := &handlers.MaterialHandler{DB: db, Cfg: cfg} tskH := &handlers.TaskHandler{DB: db, Dispatcher: dsp} chlH := &handlers.ChallengeHandler{DB: db, Hub: hub, Registry: registry, ExecutorMode: cfg.ExecutorMode} chlH.StartLoginPoll = accH.StartLoginPoll ntfH := &handlers.NotificationHandler{DB: db} auth := api.Group("/auth") { auth.POST("/register", authH.Register) auth.POST("/login", authH.Login) auth.POST("/refresh", authH.Refresh) auth.POST("/logout", middleware.AuthRequired(cfg), authH.Logout) auth.POST("/password", middleware.AuthRequired(cfg), authH.ChangePassword) auth.GET("/me", middleware.AuthRequired(cfg), authH.Me) auth.POST("/switch-workspace/:id", middleware.AuthRequired(cfg), authH.SwitchWorkspace) } wsg := api.Group("/workspaces", middleware.AuthRequired(cfg)) { wsg.POST("", wsH.Create) wsg.GET("", wsH.List) wsg.PUT("/:id", wsH.Update) } mb := api.Group("/members", middleware.AuthRequired(cfg)) { mb.GET("", mbH.List) mb.POST("/invite", mbH.Invite) mb.POST("/join", mbH.Join) mb.PUT("/:id/role", mbH.UpdateRole) mb.DELETE("/:id", mbH.Remove) } ad := api.Group("/audit-logs", middleware.AuthRequired(cfg)) { ad.GET("", adH.List) } acc := api.Group("/accounts", middleware.AuthRequired(cfg)) { acc.GET("", accH.List) acc.POST("", middleware.WorkspaceRoles("owner", "admin", "operator"), accH.Create) acc.PUT("/:id", middleware.WorkspaceRoles("owner", "admin", "operator"), accH.Update) acc.DELETE("/:id", middleware.WorkspaceRoles("owner", "admin"), accH.Delete) acc.POST("/:id/bind", middleware.WorkspaceRoles("owner", "admin", "operator"), accH.Bind) acc.POST("/:id/credentials", middleware.WorkspaceRoles("owner", "admin", "operator"), accH.ImportCredentials) acc.POST("/:id/check", middleware.WorkspaceRoles("owner", "admin", "operator"), accH.Check) acc.POST("/:id/unbind", middleware.WorkspaceRoles("owner", "admin"), accH.Unbind) } mat := api.Group("/materials", middleware.AuthRequired(cfg)) { mat.GET("", matH.List) mat.POST("", middleware.WorkspaceRoles("owner", "admin", "operator"), matH.Upload) mat.DELETE("/:id", middleware.WorkspaceRoles("owner", "admin", "operator"), matH.Delete) mat.GET("/:id/url", matH.URL) } files := api.Group("/files") { files.GET("/:token", matH.ServeFile) } tsk := api.Group("/tasks", middleware.AuthRequired(cfg)) { tsk.GET("", tskH.List) tsk.POST("", middleware.WorkspaceRoles("owner", "admin", "operator"), tskH.Create) tsk.GET("/:id/events", tskH.Events) tsk.GET("/:id", tskH.Get) tsk.PUT("/:id", middleware.WorkspaceRoles("owner", "admin", "operator"), tskH.Update) tsk.DELETE("/:id", middleware.WorkspaceRoles("owner", "admin", "operator"), tskH.Delete) tsk.POST("/:id/submit", middleware.WorkspaceRoles("owner", "admin", "operator"), tskH.Submit) tsk.POST("/:id/approve", middleware.WorkspaceRoles("owner", "admin", "reviewer"), tskH.Approve) tsk.POST("/:id/reject", middleware.WorkspaceRoles("owner", "admin", "reviewer"), tskH.Reject) tsk.POST("/:id/resubmit", middleware.WorkspaceRoles("owner", "admin", "operator"), tskH.Resubmit) tsk.POST("/:id/retry", middleware.WorkspaceRoles("owner", "admin", "operator"), tskH.Retry) tsk.POST("/:id/cancel", middleware.WorkspaceRoles("owner", "admin", "operator"), tskH.Cancel) } chl := api.Group("/challenges", middleware.AuthRequired(cfg)) { chl.GET("", chlH.List) chl.POST("/:id/solve", middleware.WorkspaceRoles("owner", "admin", "operator", "reviewer"), chlH.Solve) chl.POST("/:id/resend", middleware.WorkspaceRoles("owner", "admin", "operator", "reviewer"), chlH.Resend) chl.POST("/:id/suspend", middleware.WorkspaceRoles("owner", "admin", "operator", "reviewer"), chlH.Suspend) } ntf := api.Group("/notifications", middleware.AuthRequired(cfg)) { ntf.GET("", ntfH.List) ntf.POST("/:id/read", ntfH.Read) ntf.POST("/read-all", ntfH.ReadAll) } admH := &handlers.AdminHandler{DB: db, Hub: hub} adm := api.Group("/admin", middleware.AuthRequired(cfg), middleware.AdminRequired()) { adm.GET("/tenants", admH.Tenants) adm.PUT("/tenants/:id/status", admH.TenantStatus) } return r }