package server import ( "context" "encoding/json" "errors" "net/http" "strconv" "chat-agent-system/internal/auth" "chat-agent-system/internal/workflowdef" ) func (s *Server) requireWorkflowAdmin(w http.ResponseWriter, r *http.Request) (*auth.UserAccount, bool) { user, ok := s.requireSystemAdmin(w, r) if !ok { return nil, false } if s.wfDefSvc() == nil || !s.wfDefSvc().Available() { writeSafeError(w, r, http.StatusServiceUnavailable, "工作流定义服务需要数据库 IAM") return nil, false } return user, true } func (s *Server) handleAdminWorkflows(w http.ResponseWriter, r *http.Request) { user, ok := s.requireWorkflowAdmin(w, r) if !ok { return } switch r.Method { case http.MethodGet: defs, err := s.wfDefSvc().ListDefinitions(r.Context()) if err != nil { writeDomainError(w, r, http.StatusInternalServerError, err) return } writeJSONResponse(w, http.StatusOK, map[string]any{"workflows": defs}) case http.MethodPost: var req workflowdef.CreateDefinitionInput if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeSafeError(w, r, http.StatusBadRequest, "无效的 JSON") return } def, ver, err := s.wfDefSvc().CreateDefinition(r.Context(), req, user.ID) if err != nil { status := http.StatusBadRequest if errors.Is(err, workflowdef.ErrValidationFailed) { status = http.StatusUnprocessableEntity } writeDomainError(w, r, status, err) return } writeJSONResponse(w, http.StatusCreated, map[string]any{"definition": def, "version": ver}) default: writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed") } } func (s *Server) handleAdminWorkflowByID(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireWorkflowAdmin(w, r); !ok { return } id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil || id <= 0 { writeSafeError(w, r, http.StatusBadRequest, "invalid workflow id") return } if r.Method != http.MethodGet { writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed") return } def, err := s.wfDefSvc().GetDefinition(r.Context(), id) if err != nil { writeDomainError(w, r, http.StatusNotFound, err) return } versions, err := s.wfDefSvc().ListVersions(r.Context(), id) if err != nil { writeDomainError(w, r, http.StatusInternalServerError, err) return } writeJSONResponse(w, http.StatusOK, map[string]any{"definition": def, "versions": versions}) } func (s *Server) handleAdminWorkflowVersion(w http.ResponseWriter, r *http.Request) { user, ok := s.requireWorkflowAdmin(w, r) if !ok { return } workflowID, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil || workflowID <= 0 { writeSafeError(w, r, http.StatusBadRequest, "invalid workflow id") return } version, err := strconv.Atoi(r.PathValue("version")) if err != nil || version <= 0 { writeSafeError(w, r, http.StatusBadRequest, "invalid version") return } switch r.Method { case http.MethodPatch, http.MethodPut: var body struct { Definition workflowdef.VersionDefinition `json:"definition"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeSafeError(w, r, http.StatusBadRequest, "invalid json") return } updated, err := s.wfDefSvc().UpdateDraft(r.Context(), workflowID, version, body.Definition) if err != nil { status := http.StatusBadRequest if errors.Is(err, workflowdef.ErrNotDraft) { status = http.StatusConflict } writeDomainError(w, r, status, err) return } writeJSONResponse(w, http.StatusOK, updated) default: writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed") } _ = user } func (s *Server) handleAdminWorkflowValidate(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireWorkflowAdmin(w, r); !ok { return } if r.Method != http.MethodPost { writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed") return } workflowID, _ := strconv.ParseInt(r.PathValue("id"), 10, 64) version, _ := strconv.Atoi(r.PathValue("version")) res, err := s.wfDefSvc().ValidateVersion(r.Context(), workflowID, version) if err != nil { writeDomainError(w, r, http.StatusNotFound, err) return } writeJSONResponse(w, http.StatusOK, res) } func (s *Server) handleAdminWorkflowPublish(w http.ResponseWriter, r *http.Request) { user, ok := s.requireWorkflowAdmin(w, r) if !ok { return } if r.Method != http.MethodPost { writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed") return } workflowID, _ := strconv.ParseInt(r.PathValue("id"), 10, 64) version, _ := strconv.Atoi(r.PathValue("version")) ver, err := s.wfDefSvc().PublishVersion(r.Context(), workflowID, version, user.ID) if err != nil { status := http.StatusBadRequest if errors.Is(err, workflowdef.ErrValidationFailed) { status = http.StatusUnprocessableEntity } writeDomainError(w, r, status, err) return } if refresher, ok := s.pwSvc().Catalog().(interface { Refresh(context.Context) error }); ok { _ = refresher.Refresh(r.Context()) } writeJSONResponse(w, http.StatusOK, ver) } func (s *Server) handleAdminWorkflowRetire(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireWorkflowAdmin(w, r); !ok { return } if r.Method != http.MethodPost { writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed") return } workflowID, _ := strconv.ParseInt(r.PathValue("id"), 10, 64) version, _ := strconv.Atoi(r.PathValue("version")) ver, err := s.wfDefSvc().RetireVersion(r.Context(), workflowID, version) if err != nil { writeDomainError(w, r, http.StatusBadRequest, err) return } if refresher, ok := s.pwSvc().Catalog().(interface { Refresh(context.Context) error }); ok { _ = refresher.Refresh(r.Context()) } writeJSONResponse(w, http.StatusOK, ver) }