feat(ai): catalogue d'outils lecture & recherche (#79 phase C)
CI / lint (push) Successful in 59s
CI / security (push) Successful in 49s
CI / test (push) Successful in 1m24s
CI / build (push) Successful in 37s
CI / e2e (push) Successful in 10m24s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
CI / lint (push) Successful in 59s
CI / security (push) Successful in 49s
CI / test (push) Successful in 1m24s
CI / build (push) Successful in 37s
CI / e2e (push) Successful in 10m24s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s
This commit is contained in:
@@ -100,3 +100,115 @@ def browse_directory(vault_name: str, path: str = "") -> dict[str, Any]:
|
||||
raise ServiceError("Permission denied", code="permission_denied", status=403) from None
|
||||
|
||||
return {"vault": vault_name, "path": path, "items": items}
|
||||
|
||||
|
||||
def list_all_files(
|
||||
vault_name: str,
|
||||
dir: str = "",
|
||||
limit: int = 200,
|
||||
recursive: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
"""List files in a vault directory sorted by modification time (newest first).
|
||||
|
||||
Unlike :func:`browse_directory`, this returns files only (with metadata:
|
||||
size, mtime, extension) and can recurse into subdirectories. Hidden files
|
||||
and ignored directories are skipped.
|
||||
|
||||
Args:
|
||||
vault_name: Name of the vault.
|
||||
dir: Relative directory path within the vault (empty = root).
|
||||
limit: Maximum number of files to return.
|
||||
recursive: Recurse into subdirectories when True.
|
||||
|
||||
Returns:
|
||||
Dict with ``vault``, ``directory``, ``recursive``, ``count`` and
|
||||
``files``.
|
||||
|
||||
Raises:
|
||||
ServiceError: ``not_found`` (404) if the directory does not exist,
|
||||
``permission_denied`` (403) if it cannot be read.
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from backend.indexer import IGNORED_DIRS
|
||||
|
||||
root = get_vault_root(vault_name)
|
||||
dir_path = resolve_safe_path(root, dir) if dir else root
|
||||
|
||||
if not dir_path.exists() or not dir_path.is_dir():
|
||||
raise ServiceError(
|
||||
f"Directory not found: {dir}",
|
||||
code="not_found",
|
||||
status=404,
|
||||
details={"vault": vault_name, "path": dir},
|
||||
)
|
||||
|
||||
files: list[dict[str, Any]] = []
|
||||
dir_prefix = (dir or "").strip("/")
|
||||
|
||||
try:
|
||||
iterator = dir_path.rglob("*") if recursive else dir_path.iterdir()
|
||||
for entry in iterator:
|
||||
if not entry.is_file():
|
||||
continue
|
||||
if entry.name.startswith("."):
|
||||
continue
|
||||
if entry.name in IGNORED_DIRS:
|
||||
continue
|
||||
|
||||
if recursive and dir_prefix:
|
||||
skip = False
|
||||
try:
|
||||
for part in entry.relative_to(dir_path).parts[:-1]:
|
||||
if part.startswith(".") or part in IGNORED_DIRS:
|
||||
skip = True
|
||||
break
|
||||
except ValueError:
|
||||
pass
|
||||
if skip:
|
||||
continue
|
||||
|
||||
stat = entry.stat()
|
||||
rel_path = str(entry.relative_to(root)).replace("\\", "/")
|
||||
|
||||
if recursive and dir_prefix:
|
||||
try:
|
||||
rel_to_dir = str(entry.parent.relative_to(dir_path)).replace("\\", "/")
|
||||
except ValueError:
|
||||
rel_to_dir = ""
|
||||
else:
|
||||
rel_to_dir = ""
|
||||
|
||||
ext = entry.suffix.lower() if entry.suffix else ""
|
||||
|
||||
file_entry = {
|
||||
"name": entry.name,
|
||||
"path": rel_path,
|
||||
"vault": vault_name,
|
||||
"size": stat.st_size,
|
||||
"modified": stat.st_mtime,
|
||||
"modified_iso": datetime.fromtimestamp(stat.st_mtime, tz=timezone.utc).isoformat(),
|
||||
"extension": ext.lstrip(".") if ext else "",
|
||||
}
|
||||
if rel_to_dir and rel_to_dir != ".":
|
||||
file_entry["rel_dir"] = rel_to_dir
|
||||
|
||||
files.append(file_entry)
|
||||
except PermissionError:
|
||||
raise ServiceError(
|
||||
"Permission denied reading directory",
|
||||
code="permission_denied",
|
||||
status=403,
|
||||
details={"vault": vault_name, "path": dir},
|
||||
) from None
|
||||
|
||||
files.sort(key=lambda f: f["modified"], reverse=True)
|
||||
files = files[:limit]
|
||||
|
||||
return {
|
||||
"vault": vault_name,
|
||||
"directory": dir,
|
||||
"recursive": recursive,
|
||||
"count": len(files),
|
||||
"files": files,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user