Files
Atlas/internal/api/admin_handlers.go
T
renjue ad38beeb9e
CI / docker (push) Successful in 11m2s
实现 Atlas AI 平台一期能力并完成品牌化改造。
引入用户端对话/生图与管理端 Provider 配置,统一 invoke 编排、Gateway、请求日志与模型管理;前端按设计规范拆分布局,Go module 更名为 github.com/rose_cat707/Atlas;生图长任务进度改为 SSE 推送;重写 README;移除 Dockerfile syntax 指令以修复 CI 构建超时。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 20:23:13 +08:00

190 lines
6.0 KiB
Go

package api
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/rose_cat707/Atlas/internal/store"
)
func (s *Server) registerAdminRoutes(r gin.IRoutes) {
r.GET("/admin/providers", s.adminListProviders)
r.POST("/admin/providers", s.adminCreateProvider)
r.GET("/admin/providers/:id", s.adminGetProvider)
r.PUT("/admin/providers/:id", s.adminUpdateProvider)
r.DELETE("/admin/providers/:id", s.adminDeleteProvider)
r.GET("/admin/providers/:id/models", s.adminListProviderModels)
r.POST("/admin/providers/:id/models", s.adminAddProviderModel)
r.DELETE("/admin/providers/:id/models/:modelId", s.adminDeleteProviderModel)
r.POST("/admin/providers/:id/models/sync", s.adminSyncProviderModels)
r.GET("/admin/logs", s.adminListLogs)
r.GET("/admin/dashboard/stats", s.adminDashboardStats)
}
func (s *Server) adminListProviders(c *gin.Context) {
items, err := s.app.Store.ListProviders(c.Request.Context(), c.Query("service_type"), false)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
masked := make([]store.Provider, len(items))
for i, p := range items {
masked[i] = store.MaskProvider(p)
}
c.JSON(http.StatusOK, gin.H{"items": masked})
}
func (s *Server) adminCreateProvider(c *gin.Context) {
var in store.Provider
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := store.ValidateProvider(&in); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if in.ExtraJSON == "" {
in.ExtraJSON = "{}"
}
id, err := s.app.Store.CreateProvider(c.Request.Context(), &in)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
in.ID = id
_ = s.app.Store.InsertAuditLog(c.Request.Context(), "create", "provider", in.Name)
c.JSON(http.StatusOK, store.MaskProvider(in))
}
func (s *Server) adminGetProvider(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
p, err := s.app.Store.GetProvider(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
c.JSON(http.StatusOK, store.MaskProvider(*p))
}
func (s *Server) adminUpdateProvider(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
var in store.Provider
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
existing, err := s.app.Store.GetProvider(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
return
}
in.ID = id
if in.APIKey == "" || in.APIKey == "******" {
in.APIKey = existing.APIKey
}
if err := store.ValidateProvider(&in); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := s.app.Store.UpdateProvider(c.Request.Context(), &in); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
_ = s.app.Store.InsertAuditLog(c.Request.Context(), "update", "provider", in.Name)
c.JSON(http.StatusOK, store.MaskProvider(in))
}
func (s *Server) adminDeleteProvider(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
if err := s.app.Store.DeleteProvider(c.Request.Context(), id); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
_ = s.app.Store.InsertAuditLog(c.Request.Context(), "delete", "provider", strconv.FormatInt(id, 10))
c.JSON(http.StatusOK, gin.H{"ok": true})
}
func (s *Server) adminListProviderModels(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
breakdown, err := s.app.Models.Breakdown(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, breakdown)
}
func (s *Server) adminAddProviderModel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
var in struct {
ModelID string `json:"model_id"`
Name string `json:"name"`
}
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := s.app.Models.AddManual(c.Request.Context(), id, in.ModelID, in.Name); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
breakdown, _ := s.app.Models.Breakdown(c.Request.Context(), id)
c.JSON(http.StatusOK, breakdown)
}
func (s *Server) adminDeleteProviderModel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
modelID := c.Param("modelId")
if err := s.app.Models.RemoveManual(c.Request.Context(), id, modelID); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
breakdown, _ := s.app.Models.Breakdown(c.Request.Context(), id)
c.JSON(http.StatusOK, breakdown)
}
func (s *Server) adminSyncProviderModels(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
upstream, err := s.app.Models.RefreshUpstream(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
breakdown, _ := s.app.Models.Breakdown(c.Request.Context(), id)
c.JSON(http.StatusOK, gin.H{"upstream": upstream, "breakdown": breakdown})
}
func (s *Server) adminListLogs(c *gin.Context) {
limit, offset := parseLimitOffset(c, 50, 500)
filter := store.RequestLogFilter{
Path: c.Query("path"),
ProviderID: parseInt64(c.Query("provider_id")),
}
if sc := c.Query("status_code"); sc != "" {
filter.StatusCode, _ = strconv.Atoi(sc)
}
items, total, err := s.app.Store.ListRequestLogs(c.Request.Context(), filter, limit, offset)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"items": items, "total": total})
}
func (s *Server) adminDashboardStats(c *gin.Context) {
stats, err := s.app.Store.DashboardStats(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, stats)
}
func parseInt64(v string) int64 {
n, _ := strconv.ParseInt(v, 10, 64)
return n
}