import html from pathlib import Path from fastapi import APIRouter, Form from fastapi.responses import HTMLResponse, RedirectResponse from ..backups import is_backup_path, list_backups from ..config import BACKUP_SCRIPT from ..shell import run_command from ..templates.layout import page, render_result router = APIRouter() @router.get("/backups", response_class=HTMLResponse) def backups_page(): rows = "" for path in list_backups(): size_mb = path.stat().st_size / 1024 / 1024 backup_name = html.escape(path.name) backup_path = html.escape(str(path), quote=True) restore_cmd = html.escape( f"sudo /home/jiri/workspace/appfactory-tools/scripts/restore-appfactory.sh --force {path}", quote=True, ) rows += f""" {backup_name}
{size_mb:.2f} MB
Obnova je nebezpečná a musí se spustit ručně přes SSH.
""" if not rows: rows = 'Nebyly nalezeny žádné zálohy.' return page( "Zálohy", f"""

Správa záloh

Zálohy neobsahují samotný adresář se zálohami. Obnova starší zálohy by neměla smazat novější soubory .tar.gz. Obnova zůstává ruční, aby nedošlo k nechtěnému přepsání dat.

Dostupné zálohy

{rows}
Záloha Cesta Příkaz pro obnovu Akce
""", ) @router.post("/backups/create", response_class=HTMLResponse) def create_backup(): result = run_command([BACKUP_SCRIPT]) status = "OK" if result.returncode == 0 else "FAILED" return render_result( title=f"Vytvoření zálohy: {status}", back_url="/portal/backups", sections=[("Výstup", result.stdout), ("Chyba", result.stderr)], ) @router.post("/backups/delete") def delete_backup(backup_path: str = Form(...)): target = Path(backup_path) if not is_backup_path(target): return HTMLResponse("Neplatná cesta k záloze", status_code=400) target = target.resolve() if target.exists(): target.unlink() return RedirectResponse(url="/portal/backups", status_code=303)