2026-06-01 15:54:25 +00:00
|
|
|
"""Org-scoped filesystem paths."""
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
DATA_ROOT = Path("data")
|
|
|
|
|
UPLOAD_ROOT = Path("uploads")
|
|
|
|
|
PROCESSED_ROOT = Path("processed")
|
|
|
|
|
RAG_CACHE_DIRNAME = "lightrag_caches"
|
|
|
|
|
MEETINGS_DIRNAME = "meetings"
|
2026-06-01 16:16:23 +00:00
|
|
|
DOCUMENTS_DIRNAME = "documents"
|
2026-06-01 15:54:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def org_upload_dir(org_slug: str, user_id: int) -> Path:
|
|
|
|
|
path = UPLOAD_ROOT / org_slug / str(user_id)
|
|
|
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def org_meetings_dir(org_slug: str) -> Path:
|
|
|
|
|
path = PROCESSED_ROOT / org_slug / MEETINGS_DIRNAME
|
|
|
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def org_rag_index_dir(org_slug: str) -> Path:
|
|
|
|
|
path = PROCESSED_ROOT / org_slug / RAG_CACHE_DIRNAME
|
|
|
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
2026-06-01 16:16:23 +00:00
|
|
|
def org_documents_dir(org_slug: str) -> Path:
|
|
|
|
|
path = PROCESSED_ROOT / org_slug / DOCUMENTS_DIRNAME
|
|
|
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def resolve_document_path(org_slug: str, rel_path: str) -> Path:
|
|
|
|
|
base = org_documents_dir(org_slug).resolve()
|
|
|
|
|
full = (base / rel_path).resolve()
|
|
|
|
|
if not str(full).startswith(str(base)):
|
|
|
|
|
raise ValueError("Invalid path")
|
|
|
|
|
return full
|
|
|
|
|
|
|
|
|
|
|
2026-06-01 15:54:25 +00:00
|
|
|
def resolve_meeting_path(org_slug: str, rel_path: str) -> Path:
|
|
|
|
|
"""Resolve relative path under org meetings dir; reject traversal."""
|
|
|
|
|
base = org_meetings_dir(org_slug).resolve()
|
|
|
|
|
full = (base / rel_path).resolve()
|
|
|
|
|
if not str(full).startswith(str(base)):
|
|
|
|
|
raise ValueError("Invalid path")
|
|
|
|
|
return full
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def write_folder_project_meta(folder_path: Path, project_slug: str) -> None:
|
|
|
|
|
meta = {
|
|
|
|
|
"project_slug": project_slug.strip().lower(),
|
|
|
|
|
"created_at": datetime.now().isoformat(),
|
|
|
|
|
}
|
|
|
|
|
(folder_path / ".project.json").write_text(
|
|
|
|
|
json.dumps(meta, ensure_ascii=False),
|
|
|
|
|
encoding="utf-8",
|
|
|
|
|
)
|