admin.go 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. // Package routes provides HTTP route registration and handlers.
  2. package routes
  3. import (
  4. "github.com/Wei-Shaw/sub2api/internal/handler"
  5. "github.com/Wei-Shaw/sub2api/internal/pkg/response"
  6. "github.com/Wei-Shaw/sub2api/internal/server/middleware"
  7. "github.com/Wei-Shaw/sub2api/internal/service"
  8. "github.com/gin-gonic/gin"
  9. )
  10. // RegisterAdminRoutes 注册管理员路由
  11. func RegisterAdminRoutes(
  12. v1 *gin.RouterGroup,
  13. h *handler.Handlers,
  14. adminAuth middleware.AdminAuthMiddleware,
  15. auditLog middleware.AuditLogMiddleware,
  16. stepUpAuth middleware.StepUpAuthMiddleware,
  17. settingService *service.SettingService,
  18. panelRateLimiter *middleware.PanelRateLimiter,
  19. userService *service.UserService,
  20. ) {
  21. // 插件 UI 使用短时能力 URL,仅提供经过安装校验的静态资源。
  22. v1.GET("/plugin-ui/:token/*path", h.Admin.Plugin.ServeUIAsset)
  23. admin := v1.Group("/admin")
  24. admin.Use(gin.HandlerFunc(adminAuth))
  25. // 面板全局按用户限流(默认管理员豁免,可在系统设置中关闭豁免)
  26. admin.Use(panelRateLimiter.Global())
  27. // 审计中间件挂在认证之后:所有管理面变更类操作 + 敏感读取入审计日志
  28. admin.Use(gin.HandlerFunc(auditLog))
  29. admin.Use(middleware.UserHierarchyGuard(userService))
  30. admin.Use(middleware.AdminComplianceGuard(settingService))
  31. {
  32. // 部署与运营合规确认
  33. registerAdminComplianceRoutes(admin, h)
  34. // 仪表盘
  35. registerDashboardRoutes(admin, h)
  36. // 用户管理
  37. registerUserManagementRoutes(admin, h)
  38. registerRelayManagementRoutes(admin, h)
  39. // 分组管理
  40. registerGroupRoutes(admin, h)
  41. // 账号管理
  42. registerAccountRoutes(admin, h, stepUpAuth)
  43. // 公告管理
  44. registerAnnouncementRoutes(admin, h)
  45. // OpenAI OAuth
  46. registerOpenAIOAuthRoutes(admin, h)
  47. // Gemini OAuth
  48. registerGeminiOAuthRoutes(admin, h)
  49. // Antigravity OAuth
  50. registerAntigravityOAuthRoutes(admin, h)
  51. // Grok OAuth
  52. registerGrokOAuthRoutes(admin, h)
  53. // 国产供应商(kimi/zhipu/deepseek)额度与余额
  54. registerCNProviderRoutes(admin, h)
  55. // 代理管理
  56. registerProxyRoutes(admin, h, stepUpAuth)
  57. // 卡密管理
  58. registerRedeemCodeRoutes(admin, h)
  59. // 优惠码管理
  60. registerPromoCodeRoutes(admin, h)
  61. // 系统设置
  62. registerSettingsRoutes(admin, h)
  63. // 数据管理
  64. registerDataManagementRoutes(admin, h, stepUpAuth)
  65. // 数据库备份恢复
  66. registerBackupRoutes(admin, h, stepUpAuth)
  67. // 运维监控(Ops)
  68. registerOpsRoutes(admin, h)
  69. // 系统管理
  70. registerSystemRoutes(admin, h, stepUpAuth)
  71. // 订阅管理
  72. registerSubscriptionRoutes(admin, h)
  73. // 使用记录管理
  74. registerUsageRoutes(admin, h)
  75. // 用户属性管理
  76. registerUserAttributeRoutes(admin, h)
  77. // 错误透传规则管理
  78. registerErrorPassthroughRoutes(admin, h)
  79. // TLS 指纹模板管理
  80. registerTLSFingerprintProfileRoutes(admin, h)
  81. // 本地进程插件管理
  82. registerPluginRoutes(admin, h, stepUpAuth)
  83. // API Key 管理
  84. registerAdminAPIKeyRoutes(admin, h)
  85. // 定时测试计划
  86. registerScheduledTestRoutes(admin, h)
  87. // 渠道管理
  88. registerChannelRoutes(admin, h)
  89. // 渠道监控
  90. registerChannelMonitorRoutes(admin, h, settingService)
  91. registerChannelMonitorV2Routes(admin, h, settingService)
  92. // 风控中心
  93. registerContentModerationRoutes(admin, h)
  94. registerSecurityPolicyRoutes(admin, h)
  95. // 分组安全策略(自定义词包 + 会话解封)
  96. // 全站模型定价覆盖
  97. registerGlobalPricingRoutes(admin, h)
  98. // 账号健康分
  99. registerAccountHealthRoutes(admin, h)
  100. // 毛利看板与熔断
  101. registerMarginRoutes(admin, h)
  102. // 分级路由
  103. registerTieredRoutingRoutes(admin, h)
  104. // 烧钱防护
  105. registerSpendGuardRoutes(admin, h)
  106. // 工单系统
  107. registerTicketAdminRoutes(admin, h)
  108. // 账单导出
  109. registerBillingExportAdminRoutes(admin, h)
  110. // 独立提示词输入审计
  111. registerPromptAuditRoutes(admin, h)
  112. // 邀请返利(专属用户管理)
  113. registerAffiliateRoutes(admin, h)
  114. // 操作审计日志
  115. registerAuditLogRoutes(admin, h, stepUpAuth)
  116. }
  117. }
  118. func registerPromptAuditRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  119. promptAudit := admin.Group("/prompt-audit")
  120. {
  121. promptAudit.GET("/config", h.Admin.PromptAudit.GetConfig)
  122. promptAudit.PUT("/config", h.Admin.PromptAudit.UpdateConfig)
  123. promptAudit.POST("/endpoints/probe", h.Admin.PromptAudit.ProbeEndpoint)
  124. promptAudit.GET("/runtime", h.Admin.PromptAudit.GetRuntime)
  125. promptAudit.GET("/events", h.Admin.PromptAudit.ListEvents)
  126. promptAudit.GET("/events/:id", h.Admin.PromptAudit.GetEvent)
  127. promptAudit.DELETE("/events/:id", h.Admin.PromptAudit.DeleteEvent)
  128. promptAudit.POST("/events/batch-delete", h.Admin.PromptAudit.BatchDelete)
  129. promptAudit.POST("/events/delete-preview", h.Admin.PromptAudit.DeletePreview)
  130. promptAudit.POST("/events/delete-by-filter", h.Admin.PromptAudit.DeleteByFilter)
  131. }
  132. }
  133. func registerAuditLogRoutes(admin *gin.RouterGroup, h *handler.Handlers, _ middleware.StepUpAuthMiddleware) {
  134. auditLogs := admin.Group("/audit-logs")
  135. {
  136. auditLogs.GET("", h.Admin.AuditLog.List)
  137. auditLogs.GET("/:id", h.Admin.AuditLog.Get)
  138. // 清空需现场 TOTP 校验(在 handler 内强制),不复用 step-up sudo 窗口
  139. auditLogs.POST("/clear", h.Admin.AuditLog.Clear)
  140. }
  141. }
  142. func registerAdminComplianceRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  143. compliance := admin.Group("/compliance")
  144. {
  145. compliance.GET("", h.Admin.Compliance.GetStatus)
  146. compliance.POST("/accept", h.Admin.Compliance.Accept)
  147. }
  148. }
  149. func registerContentModerationRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  150. risk := admin.Group("/risk-control")
  151. {
  152. risk.GET("/config", h.Admin.ContentModeration.GetConfig)
  153. risk.PUT("/config", h.Admin.ContentModeration.UpdateConfig)
  154. risk.POST("/api-keys/test", h.Admin.ContentModeration.TestAPIKeys)
  155. risk.GET("/status", h.Admin.ContentModeration.GetStatus)
  156. risk.GET("/logs", h.Admin.ContentModeration.ListLogs)
  157. risk.POST("/users/:user_id/unban", h.Admin.ContentModeration.UnbanUser)
  158. risk.DELETE("/hashes", h.Admin.ContentModeration.DeleteFlaggedHash)
  159. risk.DELETE("/hashes/all", h.Admin.ContentModeration.ClearFlaggedHashes)
  160. }
  161. }
  162. func registerSecurityPolicyRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  163. secpol := admin.Group("/security-policy")
  164. {
  165. secpol.GET("/keywords/builtin", h.Admin.SecurityPolicy.ListBuiltin)
  166. secpol.GET("/keywords", h.Admin.SecurityPolicy.ListKeywords)
  167. secpol.POST("/keywords", h.Admin.SecurityPolicy.CreateKeyword)
  168. secpol.PUT("/keywords/:id", h.Admin.SecurityPolicy.UpdateKeyword)
  169. secpol.DELETE("/keywords/:id", h.Admin.SecurityPolicy.DeleteKeyword)
  170. secpol.POST("/sessions/unblock", h.Admin.SecurityPolicy.UnblockSession)
  171. }
  172. }
  173. func registerAdminAPIKeyRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  174. apiKeys := admin.Group("/api-keys")
  175. {
  176. apiKeys.PUT("/:id", h.Admin.APIKey.UpdateGroup)
  177. }
  178. }
  179. func registerOpsRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  180. ops := admin.Group("/ops")
  181. {
  182. // Realtime ops signals
  183. ops.GET("/concurrency", h.Admin.Ops.GetConcurrencyStats)
  184. ops.GET("/user-concurrency", h.Admin.Ops.GetUserConcurrencyStats)
  185. ops.GET("/account-availability", h.Admin.Ops.GetAccountAvailability)
  186. ops.GET("/realtime-traffic", h.Admin.Ops.GetRealtimeTrafficSummary)
  187. // Alerts (rules + events)
  188. ops.GET("/alert-rules", h.Admin.Ops.ListAlertRules)
  189. ops.POST("/alert-rules", h.Admin.Ops.CreateAlertRule)
  190. ops.PUT("/alert-rules/:id", h.Admin.Ops.UpdateAlertRule)
  191. ops.DELETE("/alert-rules/:id", h.Admin.Ops.DeleteAlertRule)
  192. ops.GET("/alert-events", h.Admin.Ops.ListAlertEvents)
  193. ops.GET("/alert-events/:id", h.Admin.Ops.GetAlertEvent)
  194. ops.PUT("/alert-events/:id/status", h.Admin.Ops.UpdateAlertEventStatus)
  195. ops.POST("/alert-silences", h.Admin.Ops.CreateAlertSilence)
  196. // Email notification config (DB-backed)
  197. ops.GET("/email-notification/config", h.Admin.Ops.GetEmailNotificationConfig)
  198. ops.PUT("/email-notification/config", h.Admin.Ops.UpdateEmailNotificationConfig)
  199. // Runtime settings (DB-backed)
  200. runtime := ops.Group("/runtime")
  201. {
  202. runtime.GET("/alert", h.Admin.Ops.GetAlertRuntimeSettings)
  203. runtime.PUT("/alert", h.Admin.Ops.UpdateAlertRuntimeSettings)
  204. runtime.GET("/logging", h.Admin.Ops.GetRuntimeLogConfig)
  205. runtime.PUT("/logging", h.Admin.Ops.UpdateRuntimeLogConfig)
  206. runtime.POST("/logging/reset", h.Admin.Ops.ResetRuntimeLogConfig)
  207. }
  208. // Advanced settings (DB-backed)
  209. ops.GET("/advanced-settings", h.Admin.Ops.GetAdvancedSettings)
  210. ops.PUT("/advanced-settings", h.Admin.Ops.UpdateAdvancedSettings)
  211. // Settings group (DB-backed)
  212. settings := ops.Group("/settings")
  213. {
  214. settings.GET("/metric-thresholds", h.Admin.Ops.GetMetricThresholds)
  215. settings.PUT("/metric-thresholds", h.Admin.Ops.UpdateMetricThresholds)
  216. }
  217. // WebSocket realtime (QPS/TPS)
  218. ws := ops.Group("/ws")
  219. {
  220. ws.GET("/qps", h.Admin.Ops.QPSWSHandler)
  221. }
  222. // Error logs (legacy)
  223. ops.GET("/errors", h.Admin.Ops.GetErrorLogs)
  224. ops.GET("/errors/:id", h.Admin.Ops.GetErrorLogByID)
  225. ops.PUT("/errors/:id/resolve", h.Admin.Ops.UpdateErrorResolution)
  226. // Request errors (client-visible failures)
  227. ops.GET("/request-errors", h.Admin.Ops.ListRequestErrors)
  228. ops.GET("/request-errors/:id", h.Admin.Ops.GetRequestError)
  229. ops.GET("/request-errors/:id/upstream-errors", h.Admin.Ops.ListRequestErrorUpstreamErrors)
  230. ops.PUT("/request-errors/:id/resolve", h.Admin.Ops.ResolveRequestError)
  231. // Bounded ingress-admission rejection aggregates.
  232. ops.GET("/ingress-rejections", h.Admin.Ops.ListIngressRejects)
  233. ops.GET("/ingress-rejections/health", h.Admin.Ops.GetIngressRejectHealth)
  234. ops.GET("/auth-cache-invalidation/health", h.Admin.Ops.GetAuthCacheInvalidationHealth)
  235. // Upstream errors (independent upstream failures)
  236. ops.GET("/upstream-errors", h.Admin.Ops.ListUpstreamErrors)
  237. ops.GET("/upstream-errors/:id", h.Admin.Ops.GetUpstreamError)
  238. ops.PUT("/upstream-errors/:id/resolve", h.Admin.Ops.ResolveUpstreamError)
  239. // Request drilldown (success + error)
  240. ops.GET("/requests", h.Admin.Ops.ListRequestDetails)
  241. // Indexed system logs
  242. ops.GET("/system-logs", h.Admin.Ops.ListSystemLogs)
  243. ops.POST("/system-logs/cleanup", h.Admin.Ops.CleanupSystemLogs)
  244. ops.GET("/system-logs/health", h.Admin.Ops.GetSystemLogIngestionHealth)
  245. // Dashboard (vNext - raw path for MVP)
  246. ops.GET("/dashboard/snapshot-v2", h.Admin.Ops.GetDashboardSnapshotV2)
  247. ops.GET("/dashboard/overview", h.Admin.Ops.GetDashboardOverview)
  248. ops.GET("/dashboard/throughput-trend", h.Admin.Ops.GetDashboardThroughputTrend)
  249. ops.GET("/dashboard/latency-histogram", h.Admin.Ops.GetDashboardLatencyHistogram)
  250. ops.GET("/dashboard/error-trend", h.Admin.Ops.GetDashboardErrorTrend)
  251. ops.GET("/dashboard/error-distribution", h.Admin.Ops.GetDashboardErrorDistribution)
  252. ops.GET("/dashboard/openai-token-stats", h.Admin.Ops.GetDashboardOpenAITokenStats)
  253. }
  254. }
  255. func registerDashboardRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  256. dashboard := admin.Group("/dashboard")
  257. {
  258. dashboard.GET("/snapshot-v2", h.Admin.Dashboard.GetSnapshotV2)
  259. dashboard.GET("/stats", h.Admin.Dashboard.GetStats)
  260. dashboard.GET("/realtime", h.Admin.Dashboard.GetRealtimeMetrics)
  261. dashboard.GET("/trend", h.Admin.Dashboard.GetUsageTrend)
  262. dashboard.GET("/models", h.Admin.Dashboard.GetModelStats)
  263. dashboard.GET("/groups", h.Admin.Dashboard.GetGroupStats)
  264. dashboard.GET("/api-keys-trend", h.Admin.Dashboard.GetAPIKeyUsageTrend)
  265. dashboard.GET("/users-trend", h.Admin.Dashboard.GetUserUsageTrend)
  266. dashboard.GET("/users-ranking", h.Admin.Dashboard.GetUserSpendingRanking)
  267. dashboard.POST("/users-usage", h.Admin.Dashboard.GetBatchUsersUsage)
  268. dashboard.POST("/api-keys-usage", h.Admin.Dashboard.GetBatchAPIKeysUsage)
  269. dashboard.GET("/user-breakdown", h.Admin.Dashboard.GetUserBreakdown)
  270. dashboard.POST("/aggregation/backfill", h.Admin.Dashboard.BackfillAggregation)
  271. }
  272. }
  273. func registerUserManagementRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  274. users := admin.Group("/users")
  275. {
  276. users.GET("", h.Admin.User.List)
  277. users.GET("/:id", h.Admin.User.GetByID)
  278. users.POST("/:id/auth-identities", h.Admin.User.BindAuthIdentity)
  279. users.POST("", h.Admin.User.Create)
  280. users.PUT("/:id", h.Admin.User.Update)
  281. users.DELETE("/:id", h.Admin.User.Delete)
  282. users.POST("/:id/balance", h.Admin.User.UpdateBalance)
  283. users.GET("/:id/api-keys", h.Admin.User.GetUserAPIKeys)
  284. users.GET("/:id/usage", h.Admin.User.GetUserUsage)
  285. users.GET("/:id/balance-history", h.Admin.User.GetBalanceHistory)
  286. users.POST("/:id/replace-group", h.Admin.User.ReplaceGroup)
  287. users.GET("/:id/rpm-status", h.Admin.User.GetUserRPMStatus)
  288. users.POST("/batch-concurrency", h.Admin.User.BatchUpdateConcurrency)
  289. users.POST("/batch-limits", h.Admin.User.BatchUpdateLimits)
  290. users.GET("/:id/platform-quotas", h.Admin.User.GetUserPlatformQuotas)
  291. users.PUT("/:id/platform-quotas", h.Admin.User.UpdateUserPlatformQuotas)
  292. users.POST("/:id/platform-quotas/reset", h.Admin.User.ResetUserPlatformQuotaWindow)
  293. // User attribute values
  294. users.GET("/:id/attributes", h.Admin.UserAttribute.GetUserAttributes)
  295. users.PUT("/:id/attributes", h.Admin.UserAttribute.UpdateUserAttributes)
  296. }
  297. }
  298. func registerGroupRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  299. groups := admin.Group("/groups")
  300. {
  301. groups.GET("", h.Admin.Group.List)
  302. groups.GET("/all", h.Admin.Group.GetAll)
  303. groups.GET("/usage-summary", h.Admin.Group.GetUsageSummary)
  304. groups.GET("/capacity-summary", h.Admin.Group.GetCapacitySummary)
  305. groups.GET("/live-capability", h.Admin.Group.GetLiveCapability)
  306. groups.PUT("/sort-order", h.Admin.Group.UpdateSortOrder)
  307. groups.GET("/:id/composite-routes", h.Admin.Group.ListCompositeRoutes)
  308. groups.POST("/:id/composite-routes", h.Admin.Group.CreateCompositeRoute)
  309. groups.POST("/:id/composite-routes/preview", h.Admin.Group.PreviewCompositeRoute)
  310. groups.PUT("/:id/composite-routes/:route_id", h.Admin.Group.UpdateCompositeRoute)
  311. groups.DELETE("/:id/composite-routes/:route_id", h.Admin.Group.DeleteCompositeRoute)
  312. groups.GET("/:id", h.Admin.Group.GetByID)
  313. groups.POST("", h.Admin.Group.Create)
  314. groups.POST("/:id/duplicate", h.Admin.Group.Duplicate)
  315. groups.PUT("/:id", h.Admin.Group.Update)
  316. groups.DELETE("/:id", h.Admin.Group.Delete)
  317. groups.GET("/:id/stats", h.Admin.Group.GetStats)
  318. groups.GET("/:id/rate-multipliers", h.Admin.Group.GetGroupRateMultipliers)
  319. groups.PUT("/:id/rate-multipliers", h.Admin.Group.BatchSetGroupRateMultipliers)
  320. groups.DELETE("/:id/rate-multipliers", h.Admin.Group.ClearGroupRateMultipliers)
  321. groups.PUT("/:id/rpm-overrides", h.Admin.Group.BatchSetGroupRPMOverrides)
  322. groups.DELETE("/:id/rpm-overrides", h.Admin.Group.ClearGroupRPMOverrides)
  323. groups.GET("/:id/api-keys", h.Admin.Group.GetGroupAPIKeys)
  324. }
  325. }
  326. func registerAccountRoutes(admin *gin.RouterGroup, h *handler.Handlers, stepUpAuth middleware.StepUpAuthMiddleware) {
  327. accounts := admin.Group("/accounts")
  328. {
  329. accounts.GET("", h.Admin.Account.List)
  330. // Keep the registry route ahead of the dynamic /:id routes so clients can
  331. // always discover the available strategy profiles without ambiguity.
  332. accounts.GET("/anti-degrade/strategies", h.Admin.AntiDegrade.Strategies)
  333. accounts.GET("/upstream-billing-rates", h.Admin.Account.GetUpstreamBillingRates)
  334. accounts.GET("/upstream-billing-probe/settings", h.Admin.Account.GetUpstreamBillingProbeSettings)
  335. accounts.PUT("/upstream-billing-probe/settings", h.Admin.Account.UpdateUpstreamBillingProbeSettings)
  336. accounts.POST("/upstream-billing-probe/batch", h.Admin.Account.ProbeUpstreamBillingBatch)
  337. accounts.GET("/ollama-cloud-usage/settings", h.Admin.Account.GetOllamaCloudUsageSettings)
  338. accounts.PUT("/ollama-cloud-usage/settings", h.Admin.Account.UpdateOllamaCloudUsageSettings)
  339. accounts.GET("/:id", h.Admin.Account.GetByID)
  340. accounts.POST("", h.Admin.Account.Create)
  341. accounts.POST("/:id/duplicate", h.Admin.Account.Duplicate)
  342. accounts.POST("/check-mixed-channel", h.Admin.Account.CheckMixedChannel)
  343. accounts.POST("/import/codex-session", h.Admin.Account.ImportCodexSession)
  344. accounts.POST("/sync/crs", h.Admin.Account.SyncFromCRS)
  345. accounts.POST("/sync/crs/preview", h.Admin.Account.PreviewFromCRS)
  346. accounts.PUT("/:id", h.Admin.Account.Update)
  347. accounts.GET("/:id/grok-media-eligibility", h.Admin.Account.GetGrokMediaEligibility)
  348. accounts.PUT("/:id/grok-media-eligibility", h.Admin.Account.UpdateGrokMediaEligibility)
  349. accounts.PUT("/:id/upstream-billing-probe", h.Admin.Account.SetUpstreamBillingProbeEnabled)
  350. accounts.POST("/:id/upstream-billing-probe", h.Admin.Account.ProbeUpstreamBilling)
  351. accounts.GET("/:id/ollama-cloud-usage", h.Admin.Account.GetOllamaCloudUsage)
  352. accounts.PUT("/:id/ollama-cloud-usage/session", h.Admin.Account.SaveOllamaCloudUsageSession)
  353. accounts.DELETE("/:id/ollama-cloud-usage/session", h.Admin.Account.DeleteOllamaCloudUsageSession)
  354. accounts.PUT("/:id/ollama-cloud-usage/auto-refresh", h.Admin.Account.SetOllamaCloudUsageAutoRefresh)
  355. accounts.POST("/:id/ollama-cloud-usage/refresh", h.Admin.Account.RefreshOllamaCloudUsage)
  356. accounts.DELETE("/:id", h.Admin.Account.Delete)
  357. accounts.POST("/:id/test", h.Admin.Account.Test)
  358. accounts.POST("/:id/recover-state", h.Admin.Account.RecoverState)
  359. accounts.POST("/:id/refresh", h.Admin.Account.Refresh)
  360. accounts.POST("/:id/apply-oauth-credentials", h.Admin.Account.ApplyOAuthCredentials)
  361. accounts.POST("/:id/set-privacy", h.Admin.Account.SetPrivacy)
  362. accounts.POST("/:id/refresh-tier", h.Admin.Account.RefreshTier)
  363. accounts.GET("/:id/stats", h.Admin.Account.GetStats)
  364. accounts.POST("/:id/clear-error", h.Admin.Account.ClearError)
  365. accounts.POST("/:id/revert-proxy-fallback", h.Admin.Account.RevertProxyFallback)
  366. accounts.GET("/:id/anti-degrade", h.Admin.AntiDegrade.Preview)
  367. accounts.POST("/:id/anti-degrade/apply", h.Admin.AntiDegrade.Apply)
  368. accounts.POST("/:id/anti-degrade/revert", h.Admin.AntiDegrade.Revert)
  369. accounts.GET("/:id/usage", h.Admin.Account.GetUsage)
  370. accounts.GET("/:id/today-stats", h.Admin.Account.GetTodayStats)
  371. accounts.POST("/usage/batch", h.Admin.Account.GetBatchUsage)
  372. accounts.POST("/today-stats/batch", h.Admin.Account.GetBatchTodayStats)
  373. accounts.POST("/:id/clear-rate-limit", h.Admin.Account.ClearRateLimit)
  374. accounts.POST("/:id/reset-quota", h.Admin.Account.ResetQuota)
  375. accounts.GET("/:id/temp-unschedulable", h.Admin.Account.GetTempUnschedulable)
  376. accounts.DELETE("/:id/temp-unschedulable", h.Admin.Account.ClearTempUnschedulable)
  377. accounts.POST("/:id/schedulable", h.Admin.Account.SetSchedulable)
  378. accounts.POST("/models/sync-upstream-preview", h.Admin.Account.SyncUpstreamModelsPreview)
  379. accounts.GET("/:id/models", h.Admin.Account.GetAvailableModels)
  380. accounts.POST("/:id/models/sync-upstream", h.Admin.Account.SyncUpstreamModels)
  381. accounts.POST("/batch", h.Admin.Account.BatchCreate)
  382. // 账号导出泄露上游凭证原文——要求 step-up 2FA
  383. accounts.GET("/data", gin.HandlerFunc(stepUpAuth), h.Admin.Account.ExportData)
  384. accounts.POST("/data", h.Admin.Account.ImportData)
  385. accounts.POST("/batch-update-credentials", h.Admin.Account.BatchUpdateCredentials)
  386. accounts.POST("/batch-refresh-tier", h.Admin.Account.BatchRefreshTier)
  387. accounts.POST("/bulk-update", h.Admin.Account.BulkUpdate)
  388. accounts.POST("/batch-delete", h.Admin.Account.BatchDelete)
  389. accounts.POST("/batch-clear-error", h.Admin.Account.BatchClearError)
  390. accounts.POST("/batch-refresh", h.Admin.Account.BatchRefresh)
  391. // 历史明文凭据加密回填(幂等;未启用凭据加密时返回 0)
  392. // Antigravity 默认模型映射
  393. accounts.GET("/antigravity/default-model-mapping", h.Admin.Account.GetAntigravityDefaultModelMapping)
  394. // Spark 影子账号
  395. accounts.POST("/:id/shadow", h.Admin.OpenAIOAuth.CreateShadow)
  396. // Claude OAuth routes
  397. accounts.POST("/generate-auth-url", h.Admin.OAuth.GenerateAuthURL)
  398. accounts.POST("/generate-setup-token-url", h.Admin.OAuth.GenerateSetupTokenURL)
  399. accounts.POST("/exchange-code", h.Admin.OAuth.ExchangeCode)
  400. accounts.POST("/exchange-setup-token-code", h.Admin.OAuth.ExchangeSetupTokenCode)
  401. accounts.POST("/cookie-auth", h.Admin.OAuth.CookieAuth)
  402. accounts.POST("/setup-token-cookie-auth", h.Admin.OAuth.SetupTokenCookieAuth)
  403. }
  404. }
  405. func registerAnnouncementRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  406. announcements := admin.Group("/announcements")
  407. {
  408. announcements.GET("", h.Admin.Announcement.List)
  409. announcements.POST("", h.Admin.Announcement.Create)
  410. announcements.GET("/:id", h.Admin.Announcement.GetByID)
  411. announcements.PUT("/:id", h.Admin.Announcement.Update)
  412. announcements.DELETE("/:id", h.Admin.Announcement.Delete)
  413. announcements.GET("/:id/read-status", h.Admin.Announcement.ListReadStatus)
  414. }
  415. }
  416. func registerOpenAIOAuthRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  417. openai := admin.Group("/openai")
  418. {
  419. openai.POST("/generate-auth-url", h.Admin.OpenAIOAuth.GenerateAuthURL)
  420. openai.POST("/exchange-code", h.Admin.OpenAIOAuth.ExchangeCode)
  421. openai.POST("/refresh-token", h.Admin.OpenAIOAuth.RefreshToken)
  422. openai.POST("/accounts/:id/refresh", h.Admin.OpenAIOAuth.RefreshAccountToken)
  423. openai.POST("/create-from-oauth", h.Admin.OpenAIOAuth.CreateAccountFromOAuth)
  424. openai.POST("/create-from-codex-pat", h.Admin.OpenAIOAuth.CreateAccountFromCodexPAT)
  425. openai.GET("/accounts/:id/quota", h.Admin.OpenAIOAuth.QueryQuota)
  426. openai.POST("/accounts/:id/quota/refresh", h.Admin.OpenAIOAuth.RefreshQuota)
  427. openai.POST("/accounts/:id/reset-quota", h.Admin.OpenAIOAuth.ResetQuota)
  428. }
  429. }
  430. func registerGeminiOAuthRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  431. gemini := admin.Group("/gemini")
  432. {
  433. gemini.POST("/oauth/auth-url", h.Admin.GeminiOAuth.GenerateAuthURL)
  434. gemini.POST("/oauth/exchange-code", h.Admin.GeminiOAuth.ExchangeCode)
  435. gemini.GET("/oauth/capabilities", h.Admin.GeminiOAuth.GetCapabilities)
  436. }
  437. }
  438. func registerAntigravityOAuthRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  439. antigravity := admin.Group("/antigravity")
  440. {
  441. antigravity.POST("/oauth/auth-url", h.Admin.AntigravityOAuth.GenerateAuthURL)
  442. antigravity.POST("/oauth/exchange-code", h.Admin.AntigravityOAuth.ExchangeCode)
  443. antigravity.POST("/oauth/refresh-token", h.Admin.AntigravityOAuth.RefreshToken)
  444. }
  445. }
  446. func registerGrokOAuthRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  447. grok := admin.Group("/grok")
  448. {
  449. grok.GET("/oauth/capabilities", h.Admin.GrokOAuth.GetCapabilities)
  450. grok.POST("/oauth/auth-url", h.Admin.GrokOAuth.GenerateAuthURL)
  451. grok.POST("/oauth/exchange-code", h.Admin.GrokOAuth.ExchangeCode)
  452. grok.POST("/oauth/refresh-token", h.Admin.GrokOAuth.RefreshToken)
  453. grok.POST("/oauth/sso-token", h.Admin.GrokOAuth.ValidateSSOToken)
  454. grok.POST("/oauth/password", h.Admin.GrokOAuth.AuthorizePassword)
  455. grok.POST("/oauth/create-from-oauth", h.Admin.GrokOAuth.CreateAccountFromOAuth)
  456. grok.POST("/sso-to-oauth", h.Admin.GrokOAuth.CreateAccountsFromSSO)
  457. grok.POST("/oauth/reconcile", h.Admin.GrokOAuth.ReconcileOAuthAccounts)
  458. grok.POST("/accounts/:id/refresh", h.Admin.GrokOAuth.RefreshAccountToken)
  459. grok.GET("/accounts/:id/quota", h.Admin.GrokOAuth.QueryQuota)
  460. grok.POST("/accounts/:id/reset-quota", h.Admin.GrokOAuth.ResetQuota)
  461. grok.GET("/runtime-sanity", h.Admin.GrokOAuth.RuntimeSanity)
  462. }
  463. }
  464. // registerCNProviderRoutes 注册国产供应商(kimi/zhipu/deepseek)的额度与余额查询端点。
  465. func registerCNProviderRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  466. cn := admin.Group("/cn-providers")
  467. {
  468. // Coding Plan 滚动窗口用量(kimi/zhipu coding 账号)。
  469. cn.GET("/accounts/:id/quota", h.Admin.CNProvider.QueryQuota)
  470. // payg 账号余额(kimi/deepseek;zhipu 无余额端点)。
  471. cn.GET("/accounts/:id/balance", h.Admin.CNProvider.QueryBalance)
  472. }
  473. }
  474. func registerProxyRoutes(admin *gin.RouterGroup, h *handler.Handlers, stepUpAuth middleware.StepUpAuthMiddleware) {
  475. proxies := admin.Group("/proxies")
  476. {
  477. proxies.GET("", h.Admin.Proxy.List)
  478. proxies.GET("/all", h.Admin.Proxy.GetAll)
  479. // 代理导出泄露账号密码原文——要求 step-up 2FA
  480. proxies.GET("/data", gin.HandlerFunc(stepUpAuth), h.Admin.Proxy.ExportData)
  481. proxies.POST("/data", h.Admin.Proxy.ImportData)
  482. proxies.GET("/:id", h.Admin.Proxy.GetByID)
  483. proxies.POST("", h.Admin.Proxy.Create)
  484. proxies.PUT("/:id", h.Admin.Proxy.Update)
  485. proxies.DELETE("/:id", h.Admin.Proxy.Delete)
  486. proxies.POST("/:id/test", h.Admin.Proxy.Test)
  487. proxies.POST("/:id/quality-check", h.Admin.Proxy.CheckQuality)
  488. proxies.GET("/:id/stats", h.Admin.Proxy.GetStats)
  489. proxies.GET("/:id/accounts", h.Admin.Proxy.GetProxyAccounts)
  490. proxies.POST("/batch-delete", h.Admin.Proxy.BatchDelete)
  491. proxies.POST("/batch", h.Admin.Proxy.BatchCreate)
  492. }
  493. }
  494. func registerRedeemCodeRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  495. codes := admin.Group("/redeem-codes")
  496. {
  497. codes.GET("", h.Admin.Redeem.List)
  498. codes.GET("/stats", h.Admin.Redeem.GetStats)
  499. codes.GET("/export", h.Admin.Redeem.Export)
  500. codes.GET("/:id", h.Admin.Redeem.GetByID)
  501. codes.POST("/create-and-redeem", h.Admin.Redeem.CreateAndRedeem)
  502. codes.POST("/generate", h.Admin.Redeem.Generate)
  503. codes.DELETE("/:id", h.Admin.Redeem.Delete)
  504. codes.POST("/batch-delete", h.Admin.Redeem.BatchDelete)
  505. codes.POST("/batch-update", h.Admin.Redeem.BatchUpdate)
  506. codes.POST("/:id/expire", h.Admin.Redeem.Expire)
  507. }
  508. }
  509. func registerPromoCodeRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  510. promoCodes := admin.Group("/promo-codes")
  511. {
  512. promoCodes.GET("", h.Admin.Promo.List)
  513. promoCodes.GET("/:id", h.Admin.Promo.GetByID)
  514. promoCodes.POST("", h.Admin.Promo.Create)
  515. promoCodes.PUT("/:id", h.Admin.Promo.Update)
  516. promoCodes.DELETE("/:id", h.Admin.Promo.Delete)
  517. promoCodes.GET("/:id/usages", h.Admin.Promo.GetUsages)
  518. }
  519. }
  520. func registerSettingsRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  521. adminSettings := admin.Group("/settings")
  522. {
  523. adminSettings.GET("", h.Admin.Setting.GetSettings)
  524. adminSettings.PUT("", h.Admin.Setting.UpdateSettings)
  525. adminSettings.POST("/test-smtp", h.Admin.Setting.TestSMTPConnection)
  526. adminSettings.POST("/send-test-email", h.Admin.Setting.SendTestEmail)
  527. adminSettings.GET("/email-templates", h.Admin.Setting.ListEmailTemplates)
  528. adminSettings.POST("/email-template-preview", h.Admin.Setting.PreviewEmailTemplate)
  529. adminSettings.GET("/email-templates/:event/:locale", h.Admin.Setting.GetEmailTemplate)
  530. adminSettings.PUT("/email-templates/:event/:locale", h.Admin.Setting.UpdateEmailTemplate)
  531. adminSettings.POST("/email-templates/:event/:locale/restore-official", h.Admin.Setting.RestoreOfficialEmailTemplate)
  532. // Admin API Key 管理
  533. adminSettings.GET("/admin-api-key", h.Admin.Setting.GetAdminAPIKey)
  534. adminSettings.POST("/admin-api-key/regenerate", h.Admin.Setting.RegenerateAdminAPIKey)
  535. adminSettings.DELETE("/admin-api-key", h.Admin.Setting.DeleteAdminAPIKey)
  536. // 529过载冷却配置
  537. adminSettings.GET("/overload-cooldown", h.Admin.Setting.GetOverloadCooldownSettings)
  538. adminSettings.PUT("/overload-cooldown", h.Admin.Setting.UpdateOverloadCooldownSettings)
  539. // 429默认回避配置
  540. adminSettings.GET("/rate-limit-429-cooldown", h.Admin.Setting.GetRateLimit429CooldownSettings)
  541. adminSettings.PUT("/rate-limit-429-cooldown", h.Admin.Setting.UpdateRateLimit429CooldownSettings)
  542. // OpenAI OAuth image-tool unavailable cooldown configuration
  543. adminSettings.GET("/openai-images-oauth-unavailable-cooldown", h.Admin.Setting.GetOpenAIImagesOAuthUnavailableCooldownSettings)
  544. adminSettings.PUT("/openai-images-oauth-unavailable-cooldown", h.Admin.Setting.UpdateOpenAIImagesOAuthUnavailableCooldownSettings)
  545. // 面板 API 限流配置
  546. adminSettings.GET("/panel-rate-limit", h.Admin.Setting.GetPanelRateLimitSettings)
  547. adminSettings.PUT("/panel-rate-limit", h.Admin.Setting.UpdatePanelRateLimitSettings)
  548. // 流超时处理配置
  549. adminSettings.GET("/stream-timeout", h.Admin.Setting.GetStreamTimeoutSettings)
  550. adminSettings.PUT("/stream-timeout", h.Admin.Setting.UpdateStreamTimeoutSettings)
  551. // 请求整流器配置
  552. adminSettings.GET("/rectifier", h.Admin.Setting.GetRectifierSettings)
  553. adminSettings.PUT("/rectifier", h.Admin.Setting.UpdateRectifierSettings)
  554. // Beta 策略配置
  555. adminSettings.GET("/beta-policy", h.Admin.Setting.GetBetaPolicySettings)
  556. adminSettings.PUT("/beta-policy", h.Admin.Setting.UpdateBetaPolicySettings)
  557. // Web Search 模拟配置
  558. adminSettings.GET("/web-search-emulation", h.Admin.Setting.GetWebSearchEmulationConfig)
  559. adminSettings.PUT("/web-search-emulation", h.Admin.Setting.UpdateWebSearchEmulationConfig)
  560. adminSettings.POST("/web-search-emulation/test", h.Admin.Setting.TestWebSearchEmulation)
  561. adminSettings.POST("/web-search-emulation/reset-usage", h.Admin.Setting.ResetWebSearchUsage)
  562. }
  563. }
  564. func registerDataManagementRoutes(admin *gin.RouterGroup, h *handler.Handlers, stepUpAuth middleware.StepUpAuthMiddleware) {
  565. dataManagement := admin.Group("/data-management")
  566. {
  567. dataManagement.GET("/agent/health", h.Admin.DataManagement.GetAgentHealth)
  568. dataManagement.GET("/config", h.Admin.DataManagement.GetConfig)
  569. dataManagement.PUT("/config", h.Admin.DataManagement.UpdateConfig)
  570. dataManagement.GET("/sources/:source_type/profiles", h.Admin.DataManagement.ListSourceProfiles)
  571. dataManagement.POST("/sources/:source_type/profiles", h.Admin.DataManagement.CreateSourceProfile)
  572. dataManagement.PUT("/sources/:source_type/profiles/:profile_id", h.Admin.DataManagement.UpdateSourceProfile)
  573. dataManagement.DELETE("/sources/:source_type/profiles/:profile_id", h.Admin.DataManagement.DeleteSourceProfile)
  574. dataManagement.POST("/sources/:source_type/profiles/:profile_id/activate", h.Admin.DataManagement.SetActiveSourceProfile)
  575. dataManagement.POST("/s3/test", h.Admin.DataManagement.TestS3)
  576. dataManagement.GET("/s3/profiles", h.Admin.DataManagement.ListS3Profiles)
  577. // 修改 S3 目标可将数据备份外泄——要求 step-up 2FA
  578. dataManagement.POST("/s3/profiles", gin.HandlerFunc(stepUpAuth), h.Admin.DataManagement.CreateS3Profile)
  579. dataManagement.PUT("/s3/profiles/:profile_id", gin.HandlerFunc(stepUpAuth), h.Admin.DataManagement.UpdateS3Profile)
  580. dataManagement.DELETE("/s3/profiles/:profile_id", h.Admin.DataManagement.DeleteS3Profile)
  581. dataManagement.POST("/s3/profiles/:profile_id/activate", gin.HandlerFunc(stepUpAuth), h.Admin.DataManagement.SetActiveS3Profile)
  582. dataManagement.POST("/backups", gin.HandlerFunc(stepUpAuth), h.Admin.DataManagement.CreateBackupJob)
  583. dataManagement.GET("/backups", h.Admin.DataManagement.ListBackupJobs)
  584. dataManagement.GET("/backups/:job_id", h.Admin.DataManagement.GetBackupJob)
  585. }
  586. }
  587. func registerBackupRoutes(admin *gin.RouterGroup, h *handler.Handlers, stepUpAuth middleware.StepUpAuthMiddleware) {
  588. backup := admin.Group("/backups")
  589. {
  590. // S3 存储配置
  591. backup.GET("/s3-config", h.Admin.Backup.GetS3Config)
  592. // 修改 S3 目标可将数据库备份外泄——要求 step-up 2FA
  593. backup.PUT("/s3-config", gin.HandlerFunc(stepUpAuth), h.Admin.Backup.UpdateS3Config)
  594. backup.POST("/s3-config/test", h.Admin.Backup.TestS3Connection)
  595. // 异步生图对象存储配置(与备份共用 S3 客户端,可直接复用备份凭证)
  596. backup.GET("/image-storage", h.Admin.Backup.GetImageStorageConfig)
  597. // 同 S3 配置:改写对象存储目标可将生成内容导向外部账号——要求 step-up 2FA
  598. backup.PUT("/image-storage", gin.HandlerFunc(stepUpAuth), h.Admin.Backup.UpdateImageStorageConfig)
  599. backup.POST("/image-storage/test", h.Admin.Backup.TestImageStorageConnection)
  600. // 定时备份配置
  601. backup.GET("/schedule", h.Admin.Backup.GetSchedule)
  602. backup.PUT("/schedule", h.Admin.Backup.UpdateSchedule)
  603. // 备份操作
  604. backup.POST("", gin.HandlerFunc(stepUpAuth), h.Admin.Backup.CreateBackup)
  605. backup.GET("", h.Admin.Backup.ListBackups)
  606. backup.GET("/:id", h.Admin.Backup.GetBackup)
  607. backup.DELETE("/:id", h.Admin.Backup.DeleteBackup)
  608. // 备份下载链接可直接取走整库数据——要求 step-up 2FA
  609. backup.GET("/:id/download-url", gin.HandlerFunc(stepUpAuth), h.Admin.Backup.GetDownloadURL)
  610. // 恢复操作:整库覆盖可回滚安全设置(含 step-up 开关本身)——要求 step-up 2FA
  611. backup.POST("/:id/restore", gin.HandlerFunc(stepUpAuth), h.Admin.Backup.RestoreBackup)
  612. }
  613. }
  614. func registerSystemRoutes(admin *gin.RouterGroup, h *handler.Handlers, stepUpAuth middleware.StepUpAuthMiddleware) {
  615. system := admin.Group("/system")
  616. {
  617. system.GET("/version", h.Admin.System.GetVersion)
  618. system.GET("/check-updates", h.Admin.System.CheckUpdates)
  619. system.GET("/rollback-versions", h.Admin.System.GetRollbackVersions)
  620. system.POST("/update", gin.HandlerFunc(stepUpAuth), h.Admin.System.PerformUpdate)
  621. system.POST("/rollback", gin.HandlerFunc(stepUpAuth), h.Admin.System.Rollback)
  622. system.POST("/restart", gin.HandlerFunc(stepUpAuth), h.Admin.System.RestartService)
  623. }
  624. }
  625. func registerSubscriptionRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  626. subscriptions := admin.Group("/subscriptions")
  627. {
  628. subscriptions.GET("", h.Admin.Subscription.List)
  629. subscriptions.GET("/:id", h.Admin.Subscription.GetByID)
  630. subscriptions.GET("/:id/progress", h.Admin.Subscription.GetProgress)
  631. subscriptions.POST("/assign", h.Admin.Subscription.Assign)
  632. subscriptions.POST("/bulk-assign", h.Admin.Subscription.BulkAssign)
  633. subscriptions.POST("/:id/extend", h.Admin.Subscription.Extend)
  634. subscriptions.POST("/:id/reset-quota", h.Admin.Subscription.ResetQuota)
  635. subscriptions.POST("/:id/revoke", h.Admin.Subscription.Revoke)
  636. subscriptions.POST("/:id/restore", h.Admin.Subscription.Restore)
  637. subscriptions.DELETE("/:id", h.Admin.Subscription.Revoke)
  638. }
  639. // 分组下的订阅列表
  640. admin.GET("/groups/:id/subscriptions", h.Admin.Subscription.ListByGroup)
  641. // 用户下的订阅列表
  642. admin.GET("/users/:id/subscriptions", h.Admin.Subscription.ListByUser)
  643. }
  644. func registerUsageRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  645. usage := admin.Group("/usage")
  646. {
  647. usage.GET("", h.Admin.Usage.List)
  648. usage.GET("/stats", h.Admin.Usage.Stats)
  649. usage.GET("/search-users", h.Admin.Usage.SearchUsers)
  650. usage.GET("/search-api-keys", h.Admin.Usage.SearchAPIKeys)
  651. usage.GET("/cleanup-tasks", h.Admin.Usage.ListCleanupTasks)
  652. usage.POST("/cleanup-tasks", h.Admin.Usage.CreateCleanupTask)
  653. usage.POST("/cleanup-tasks/:id/cancel", h.Admin.Usage.CancelCleanupTask)
  654. }
  655. }
  656. func registerUserAttributeRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  657. attrs := admin.Group("/user-attributes")
  658. {
  659. attrs.GET("", h.Admin.UserAttribute.ListDefinitions)
  660. attrs.POST("", h.Admin.UserAttribute.CreateDefinition)
  661. attrs.POST("/batch", h.Admin.UserAttribute.GetBatchUserAttributes)
  662. attrs.PUT("/reorder", h.Admin.UserAttribute.ReorderDefinitions)
  663. attrs.PUT("/:id", h.Admin.UserAttribute.UpdateDefinition)
  664. attrs.DELETE("/:id", h.Admin.UserAttribute.DeleteDefinition)
  665. }
  666. }
  667. func registerScheduledTestRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  668. plans := admin.Group("/scheduled-test-plans")
  669. {
  670. plans.POST("", h.Admin.ScheduledTest.Create)
  671. plans.PUT("/:id", h.Admin.ScheduledTest.Update)
  672. plans.DELETE("/:id", h.Admin.ScheduledTest.Delete)
  673. plans.GET("/:id/results", h.Admin.ScheduledTest.ListResults)
  674. }
  675. // Nested under accounts
  676. admin.GET("/accounts/:id/scheduled-test-plans", h.Admin.ScheduledTest.ListByAccount)
  677. }
  678. func registerErrorPassthroughRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  679. rules := admin.Group("/error-passthrough-rules")
  680. {
  681. rules.GET("", h.Admin.ErrorPassthrough.List)
  682. rules.GET("/:id", h.Admin.ErrorPassthrough.GetByID)
  683. rules.POST("", h.Admin.ErrorPassthrough.Create)
  684. rules.PUT("/:id", h.Admin.ErrorPassthrough.Update)
  685. rules.DELETE("/:id", h.Admin.ErrorPassthrough.Delete)
  686. }
  687. }
  688. func registerTLSFingerprintProfileRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  689. profiles := admin.Group("/tls-fingerprint-profiles")
  690. {
  691. profiles.GET("", h.Admin.TLSFingerprintProfile.List)
  692. profiles.GET("/:id", h.Admin.TLSFingerprintProfile.GetByID)
  693. profiles.POST("", h.Admin.TLSFingerprintProfile.Create)
  694. profiles.PUT("/:id", h.Admin.TLSFingerprintProfile.Update)
  695. profiles.DELETE("/:id", h.Admin.TLSFingerprintProfile.Delete)
  696. }
  697. }
  698. func registerPluginRoutes(admin *gin.RouterGroup, h *handler.Handlers, stepUpAuth middleware.StepUpAuthMiddleware) {
  699. plugins := admin.Group("/plugins")
  700. {
  701. plugins.GET("", h.Admin.Plugin.List)
  702. plugins.GET("/:id", h.Admin.Plugin.Get)
  703. plugins.POST("/upload", gin.HandlerFunc(stepUpAuth), h.Admin.Plugin.Upload)
  704. plugins.POST("/:id/enable", gin.HandlerFunc(stepUpAuth), h.Admin.Plugin.Enable)
  705. plugins.POST("/:id/disable", gin.HandlerFunc(stepUpAuth), h.Admin.Plugin.Disable)
  706. plugins.DELETE("/:id", gin.HandlerFunc(stepUpAuth), h.Admin.Plugin.Delete)
  707. plugins.GET("/:id/config", h.Admin.Plugin.GetConfig)
  708. plugins.PUT("/:id/config", gin.HandlerFunc(stepUpAuth), h.Admin.Plugin.SaveConfig)
  709. plugins.POST("/:id/test", gin.HandlerFunc(stepUpAuth), h.Admin.Plugin.Test)
  710. plugins.POST("/:id/ui-session", h.Admin.Plugin.CreateUISession)
  711. }
  712. }
  713. func registerGlobalPricingRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  714. pricing := admin.Group("/global-pricing")
  715. {
  716. pricing.GET("", h.Admin.GlobalPricing.List)
  717. pricing.POST("", h.Admin.GlobalPricing.Create)
  718. pricing.PUT("/:id", h.Admin.GlobalPricing.Update)
  719. pricing.DELETE("/:id", h.Admin.GlobalPricing.Delete)
  720. pricing.POST("/:id/enable", h.Admin.GlobalPricing.SetEnabled)
  721. }
  722. }
  723. func registerAccountHealthRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  724. health := admin.Group("/account-health")
  725. {
  726. health.GET("", h.Admin.AccountHealth.Snapshot)
  727. health.GET("/settings", h.Admin.AccountHealth.GetSettings)
  728. health.PUT("/settings", h.Admin.AccountHealth.UpdateSettings)
  729. health.POST("/:id/isolate", h.Admin.AccountHealth.Isolate)
  730. health.POST("/:id/resume", h.Admin.AccountHealth.Resume)
  731. }
  732. }
  733. func registerMarginRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  734. margins := admin.Group("/margins")
  735. {
  736. margins.GET("", h.Admin.Margin.Summary)
  737. margins.GET("/fuse-settings", h.Admin.Margin.GetSettings)
  738. margins.PUT("/fuse-settings", h.Admin.Margin.UpdateSettings)
  739. margins.GET("/events", h.Admin.Margin.Events)
  740. margins.POST("/channels/:id/unfuse", h.Admin.Margin.Unfuse)
  741. }
  742. }
  743. func registerTieredRoutingRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  744. routing := admin.Group("/tiered-routing")
  745. {
  746. routing.GET("/settings", h.Admin.TieredRouting.GetSettings)
  747. routing.PUT("/settings", h.Admin.TieredRouting.UpdateSettings)
  748. }
  749. }
  750. func registerSpendGuardRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  751. guard := admin.Group("/spend-guard")
  752. {
  753. guard.GET("", h.Admin.SpendGuard.Offenders)
  754. guard.GET("/settings", h.Admin.SpendGuard.GetSettings)
  755. guard.PUT("/settings", h.Admin.SpendGuard.UpdateSettings)
  756. guard.GET("/events", h.Admin.SpendGuard.Events)
  757. guard.POST("/keys/:id/unfreeze", h.Admin.SpendGuard.Unfreeze)
  758. }
  759. }
  760. func registerTicketAdminRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  761. tickets := admin.Group("/tickets")
  762. {
  763. tickets.GET("", h.Admin.Ticket.ListAll)
  764. tickets.GET("/stats", h.Admin.Ticket.Stats)
  765. tickets.GET("/:id", h.Admin.Ticket.GetAny)
  766. tickets.POST("/:id/replies", h.Admin.Ticket.ReplyAny)
  767. tickets.POST("/:id/close", h.Admin.Ticket.CloseAny)
  768. }
  769. }
  770. func registerBillingExportAdminRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  771. billing := admin.Group("/billing/users/:userId")
  772. {
  773. billing.GET("/statement", h.Admin.BillingExport.AdminStatement)
  774. billing.GET("/export", h.Admin.BillingExport.AdminExport)
  775. }
  776. }
  777. func registerChannelRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  778. channels := admin.Group("/channels")
  779. {
  780. channels.GET("", h.Admin.Channel.List)
  781. channels.GET("/model-pricing", h.Admin.Channel.GetModelDefaultPricing)
  782. channels.GET("/pricing/sync-models", h.Admin.Channel.SyncPricingModels)
  783. channels.GET("/:id", h.Admin.Channel.GetByID)
  784. channels.POST("", h.Admin.Channel.Create)
  785. channels.PUT("/:id", h.Admin.Channel.Update)
  786. channels.DELETE("/:id", h.Admin.Channel.Delete)
  787. }
  788. }
  789. func registerChannelMonitorRoutes(admin *gin.RouterGroup, h *handler.Handlers, settingService *service.SettingService) {
  790. guard := channelMonitorAdminFeatureGuard(settingService)
  791. monitors := admin.Group("/channel-monitors")
  792. monitors.Use(guard)
  793. {
  794. monitors.GET("", h.Admin.ChannelMonitor.List)
  795. monitors.POST("", h.Admin.ChannelMonitor.Create)
  796. monitors.GET("/:id", h.Admin.ChannelMonitor.Get)
  797. monitors.POST("/:id/duplicate", h.Admin.ChannelMonitor.Duplicate)
  798. monitors.PUT("/:id", h.Admin.ChannelMonitor.Update)
  799. monitors.DELETE("/:id", h.Admin.ChannelMonitor.Delete)
  800. monitors.POST("/:id/run", h.Admin.ChannelMonitor.Run)
  801. monitors.GET("/:id/history", h.Admin.ChannelMonitor.History)
  802. }
  803. templates := admin.Group("/channel-monitor-templates")
  804. templates.Use(guard)
  805. {
  806. templates.GET("", h.Admin.ChannelMonitorTemplate.List)
  807. templates.POST("", h.Admin.ChannelMonitorTemplate.Create)
  808. templates.GET("/:id", h.Admin.ChannelMonitorTemplate.Get)
  809. templates.PUT("/:id", h.Admin.ChannelMonitorTemplate.Update)
  810. templates.DELETE("/:id", h.Admin.ChannelMonitorTemplate.Delete)
  811. templates.GET("/:id/monitors", h.Admin.ChannelMonitorTemplate.AssociatedMonitors)
  812. templates.POST("/:id/apply", h.Admin.ChannelMonitorTemplate.Apply)
  813. }
  814. }
  815. // registerAffiliateRoutes 注册邀请返利的管理端路由(专属用户配置)
  816. func registerAffiliateRoutes(admin *gin.RouterGroup, h *handler.Handlers) {
  817. affiliates := admin.Group("/affiliates")
  818. {
  819. affiliates.GET("/invites", h.Admin.Affiliate.ListInviteRecords)
  820. affiliates.GET("/rebates", h.Admin.Affiliate.ListRebateRecords)
  821. affiliates.GET("/transfers", h.Admin.Affiliate.ListTransferRecords)
  822. users := affiliates.Group("/users")
  823. {
  824. users.GET("", h.Admin.Affiliate.ListUsers)
  825. users.GET("/lookup", h.Admin.Affiliate.LookupUsers)
  826. users.POST("/batch-rate", h.Admin.Affiliate.BatchSetRate)
  827. users.GET("/:user_id/overview", h.Admin.Affiliate.GetUserOverview)
  828. users.PUT("/:user_id", h.Admin.Affiliate.UpdateUserSettings)
  829. users.DELETE("/:user_id", h.Admin.Affiliate.ClearUserSettings)
  830. }
  831. }
  832. }
  833. func registerChannelMonitorV2Routes(admin *gin.RouterGroup, h *handler.Handlers, settingService *service.SettingService) {
  834. // Config GET/PUT: feature enabled only (operators can prepare V2 before flipping mode).
  835. // Read/matrix endpoints: require mode=v2 so V1 deployments do not serve passive data.
  836. featureGuard := channelMonitorAdminFeatureGuard(settingService)
  837. modeV2Guard := channelMonitorModeV2Guard(settingService)
  838. monitor := admin.Group("/channel-monitor-v2")
  839. {
  840. config := monitor.Group("")
  841. config.Use(featureGuard)
  842. {
  843. config.GET("/config", h.ChannelMonitorV2.GetConfig)
  844. config.PUT("/config", h.ChannelMonitorV2.UpdateConfig)
  845. }
  846. reads := monitor.Group("")
  847. reads.Use(modeV2Guard)
  848. {
  849. reads.GET("/dimensions", h.ChannelMonitorV2.Dimensions)
  850. reads.GET("/snapshot", h.ChannelMonitorV2.AdminSnapshot)
  851. reads.GET("/models", h.ChannelMonitorV2.AdminModels)
  852. reads.GET("/matrix", h.ChannelMonitorV2.AdminMatrix)
  853. reads.GET("/errors", h.ChannelMonitorV2.Errors)
  854. reads.GET("/users", h.ChannelMonitorV2.AdminUsers)
  855. }
  856. }
  857. }
  858. func channelMonitorAdminFeatureGuard(settingService *service.SettingService) gin.HandlerFunc {
  859. return func(c *gin.Context) {
  860. if settingService != nil && settingService.GetChannelMonitorRuntime(c.Request.Context()).Enabled {
  861. c.Next()
  862. return
  863. }
  864. response.ErrorFrom(c, service.ErrChannelMonitorDisabled)
  865. c.Abort()
  866. }
  867. }
  868. // channelMonitorModeV2Guard requires feature enabled and channel_monitor_mode=v2.
  869. func channelMonitorModeV2Guard(settingService *service.SettingService) gin.HandlerFunc {
  870. return func(c *gin.Context) {
  871. if settingService == nil {
  872. response.ErrorFrom(c, service.ErrChannelMonitorDisabled)
  873. c.Abort()
  874. return
  875. }
  876. rt := settingService.GetChannelMonitorRuntime(c.Request.Context())
  877. if !rt.Enabled {
  878. response.ErrorFrom(c, service.ErrChannelMonitorDisabled)
  879. c.Abort()
  880. return
  881. }
  882. if !rt.PassiveAggregationAllowed() {
  883. response.ErrorFrom(c, service.ErrChannelMonitorModeMismatch)
  884. c.Abort()
  885. return
  886. }
  887. c.Next()
  888. }
  889. }