Keep slim handlers.go core; move chat/docgov/health/http/context handlers into domain files ≤800 lines without behavior change.
134 lines
4.0 KiB
Go
134 lines
4.0 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"chat-agent-system/internal/ctxmgr"
|
|
)
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 多级上下文与偏好记忆 RESTful 控制器
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// handleGetUserContext 获取单用户私有上下文与个性化偏好
|
|
// user_id 仅允许等于当前认证用户本人(或系统管理员),不再默认回落 user id=1。
|
|
func (s *Server) handleGetUserContext(w http.ResponseWriter, r *http.Request) {
|
|
user, ok := s.requirePrincipal(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
userIDStr := r.URL.Query().Get("user_id")
|
|
projectIDStr := r.URL.Query().Get("project_id")
|
|
sessionID := r.URL.Query().Get("session_id")
|
|
|
|
userID, _ := strconv.ParseInt(userIDStr, 10, 64)
|
|
if userID <= 0 {
|
|
userID = user.ID
|
|
}
|
|
if userID != user.ID && !s.isSystemAdminUser(r.Context(), user) {
|
|
writeJSONResponse(w, http.StatusForbidden, map[string]string{
|
|
"error_code": "ERR_FORBIDDEN",
|
|
"message": "无权查询其他用户的上下文",
|
|
})
|
|
return
|
|
}
|
|
projectID, _ := strconv.ParseInt(projectIDStr, 10, 64)
|
|
|
|
if s.ctxMgr == nil {
|
|
writeSafeError(w, r, http.StatusServiceUnavailable, "context manager not initialized")
|
|
return
|
|
}
|
|
|
|
uCtx, err := s.ctxMgr.GetUserContext(r.Context(), projectID, userID, sessionID)
|
|
if err != nil {
|
|
writeSafeError(w, r, http.StatusInternalServerError, "get user context failed: "+err.Error())
|
|
return
|
|
}
|
|
|
|
writeJSONResponse(w, http.StatusOK, uCtx)
|
|
}
|
|
|
|
// handleUpdateUserPreference 定期整理或前端保存用户习惯偏好
|
|
func (s *Server) handleUpdateUserPreference(w http.ResponseWriter, r *http.Request) {
|
|
user, ok := s.requireAuthenticatedUser(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req UpdateUserPreferenceRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeSafeError(w, r, http.StatusBadRequest, "invalid request body: "+err.Error())
|
|
return
|
|
}
|
|
if req.UserID <= 0 {
|
|
req.UserID = user.ID
|
|
}
|
|
if req.UserID != user.ID && !s.isSystemAdminUser(r.Context(), user) {
|
|
writeJSONResponse(w, http.StatusForbidden, map[string]string{
|
|
"error_code": "ERR_FORBIDDEN",
|
|
"message": "无权修改其他用户的偏好",
|
|
})
|
|
return
|
|
}
|
|
|
|
if s.ctxMgr == nil {
|
|
writeSafeError(w, r, http.StatusServiceUnavailable, "context manager not initialized")
|
|
return
|
|
}
|
|
|
|
pref := &ctxmgr.UserPreference{
|
|
UserID: req.UserID,
|
|
CommunicationStyle: req.CommunicationStyle,
|
|
FocusAreas: req.FocusAreas,
|
|
OutputFormatPref: req.OutputFormatPref,
|
|
CustomInstructions: req.CustomInstructions,
|
|
}
|
|
|
|
if err := s.ctxMgr.UpdateUserPreference(r.Context(), pref); err != nil {
|
|
writeSafeError(w, r, http.StatusInternalServerError, "save user preference failed: "+err.Error())
|
|
return
|
|
}
|
|
|
|
writeJSONResponse(w, http.StatusOK, map[string]any{"status": "ok", "user_id": req.UserID})
|
|
}
|
|
|
|
// handleGetProjectContext 获取项目级多方协同事实黑板与里程碑决策流
|
|
func (s *Server) handleGetProjectContext(w http.ResponseWriter, r *http.Request) {
|
|
user, ok := s.requireAuthenticatedUser(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
projectIDStr := r.URL.Query().Get("project_id")
|
|
projectID, _ := strconv.ParseInt(projectIDStr, 10, 64)
|
|
if projectID <= 0 {
|
|
writeSafeError(w, r, http.StatusBadRequest, "missing or invalid project_id query param")
|
|
return
|
|
}
|
|
|
|
// Membership first: allowAnyStageAccess assumes the caller already passed
|
|
// project membership (see ResolveStageAccess). Without this guard any
|
|
// authenticated user can read an activated project's collaborative context.
|
|
if !s.enforceChatProjectAccess(w, r, user, projectID) {
|
|
return
|
|
}
|
|
if !s.allowAnyStageAccess(r.Context(), projectID, user.ID) {
|
|
s.writeWorkflowAccessDenied(w)
|
|
return
|
|
}
|
|
|
|
if s.ctxMgr == nil {
|
|
writeSafeError(w, r, http.StatusServiceUnavailable, "context manager not initialized")
|
|
return
|
|
}
|
|
|
|
pCtx, err := s.ctxMgr.GetProjectContext(r.Context(), projectID)
|
|
if err != nil {
|
|
writeSafeError(w, r, http.StatusInternalServerError, "get project context failed: "+err.Error())
|
|
return
|
|
}
|
|
|
|
writeJSONResponse(w, http.StatusOK, pCtx)
|
|
}
|