feat: simplify SOP to immediate-effect configuration
This commit is contained in:
@@ -20,13 +20,17 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func New(db *gorm.DB, authService *auth.Service, frontend fs.FS, log *zap.Logger, environment string) http.Handler {
|
||||
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)
|
||||
@@ -41,6 +45,13 @@ func New(db *gorm.DB, authService *auth.Service, frontend fs.FS, log *zap.Logger
|
||||
})
|
||||
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/submit", runHandler.PublicSubmit)
|
||||
public.POST("/runs/:id/next", runHandler.PublicNext)
|
||||
public.POST("/runs/:id/finish", runHandler.PublicFinish)
|
||||
public.POST("/runs/:id/reset", runHandler.PublicReset)
|
||||
|
||||
protected := api.Group("")
|
||||
protected.Use(middleware.Authenticate(authService))
|
||||
@@ -58,23 +69,18 @@ func New(db *gorm.DB, authService *auth.Service, frontend fs.FS, log *zap.Logger
|
||||
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.GET("/sops/:id/versions", middleware.RequirePermission("sop.view"), sopHandler.ListVersions)
|
||||
protected.PUT("/sops/:id/draft", middleware.RequirePermission("sop.edit"), sopHandler.SaveGraph)
|
||||
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.POST("/sops/:id/submit-review", middleware.RequirePermission("sop.submit_review"), sopHandler.SubmitReview)
|
||||
protected.POST("/sops/:id/publish", middleware.RequirePermission("sop.publish"), sopHandler.Publish)
|
||||
protected.POST("/sops/:id/reject", middleware.RequirePermission("sop.review"), sopHandler.Reject)
|
||||
protected.POST("/sops/:id/offline", middleware.RequirePermission("sop.publish"), sopHandler.Offline)
|
||||
protected.POST("/sops/:id/versions", middleware.RequirePermission("sop.edit"), sopHandler.CreateVersion)
|
||||
protected.POST("/sops/:id/rollback", middleware.RequirePermission("sop.publish"), sopHandler.Rollback)
|
||||
protected.GET("/reviews", middleware.RequirePermission("sop.review"), sopHandler.Reviews)
|
||||
|
||||
protected.GET("/published-sops", middleware.RequirePermission("sop.execute"), runHandler.PublishedSOPs)
|
||||
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)
|
||||
@@ -84,11 +90,8 @@ func New(db *gorm.DB, authService *auth.Service, frontend fs.FS, log *zap.Logger
|
||||
protected.POST("/runs/:id/finish", middleware.RequirePermission("sop.execute"), runHandler.Finish)
|
||||
protected.POST("/runs/:id/feedback", middleware.RequirePermission("runs.feedback"), runHandler.Feedback)
|
||||
|
||||
protected.GET("/knowledge-cards", middleware.RequirePermission("knowledge.view"), knowledgeHandler.List)
|
||||
protected.POST("/knowledge-cards", middleware.RequirePermission("knowledge.edit"), knowledgeHandler.Create)
|
||||
protected.GET("/knowledge-cards/:id/versions", middleware.RequirePermission("knowledge.view"), knowledgeHandler.Versions)
|
||||
protected.PUT("/knowledge-cards/:id", middleware.RequirePermission("knowledge.edit"), knowledgeHandler.Update)
|
||||
protected.DELETE("/knowledge-cards/:id", middleware.RequirePermission("knowledge.edit"), knowledgeHandler.Delete)
|
||||
protected.GET("/scenarios/:id/knowledge-graph", middleware.RequirePermission("knowledge.view"), knowledgeHandler.GetGraph)
|
||||
protected.PUT("/scenarios/:id/knowledge-graph", middleware.RequirePermission("knowledge.edit"), knowledgeHandler.ReplaceGraph)
|
||||
|
||||
router.NoRoute(spaHandler(frontend))
|
||||
return router
|
||||
|
||||
44
internal/httpserver/server_test.go
Normal file
44
internal/httpserver/server_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package httpserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/auth"
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/config"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func TestSDKFilesAreServedOverHTTP(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
frontend := fstest.MapFS{
|
||||
"index.html": &fstest.MapFile{Data: []byte("<html>ok</html>")},
|
||||
}
|
||||
sdkFS := fstest.MapFS{
|
||||
"index.js": &fstest.MapFile{Data: []byte("export function create() {}")},
|
||||
"index.iife.js": &fstest.MapFile{Data: []byte("var IqudooSalesScenario = {};")},
|
||||
}
|
||||
handler := New(nil, auth.NewService(nil, config.AuthConfig{}), frontend, sdkFS, zap.NewNop(), "test")
|
||||
|
||||
for _, path := range []string{"/sdk/index.js", "/sdk/index.iife.js"} {
|
||||
req := httptest.NewRequest(http.MethodGet, path, nil)
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("GET %s status = %d, want %d", path, rec.Code, http.StatusOK)
|
||||
}
|
||||
if rec.Header().Get("Access-Control-Allow-Origin") != "*" {
|
||||
t.Fatalf("GET %s missing open CORS header", path)
|
||||
}
|
||||
if got := rec.Header().Get("Content-Type"); got != "text/javascript; charset=utf-8" {
|
||||
t.Fatalf("GET %s Content-Type = %q, want text/javascript", path, got)
|
||||
}
|
||||
if rec.Body.Len() == 0 {
|
||||
t.Fatalf("GET %s returned empty body", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user