Files
Agent-System/internal/server/workflow_terminate_handlers.go
T
weichenandCursor f6813cc272 feat(api): add additive HTTP/SSE error envelopes
Public errors now emit code, safe message, and request_id while keeping the legacy error field. Raw SQL, paths, tokens, and XSS payloads are stripped; the frontend branches on code instead of substring matching.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:40:56 +00:00

81 lines
2.8 KiB
Go

package server
import (
"encoding/json"
"errors"
"net/http"
"strconv"
"chat-agent-system/internal/projectinstance"
)
func (s *Server) handleTerminationPreview(w http.ResponseWriter, r *http.Request) {
if s.instSvc == nil || !s.instSvc.Available() {
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE"}`)
return
}
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil || instanceID <= 0 {
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM"}`)
return
}
user, err := s.authenticateUser(r)
if err != nil || user == nil {
writeSafeError(w, r, http.StatusUnauthorized, `{"error":"ERR_UNAUTHENTICATED"}`)
return
}
detail, err := s.instSvc.GetInstanceDetail(r.Context(), instanceID)
if err != nil {
writeSafeError(w, r, http.StatusNotFound, `{"error":"ERR_NOT_FOUND"}`)
return
}
isCreator, _ := s.pwSvc.IsProjectCreator(r.Context(), detail.Instance.ProjectID, user.ID)
preview, err := s.instSvc.GetTerminationPreview(r.Context(), instanceID, detail.Instance.ProjectID, user.ID, isCreator)
if err != nil {
writeProjectInstanceError(w, err)
return
}
writeJSONResponse(w, http.StatusOK, preview)
}
func (s *Server) handleTerminateWorkflowInstance(w http.ResponseWriter, r *http.Request) {
if s.instSvc == nil || !s.instSvc.Available() {
writeSafeError(w, r, http.StatusServiceUnavailable, `{"error":"ERR_NOT_AVAILABLE"}`)
return
}
instanceID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil || instanceID <= 0 {
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM"}`)
return
}
user, err := s.authenticateUser(r)
if err != nil || user == nil {
writeSafeError(w, r, http.StatusUnauthorized, `{"error":"ERR_UNAUTHENTICATED"}`)
return
}
detail, err := s.instSvc.GetInstanceDetail(r.Context(), instanceID)
if err != nil {
writeSafeError(w, r, http.StatusNotFound, `{"error":"ERR_NOT_FOUND"}`)
return
}
var in projectinstance.TerminateInput
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
writeSafeError(w, r, http.StatusBadRequest, `{"error":"ERR_INVALID_PARAM"}`)
return
}
isCreator, _ := s.pwSvc.IsProjectCreator(r.Context(), detail.Instance.ProjectID, user.ID)
res, err := s.instSvc.TerminateInstance(r.Context(), instanceID, detail.Instance.ProjectID, user.ID, isCreator, in)
if err != nil {
switch {
case errors.Is(err, projectinstance.ErrForbiddenNotCreator):
writeSafeError(w, r, http.StatusForbidden, `{"error":"ERR_FORBIDDEN"}`)
case errors.Is(err, projectinstance.ErrTerminationNotAllowed):
writeSafeError(w, r, http.StatusConflict, `{"error":"ERR_TERMINATION_NOT_ALLOWED"}`)
default:
writeSafeError(w, r, http.StatusInternalServerError, `{"error":"ERR_INTERNAL","message":"`+err.Error()+`"}`)
}
return
}
writeJSONResponse(w, http.StatusOK, res)
}