Files
goclaw/internal/http/vault_handler_tree.go
T
viettranx 7810b8b78a fix(vault): agent filter support + rescan agent_key path matching
- Add AgentID to VaultTreeOptions, pass agent_id filter through
  backend tree endpoint and frontend hook
- Fix rescan inferOwnerFromPath: match root-level {agent_key}/...
  folders against agentMap (workspace uses agent_key directly,
  not agents/ prefix). Keep legacy agents/ prefix for compat
- Preserve full relPath for DB storage in all patterns
- Show filename with extension in tree (use path basename, not title)
- Start tree folders collapsed (prevent stuck loading state)
- Remove orphaned useVaultGraphData call from vault-page
- Tenant isolation verified: agentMap built per-tenant via scopeClause
2026-04-12 13:25:15 +07:00

58 lines
1.6 KiB
Go

package http
import (
"log/slog"
"net/http"
"strings"
"github.com/nextlevelbuilder/goclaw/internal/store"
)
// handleVaultTree returns immediate children (files + virtual folders) under
// a given path prefix for lazy-loading the vault sidebar tree.
func (h *VaultHandler) handleVaultTree(w http.ResponseWriter, r *http.Request) {
tenantID := store.TenantIDFromContext(r.Context())
path := r.URL.Query().Get("path")
if strings.Contains(path, "..") || strings.HasPrefix(path, "/") {
slog.Warn("security.vault_tree_traversal", "path", path)
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid path"})
return
}
opts := store.VaultTreeOptions{
Path: path,
AgentID: r.URL.Query().Get("agent_id"),
Scope: r.URL.Query().Get("scope"),
DocTypes: splitCSV(r.URL.Query().Get("doc_type")),
}
if teamID := r.URL.Query().Get("team_id"); teamID != "" {
opts.TeamID = &teamID
}
if opts.TeamID == nil && !store.IsOwnerRole(r.Context()) {
if ids := h.userAccessibleTeamIDs(r.Context()); len(ids) > 0 {
opts.TeamIDs = ids
} else {
empty := ""
opts.TeamID = &empty
}
}
if opts.TeamID != nil && *opts.TeamID != "" {
if !h.validateTeamMembership(r.Context(), w, *opts.TeamID) {
return
}
}
entries, err := h.store.ListTreeEntries(r.Context(), tenantID.String(), opts)
if err != nil {
slog.Warn("vault.tree failed", "error", err)
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to load tree"})
return
}
if entries == nil {
entries = []store.VaultTreeEntry{}
}
writeJSON(w, http.StatusOK, map[string]any{"entries": entries})
}