Перейти к содержанию

File Manager

Файловый менеджер для админ-панели.

Установка

uv add viai-kit-admin-files

API

Получение списка файлов

from viai_kit.admin.files import list_files

files = list_files("/var/www", root="/var/www")
for f in files:
    type_icon = "📁" if f['is_dir'] else "📄"
    print(f"{type_icon} {f['name']} ({f['size']} bytes)")

Чтение файла

from viai_kit.admin.files import read_file

content = read_file("/var/www/config.json", root="/var/www")
print(content)

Запись файла

from viai_kit.admin.files import write_file

write_file("/var/www/config.json", '{"key": "value"}', root="/var/www")

Создание директории

from viai_kit.admin.files import create_directory

create_directory("/var/www/new-folder", root="/var/www")

Удаление

from viai_kit.admin.files import delete_path

delete_path("/var/www/old-file.txt", root="/var/www")

Информация о диске

from viai_kit.admin.files import get_disk_usage

usage = get_disk_usage("/var/www")
print(f"Disk: {usage['used'] / 1024**3:.1f} / {usage['total'] / 1024**3:.1f} GB")

Структуры данных

FileItem

class FileItem(TypedDict):
    name: str
    path: str
    is_dir: bool
    size: int
    modified: str
    permissions: str
    mime_type: str | None

DiskUsage

class DiskUsage(TypedDict):
    path: str
    total: int
    used: int
    free: int
    percent: float

Безопасность

Все операции проверяют, что путь находится внутри разрешённой root директории:

def validate_path(path: str, root: str) -> str:
    """Проверяет и нормализует путь."""
    full_path = os.path.abspath(os.path.join(root, path.lstrip("/")))
    if not full_path.startswith(os.path.abspath(root)):
        raise PermissionError(f"Access denied: {path} is outside root {root}")
    return full_path

FastAPI интеграция

from fastapi import FastAPI, APIRouter, UploadFile, File
from fastapi.responses import FileResponse
from viai_kit.admin.files import list_files, read_file, write_file

router = APIRouter(prefix="/files")
FILES_ROOT = "/var/www"

@router.get("/list")
def list_dir(path: str = "/"):
    return list_files(path, root=FILES_ROOT)

@router.get("/read")
def read(path: str):
    return {"content": read_file(path, root=FILES_ROOT)}

@router.post("/write")
def write(path: str, content: str):
    write_file(path, content, root=FILES_ROOT)
    return {"status": "ok"}

@router.get("/download")
def download(path: str):
    full_path = validate_path(path, FILES_ROOT)
    return FileResponse(full_path)

Зависимости

  • aiofiles>=23.0.0 — асинхронные файловые операции