126 lines
5.5 KiB
Python
126 lines
5.5 KiB
Python
import io
|
|
import zipfile
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from fastapi.responses import FileResponse, HTMLResponse, StreamingResponse
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.api.deps import get_current_user, get_db
|
|
from app.models.user import User
|
|
from app.schemas.backup import BackupDiffResponse, BackupResponse, BulkActionRequest
|
|
from app.services.backup_service import backup_service
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("", response_model=list[BackupResponse])
|
|
def list_backups(
|
|
search: str | None = Query(default=None),
|
|
backup_type: str | None = Query(default=None, pattern="^(export|binary)$"),
|
|
router_id: int | None = Query(default=None),
|
|
sort_by: str = Query(default="created_at"),
|
|
order: str = Query(default="desc", pattern="^(asc|desc)$"),
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
return backup_service.list_backups(
|
|
db,
|
|
current_user,
|
|
search=search,
|
|
backup_type=backup_type,
|
|
router_id=router_id,
|
|
sort_by=sort_by,
|
|
order=order,
|
|
)
|
|
|
|
|
|
@router.get("/router/{router_id}", response_model=list[BackupResponse])
|
|
def list_router_backups(router_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
return backup_service.list_router_backups(db, current_user, router_id)
|
|
|
|
|
|
@router.post("/routers/export-all")
|
|
def export_all(current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
return backup_service.export_all(db, current_user)
|
|
|
|
|
|
@router.post("/routers/binary-all")
|
|
def binary_all(current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
return backup_service.binary_all(db, current_user)
|
|
|
|
|
|
@router.post("/router/{router_id}/export", response_model=BackupResponse)
|
|
def export_router(router_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
return backup_service.export_router(db, current_user, router_id)
|
|
|
|
|
|
@router.post("/router/{router_id}/binary", response_model=BackupResponse)
|
|
def binary_backup(router_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
return backup_service.binary_backup(db, current_user, router_id)
|
|
|
|
|
|
@router.post("/router/{router_id}/upload/{backup_id}")
|
|
def upload_to_router(router_id: int, backup_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
backup_service.upload_backup_to_router(db, current_user, router_id, backup_id)
|
|
return {"message": "Backup uploaded to router"}
|
|
|
|
|
|
@router.delete("/{backup_id}")
|
|
def delete_backup(backup_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
backup_service.delete_backup(db, current_user, backup_id)
|
|
return {"message": "Backup deleted"}
|
|
|
|
|
|
@router.get("/{backup_id}/download")
|
|
def download_backup(backup_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
backup = backup_service.get_backup_for_user(db, current_user, backup_id)
|
|
return FileResponse(path=backup.file_path, filename=backup.file_name)
|
|
|
|
|
|
@router.get("/{backup_id}/view")
|
|
def view_export(backup_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
backup = backup_service.get_backup_for_user(db, current_user, backup_id)
|
|
if backup.backup_type != "export":
|
|
raise HTTPException(status_code=400, detail="Only export backups can be viewed")
|
|
with open(backup.file_path, "r", encoding="utf-8", errors="ignore") as handle:
|
|
return {"content": handle.read(), "backup": BackupResponse.model_validate(backup_service._serialize_backup(backup))}
|
|
|
|
|
|
@router.post("/{backup_id}/email")
|
|
def email_backup(backup_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
backup_service.email_backup(db, current_user, backup_id)
|
|
return {"message": "Backup sent by email"}
|
|
|
|
|
|
@router.get("/{left_id}/diff/{right_id}", response_model=BackupDiffResponse)
|
|
def diff_backups(left_id: int, right_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
return backup_service.diff_backups(db, current_user, left_id, right_id)
|
|
|
|
|
|
@router.get("/{left_id}/diff/{right_id}/html", response_class=HTMLResponse)
|
|
def diff_backups_html(left_id: int, right_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
result = backup_service.diff_backups(db, current_user, left_id, right_id)
|
|
return HTMLResponse(result["diff_html"])
|
|
|
|
|
|
@router.post("/bulk")
|
|
def bulk_action(payload: BulkActionRequest, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
backups = [backup_service.get_backup_for_user(db, current_user, backup_id) for backup_id in payload.backup_ids]
|
|
if payload.action == "delete":
|
|
for backup in backups:
|
|
backup_service.delete_backup(db, current_user, backup.id, commit=False)
|
|
db.commit()
|
|
return {"message": f"Deleted {len(backups)} backups"}
|
|
if payload.action == "download":
|
|
stream = io.BytesIO()
|
|
with zipfile.ZipFile(stream, "w") as archive:
|
|
for backup in backups:
|
|
archive.write(backup.file_path, backup.file_name)
|
|
stream.seek(0)
|
|
return StreamingResponse(
|
|
stream,
|
|
media_type="application/zip",
|
|
headers={"Content-Disposition": 'attachment; filename="backups.zip"'},
|
|
)
|
|
raise HTTPException(status_code=400, detail="Unsupported bulk action")
|