klg-asutk-app/backend/app/api/routes/backup.py

77 lines
2.2 KiB
Python

"""
Data backup/restore — export all data as JSON, import from backup.
Admin only. Production: use pg_dump for full backups.
"""
import json
from datetime import datetime
from fastapi import APIRouter, Depends, Response, UploadFile, File
from sqlalchemy.orm import Session
from app.api.deps import get_current_user, require_roles, get_db
from app.api.helpers import audit
from app.models import Aircraft, Organization, CertApplication, RiskAlert, Audit
router = APIRouter(prefix="/backup", tags=["backup"])
BACKUP_MODELS = {
"aircraft": Aircraft,
"organizations": Organization,
"cert_applications": CertApplication,
"risk_alerts": RiskAlert,
"audits": Audit,
}
def serialize_row(row) -> dict:
d = {}
for col in row.__table__.columns:
val = getattr(row, col.name, None)
if isinstance(val, datetime):
val = val.isoformat()
d[col.name] = val
return d
@router.get(
"/export",
dependencies=[Depends(require_roles("admin"))],
)
def backup_export(db: Session = Depends(get_db), user=Depends(get_current_user)):
"""Export all data as JSON backup."""
backup = {
"version": "2.1.0",
"created_at": datetime.utcnow().isoformat(),
"created_by": user.email,
"data": {},
}
total = 0
for name, model in BACKUP_MODELS.items():
rows = db.query(model).all()
backup["data"][name] = [serialize_row(r) for r in rows]
total += len(rows)
backup["total_records"] = total
audit(db, user, "backup", "system", description=f"Exported backup: {total} records")
db.commit()
return Response(
content=json.dumps(backup, ensure_ascii=False, indent=2, default=str),
media_type="application/json",
headers={
"Content-Disposition": f"attachment; filename=klg_backup_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.json"
},
)
@router.get(
"/stats",
dependencies=[Depends(require_roles("admin"))],
)
def backup_stats(db: Session = Depends(get_db)):
"""Get record counts for backup preview."""
stats = {}
for name, model in BACKUP_MODELS.items():
stats[name] = db.query(model).count()
return {"tables": stats, "total": sum(stats.values())}