139 lines
7.0 KiB
Go
139 lines
7.0 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"io/fs"
|
|
"mime"
|
|
"net/http"
|
|
"path"
|
|
"strings"
|
|
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/auth"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/dashboard"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/member"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/middleware"
|
|
runhandler "git.iwork-ai.com/xdc/iqudo-top1/internal/run"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/scenario"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/scriptkit"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/sop"
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func New(db *gorm.DB, authService *auth.Service, frontend fs.FS, sdkFS fs.FS, log *zap.Logger, environment string) http.Handler {
|
|
if environment == "prod" {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
router := gin.New()
|
|
router.Use(middleware.CORS())
|
|
router.Use(middleware.RequestLogger(log.Named("http")), middleware.Recovery(log.Named("recovery")))
|
|
|
|
// 通过 HTTP 直接提供 SDK 产物,例如 /sdk/index.js 与 /sdk/index.iife.js。
|
|
router.StaticFS("/sdk", http.FS(sdkFS))
|
|
|
|
authHandler := auth.NewHandler(authService)
|
|
scenarioHandler := scenario.NewHandler(db)
|
|
sopHandler := sop.NewHandler(db)
|
|
runHandler := runhandler.NewHandler(db)
|
|
scriptkitHandler := scriptkit.NewHandler(db)
|
|
memberHandler := member.NewHandler(db)
|
|
dashboardHandler := dashboard.NewHandler(db)
|
|
|
|
api := router.Group("/api/v1")
|
|
api.GET("/health", func(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
|
})
|
|
api.POST("/auth/login", authHandler.Login)
|
|
api.POST("/auth/refresh", authHandler.Refresh)
|
|
public := router.Group("/public")
|
|
public.POST("/scenarios/:scenarioKey/runs", runHandler.PublicStart)
|
|
public.GET("/runs/:id/current", runHandler.PublicCurrent)
|
|
public.POST("/runs/:id/answer", runHandler.PublicAnswer)
|
|
public.POST("/runs/:id/submit", runHandler.PublicSubmit)
|
|
public.POST("/runs/:id/next", runHandler.PublicNext)
|
|
public.POST("/runs/:id/back", runHandler.PublicBack)
|
|
public.POST("/runs/:id/feedback", runHandler.PublicFeedback)
|
|
public.POST("/runs/:id/finish", runHandler.PublicFinish)
|
|
public.POST("/runs/:id/reset", runHandler.PublicReset)
|
|
|
|
protected := api.Group("")
|
|
protected.Use(middleware.Authenticate(authService))
|
|
protected.GET("/auth/me", authHandler.Me)
|
|
protected.GET("/members", middleware.RequirePermission("member.manage"), memberHandler.List)
|
|
protected.POST("/members", middleware.RequirePermission("member.manage"), memberHandler.Create)
|
|
protected.PUT("/members/:id", middleware.RequirePermission("member.manage"), memberHandler.Update)
|
|
protected.GET("/dashboard/summary", middleware.RequirePermission("dashboard.view"), dashboardHandler.Summary)
|
|
protected.GET("/dashboard/scriptkit", middleware.RequirePermission("dashboard.view"), dashboardHandler.Scriptkit)
|
|
|
|
protected.GET("/scenarios", middleware.RequirePermission("scenario.view"), scenarioHandler.List)
|
|
protected.POST("/scenarios", middleware.RequirePermission("scenario.edit"), scenarioHandler.Create)
|
|
protected.GET("/scenarios/:id", middleware.RequirePermission("scenario.view"), scenarioHandler.Get)
|
|
protected.PUT("/scenarios/:id", middleware.RequirePermission("scenario.edit"), scenarioHandler.Update)
|
|
protected.DELETE("/scenarios/:id", middleware.RequirePermission("scenario.edit"), scenarioHandler.Archive)
|
|
protected.POST("/scenarios/:id/fields", middleware.RequirePermission("scenario.edit"), scenarioHandler.CreateField)
|
|
protected.PUT("/scenario-fields/:fieldId", middleware.RequirePermission("scenario.edit"), scenarioHandler.UpdateField)
|
|
protected.DELETE("/scenario-fields/:fieldId", middleware.RequirePermission("scenario.edit"), scenarioHandler.DeleteField)
|
|
protected.GET("/scenarios/:id/contract", middleware.RequirePermission("scenario.view"), scenarioHandler.GetContract)
|
|
protected.PUT("/scenarios/:id/contract", middleware.RequirePermission("scenario.edit"), scenarioHandler.ReplaceContract)
|
|
protected.POST("/scenarios/:id/preview", middleware.RequirePermission("scenario.view"), runHandler.PreviewScenario)
|
|
|
|
protected.GET("/sops", middleware.RequirePermission("sop.view"), sopHandler.List)
|
|
protected.GET("/scenarios/:id/sops", middleware.RequirePermission("sop.view"), sopHandler.List)
|
|
protected.POST("/scenarios/:id/sops", middleware.RequirePermission("sop.edit"), sopHandler.Create)
|
|
protected.GET("/sops/:id", middleware.RequirePermission("sop.view"), sopHandler.Get)
|
|
protected.PUT("/sops/:id/graph", middleware.RequirePermission("sop.edit"), sopHandler.SaveGraph)
|
|
protected.POST("/sops/:id/validate", middleware.RequireAnyPermission("sop.view", "sop.edit"), sopHandler.Validate)
|
|
|
|
protected.GET("/available-sops", middleware.RequirePermission("sop.execute"), runHandler.AvailableSOPs)
|
|
protected.GET("/runs", middleware.RequireAnyPermission("runs.view_all", "runs.view_own"), runHandler.List)
|
|
protected.GET("/runs/options", middleware.RequireAnyPermission("runs.view_all", "runs.view_own"), runHandler.Options)
|
|
protected.POST("/runs", middleware.RequirePermission("sop.execute"), runHandler.Start)
|
|
protected.GET("/runs/:id", middleware.RequireAnyPermission("runs.view_all", "runs.view_own"), runHandler.Get)
|
|
protected.GET("/runs/:id/detail", middleware.RequireAnyPermission("runs.view_all", "runs.view_own"), runHandler.Detail)
|
|
protected.POST("/runs/:id/answer", middleware.RequirePermission("sop.execute"), runHandler.Answer)
|
|
protected.POST("/runs/:id/next", middleware.RequirePermission("sop.execute"), runHandler.Next)
|
|
protected.POST("/runs/:id/back", middleware.RequirePermission("sop.execute"), runHandler.Back)
|
|
protected.POST("/runs/:id/script-usage", middleware.RequirePermission("sop.execute"), runHandler.RecordScriptUsage)
|
|
protected.POST("/runs/:id/script-feedback", middleware.RequirePermission("sop.execute"), runHandler.ScriptFeedback)
|
|
protected.POST("/runs/:id/finish", middleware.RequirePermission("sop.execute"), runHandler.Finish)
|
|
protected.POST("/runs/:id/feedback", middleware.RequirePermission("runs.feedback"), runHandler.Feedback)
|
|
|
|
protected.GET("/scenarios/:id/script-package", middleware.RequirePermission("scriptkit.view"), scriptkitHandler.Get)
|
|
protected.PUT("/scenarios/:id/script-package", middleware.RequirePermission("scriptkit.edit"), scriptkitHandler.Replace)
|
|
|
|
router.NoRoute(spaHandler(frontend))
|
|
return router
|
|
}
|
|
|
|
func spaHandler(frontend fs.FS) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if strings.HasPrefix(c.Request.URL.Path, "/api/") {
|
|
c.JSON(http.StatusNotFound, gin.H{"code": "NOT_FOUND", "message": "接口不存在"})
|
|
return
|
|
}
|
|
name := strings.TrimPrefix(path.Clean(c.Request.URL.Path), "/")
|
|
if name == "" || name == "." {
|
|
name = "index.html"
|
|
}
|
|
data, err := fs.ReadFile(frontend, name)
|
|
if err != nil {
|
|
name = "index.html"
|
|
data, err = fs.ReadFile(frontend, name)
|
|
}
|
|
if err != nil {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
contentType := mime.TypeByExtension(path.Ext(name))
|
|
if contentType == "" {
|
|
contentType = "application/octet-stream"
|
|
}
|
|
if name == "index.html" {
|
|
c.Header("Cache-Control", "no-cache")
|
|
} else {
|
|
c.Header("Cache-Control", "public, max-age=31536000, immutable")
|
|
}
|
|
c.Data(http.StatusOK, contentType, data)
|
|
}
|
|
}
|