package api import ( "encoding/json" "io" "net/http" "strings" "github.com/gin-gonic/gin" ) func (a *API) localDocs(c *gin.Context) { if !isLoopbackRequest(c) { c.JSON(403, gin.H{"error": "仅允许本机管理文档"}) return } docs, err := a.store.PublishedDocs() if err != nil { c.JSON(500, gin.H{"error": "文档读取失败"}) return } c.JSON(200, gin.H{"projects": docs}) } func (a *API) publishLocalDocs(c *gin.Context) { if !isLoopbackRequest(c) { c.JSON(403, gin.H{"error": "仅允许本机发布文档"}) return } var req struct { ProjectID string `json:"projectId"` Name string `json:"name"` Endpoints []json.RawMessage `json:"endpoints"` } data, err := io.ReadAll(io.LimitReader(c.Request.Body, 2<<20+1)) if err != nil || len(data) > 2<<20 || json.Unmarshal(data, &req) != nil || len(req.Endpoints) > 500 || len(req.Endpoints) == 0 || len(req.ProjectID) > 128 || len(req.Name) > 200 || strings.TrimSpace(req.ProjectID) == "" || strings.TrimSpace(req.Name) == "" { c.JSON(400, gin.H{"error": "文档无效或超过限制(2 MB / 500 个接口)"}) return } for _, endpoint := range req.Endpoints { var item struct { Method string `json:"method"` Path string `json:"path"` Name string `json:"name"` } if json.Unmarshal(endpoint, &item) != nil || item.Name == "" || item.Method == "" || !strings.HasPrefix(item.Path, "/") { c.JSON(400, gin.H{"error": "接口方法、名称或路径无效"}) return } } doc, err := a.store.PublishDoc(req.ProjectID, req.Name, string(data)) if err != nil { c.JSON(500, gin.H{"error": "文档发布失败"}) return } c.JSON(200, doc) } func (a *API) revokeLocalDocs(c *gin.Context) { if !isLoopbackRequest(c) { c.JSON(403, gin.H{"error": "仅允许本机管理文档"}) return } if err := a.store.RevokeDoc(c.Param("projectId")); err != nil { c.JSON(500, gin.H{"error": "撤销文档失败"}) return } c.JSON(http.StatusOK, gin.H{"ok": true}) }