package server import ( "encoding/json" "errors" "net/http" "strconv" "strings" "time" "chat-agent-system/internal/authz" "chat-agent-system/internal/errorevents" "chat-agent-system/internal/sysadmin" ) // 系统管理台:细粒度 system:* 权限(phase-2:管理员 all-or-nothing)。 func (s *Server) handleAdminSystemOverview(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireSystemPermission(w, r, authz.PermSystemOverview); !ok { return } if s.sysadmin() == nil { writeSafeError(w, r, http.StatusServiceUnavailable, "sysadmin service unavailable") return } writeJSONResponse(w, http.StatusOK, s.sysadmin().Overview(r.Context())) } func (s *Server) handleAdminSystemKB(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireSystemPermission(w, r, authz.PermSystemKBRead); !ok { return } if s.sysadmin() == nil { writeSafeError(w, r, http.StatusServiceUnavailable, "sysadmin service unavailable") return } writeJSONResponse(w, http.StatusOK, s.sysadmin().KBInfo()) } func (s *Server) handleAdminSystemFeatures(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireSystemPermission(w, r, authz.PermSystemFeaturesRead); !ok { return } if s.sysadmin() == nil { writeSafeError(w, r, http.StatusServiceUnavailable, "sysadmin service unavailable") return } writeJSONResponse(w, http.StatusOK, map[string]any{"features": s.sysadmin().Features()}) } func (s *Server) handleAdminSystemSettings(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireSystemPermission(w, r, authz.PermSystemSettingsRead); !ok { return } if s.sysadmin() == nil { writeSafeError(w, r, http.StatusServiceUnavailable, "sysadmin service unavailable") return } settings, err := s.sysadmin().ListSettings(r.Context()) if err != nil { writeDomainError(w, r, http.StatusInternalServerError, err) return } writeJSONResponse(w, http.StatusOK, map[string]any{"settings": settings}) } func (s *Server) handleAdminSystemSettingByKey(w http.ResponseWriter, r *http.Request) { user, ok := s.requireSystemPermission(w, r, authz.PermSystemSettingsWrite) if !ok { return } if s.sysadmin() == nil { writeSafeError(w, r, http.StatusServiceUnavailable, "sysadmin service unavailable") return } key := r.PathValue("key") var req struct { Value json.RawMessage `json:"value"` ExpectedRevision *int64 `json:"expected_revision"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeSafeError(w, r, http.StatusBadRequest, "无效的请求体") return } setting, err := s.sysadmin().UpdateSettingEx(r.Context(), sysadmin.SettingUpdate{ Key: key, Value: req.Value, UpdatedBy: user.ID, ExpectedRevision: req.ExpectedRevision, RequestID: r.Header.Get("X-Request-ID"), }) switch { case errors.Is(err, sysadmin.ErrUnknownSetting): writeSafeError(w, r, http.StatusBadRequest, "未知的设置键") case errors.Is(err, sysadmin.ErrSettingReadOnly): writeSafeError(w, r, http.StatusForbidden, "该设置为只读") case errors.Is(err, sysadmin.ErrInvalidSettingValue): writeSafeError(w, r, http.StatusBadRequest, "设置值类型不匹配") case errors.Is(err, sysadmin.ErrExpectedRevisionRequired): writeSafeError(w, r, http.StatusBadRequest, "该设置需要 expected_revision") case errors.Is(err, sysadmin.ErrSettingRevisionConflict): writeSafeError(w, r, http.StatusConflict, `{"error":"SETTING_REVISION_CONFLICT","message":"设置版本冲突,请刷新后重试"}`) case errors.Is(err, sysadmin.ErrStoreUnavailable): writeSafeError(w, r, http.StatusServiceUnavailable, "设置存储不可用") case err != nil: writeDomainError(w, r, http.StatusInternalServerError, err) default: writeJSONResponse(w, http.StatusOK, setting) } } func (s *Server) handleAdminSystemSettingAudits(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireSystemPermission(w, r, authz.PermSystemAuditRead); !ok { return } if s.sysadmin() == nil { writeSafeError(w, r, http.StatusServiceUnavailable, "sysadmin service unavailable") return } key := r.PathValue("key") limit := 50 if raw := r.URL.Query().Get("limit"); raw != "" { n, err := strconv.Atoi(raw) if err != nil || n < 0 { writeSafeError(w, r, http.StatusBadRequest, "无效的 limit") return } limit = n } audits, err := s.sysadmin().ListPolicyAudits(r.Context(), key, limit) switch { case errors.Is(err, sysadmin.ErrUnknownSetting): writeSafeError(w, r, http.StatusBadRequest, "未知的设置键") case errors.Is(err, sysadmin.ErrStoreUnavailable): writeSafeError(w, r, http.StatusServiceUnavailable, "设置存储不可用") case err != nil: writeDomainError(w, r, http.StatusInternalServerError, err) default: writeJSONResponse(w, http.StatusOK, map[string]any{"audits": audits}) } } func (s *Server) handleAdminErrorEvents(w http.ResponseWriter, r *http.Request) { if _, ok := s.requireSystemPermission(w, r, authz.PermSystemAuditRead); !ok { return } store := errorevents.Active() if store == nil { writeSafeError(w, r, http.StatusServiceUnavailable, "错误审计存储不可用") return } q := r.URL.Query() limit := 50 if raw := q.Get("limit"); raw != "" { n, err := strconv.Atoi(raw) if err != nil || n < 0 { writeSafeError(w, r, http.StatusBadRequest, "无效的 limit") return } limit = n } filter := errorevents.Filter{ Code: q.Get("code"), RequestID: q.Get("request_id"), Class: q.Get("class"), Limit: limit, } if raw := strings.TrimSpace(q.Get("since")); raw != "" { ts, err := time.Parse(time.RFC3339, raw) if err != nil { writeSafeError(w, r, http.StatusBadRequest, "无效的 since") return } filter.Since = ts } if raw := strings.TrimSpace(q.Get("until")); raw != "" { ts, err := time.Parse(time.RFC3339, raw) if err != nil { writeSafeError(w, r, http.StatusBadRequest, "无效的 until") return } filter.Until = ts } events, err := store.List(r.Context(), filter) if err != nil { writeDomainError(w, r, http.StatusInternalServerError, err) return } writeJSONResponse(w, http.StatusOK, map[string]any{"events": events}) }