- Server no longer mirrors app.Runtime services (gov/svc/pwSvc/...): 574 call sites now use accessors in runtime_accessors.go - backgroundLoop (mutex+sync.Once) stops sweeper/publisher/reminder/wsGC goroutines race-free (baseline44161d2areproduced DATA RACE; now green under -race) - goose 00071 duplicate (dialogue merge1da17a28brought two 00071): context-conflict-adjudications renumbered to 00072; dev DB applied only through 00070 so zero data migration - task_finalize tests build minimal app.Runtime; test injection via serverTestOverrides + setOverride* (explicit-nil markers for fail-closed cases)
92 lines
2.6 KiB
Go
92 lines
2.6 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"chat-agent-system/internal/workflowdef"
|
|
)
|
|
|
|
func (s *Server) handleAdminTemplates(w http.ResponseWriter, r *http.Request) {
|
|
user, ok := s.requireWorkflowAdmin(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
assets, err := s.wfDefSvc().ListTemplates(r.Context())
|
|
if err != nil {
|
|
writeSafeError(w, r, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
writeJSONResponse(w, http.StatusOK, map[string]any{"templates": assets})
|
|
case http.MethodPost:
|
|
if err := r.ParseMultipartForm(defaultUploadBodyLimit); err != nil {
|
|
if isRequestBodyTooLarge(err) {
|
|
writeSafeError(w, r, http.StatusRequestEntityTooLarge, "upload too large")
|
|
return
|
|
}
|
|
writeSafeError(w, r, http.StatusBadRequest, "invalid multipart")
|
|
return
|
|
}
|
|
assetKey := strings.TrimSpace(r.FormValue("asset_key"))
|
|
name := strings.TrimSpace(r.FormValue("name"))
|
|
if assetKey == "" {
|
|
assetKey = strings.TrimSpace(r.FormValue("key"))
|
|
}
|
|
if name == "" {
|
|
name = assetKey
|
|
}
|
|
file, header, err := r.FormFile("file")
|
|
if err != nil || assetKey == "" {
|
|
writeSafeError(w, r, http.StatusBadRequest, "asset_key and file required")
|
|
return
|
|
}
|
|
defer file.Close()
|
|
data, err := io.ReadAll(io.LimitReader(file, 32<<20))
|
|
if err != nil {
|
|
writeSafeError(w, r, http.StatusBadRequest, "read file failed")
|
|
return
|
|
}
|
|
tv, err := s.wfDefSvc().UploadTemplate(r.Context(), assetKey, name, data, header.Filename, user.ID)
|
|
if err != nil {
|
|
status := http.StatusBadRequest
|
|
switch {
|
|
case errors.Is(err, workflowdef.ErrUploadRejected):
|
|
status = http.StatusUnsupportedMediaType
|
|
case errors.Is(err, workflowdef.ErrNotAvailable):
|
|
status = http.StatusServiceUnavailable
|
|
}
|
|
writeSafeError(w, r, status, err.Error())
|
|
return
|
|
}
|
|
writeJSONResponse(w, http.StatusCreated, tv)
|
|
default:
|
|
writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed")
|
|
}
|
|
}
|
|
|
|
func (s *Server) handleAdminTemplateVersions(w http.ResponseWriter, r *http.Request) {
|
|
if _, ok := s.requireWorkflowAdmin(w, r); !ok {
|
|
return
|
|
}
|
|
if r.Method != http.MethodGet {
|
|
writeSafeError(w, r, http.StatusMethodNotAllowed, "method not allowed")
|
|
return
|
|
}
|
|
assetKey := strings.TrimSpace(r.PathValue("key"))
|
|
if assetKey == "" {
|
|
writeSafeError(w, r, http.StatusBadRequest, "invalid asset key")
|
|
return
|
|
}
|
|
versions, err := s.wfDefSvc().ListTemplateVersions(r.Context(), assetKey)
|
|
if err != nil {
|
|
writeSafeError(w, r, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
writeJSONResponse(w, http.StatusOK, map[string]any{"versions": versions})
|
|
}
|