fix: DevTools 记忆查询跨用户支持 + 会话监看路由权限修正

- memory_handler: Query/List/Add 支持管理员通过 user_id 参数跨用户查询
- router: sessions/active 移到 admin 路由组 (需要管理员权限)
- devtools: sessions 代理路径更新为 /api/v1/admin/sessions/active
This commit is contained in:
2026-05-16 22:04:30 +08:00
parent 15a22737a2
commit 4af9414646
3 changed files with 81 additions and 19 deletions
@@ -5,7 +5,9 @@ import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
@@ -30,8 +32,16 @@ func NewMemoryHandler(aiCoreURL string) *MemoryHandler {
}
// Query 搜索用户记忆 — 代理 GET /api/v1/memory/search?user_id=...&q=...
// 管理员可通过 user_id 查询参数查询任意用户的记忆
func (h *MemoryHandler) Query(c *gin.Context) {
userID := middleware.GetUserID(c)
authUserID := middleware.GetUserID(c)
userID := c.Query("user_id")
// 非管理员只能查询自己的记忆;管理员可通过查询参数指定目标用户
if !strings.HasPrefix(authUserID, "admin_") || userID == "" {
userID = authUserID
}
query := c.Query("q")
if query == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "查询参数q不能为空"})
@@ -43,7 +53,12 @@ func (h *MemoryHandler) Query(c *gin.Context) {
resp, err := h.client.Get(url)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
log.Printf("[memory] AI-Core 不可达 (Query): %v", err)
c.JSON(http.StatusBadGateway, gin.H{
"error": fmt.Sprintf("AI-Core 不可达: %v", err),
"errorType": "ai_core_unreachable",
"hint": "AI-Core 服务未启动或不可达,请先在「服务管理」面板中启动 AI-Core",
})
return
}
defer resp.Body.Close()
@@ -56,14 +71,26 @@ func (h *MemoryHandler) Query(c *gin.Context) {
}
// List 列出用户所有记忆 — 代理 GET /api/v1/memory?user_id=...
// 管理员可通过 user_id 查询参数查询任意用户的记忆
func (h *MemoryHandler) List(c *gin.Context) {
userID := middleware.GetUserID(c)
authUserID := middleware.GetUserID(c)
userID := c.Query("user_id")
// 非管理员只能查询自己的记忆;管理员可通过查询参数指定目标用户
if !strings.HasPrefix(authUserID, "admin_") || userID == "" {
userID = authUserID
}
url := fmt.Sprintf("%s/api/v1/memory?user_id=%s", h.aiCoreURL, userID)
resp, err := h.client.Get(url)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
log.Printf("[memory] AI-Core 不可达 (List): %v", err)
c.JSON(http.StatusBadGateway, gin.H{
"error": fmt.Sprintf("AI-Core 不可达: %v", err),
"errorType": "ai_core_unreachable",
"hint": "AI-Core 服务未启动或不可达,请先在「服务管理」面板中启动 AI-Core",
})
return
}
defer resp.Body.Close()
@@ -76,10 +103,12 @@ func (h *MemoryHandler) List(c *gin.Context) {
}
// Add 手动添加记忆 — 代理 POST /api/v1/memory
// 管理员可通过请求体中的 user_id 字段为任意用户添加记忆
func (h *MemoryHandler) Add(c *gin.Context) {
userID := middleware.GetUserID(c)
authUserID := middleware.GetUserID(c)
var req struct {
UserID string `json:"user_id"`
Content string `json:"content" binding:"required"`
Category string `json:"category"`
Priority int `json:"priority"`
@@ -97,6 +126,12 @@ func (h *MemoryHandler) Add(c *gin.Context) {
req.Priority = 1
}
// 管理员可通过请求体指定目标用户,否则使用认证用户
userID := authUserID
if strings.HasPrefix(authUserID, "admin_") && req.UserID != "" {
userID = req.UserID
}
// 转发到 AI-Core
aiReq := map[string]interface{}{
"user_id": userID,
@@ -116,7 +151,12 @@ func (h *MemoryHandler) Add(c *gin.Context) {
resp, err := h.client.Do(httpReq)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
log.Printf("[memory] AI-Core 不可达 (Add): %v", err)
c.JSON(http.StatusBadGateway, gin.H{
"error": fmt.Sprintf("AI-Core 不可达: %v", err),
"errorType": "ai_core_unreachable",
"hint": "AI-Core 服务未启动或不可达,请先在「服务管理」面板中启动 AI-Core",
})
return
}
defer resp.Body.Close()
@@ -146,7 +186,12 @@ func (h *MemoryHandler) Delete(c *gin.Context) {
resp, err := h.client.Do(req)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
log.Printf("[memory] AI-Core 不可达 (Delete): %v", err)
c.JSON(http.StatusBadGateway, gin.H{
"error": fmt.Sprintf("AI-Core 不可达: %v", err),
"errorType": "ai_core_unreachable",
"hint": "AI-Core 服务未启动或不可达,请先在「服务管理」面板中启动 AI-Core",
})
return
}
defer resp.Body.Close()