local_backup.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. """API routes for scheduled local backups."""
  2. import logging
  3. from fastapi import APIRouter, Path
  4. from fastapi.responses import FileResponse, JSONResponse
  5. from backend.app.core.auth import RequirePermissionIfAuthEnabled
  6. from backend.app.core.permissions import Permission
  7. from backend.app.models.user import User
  8. from backend.app.services.local_backup import local_backup_service
  9. logger = logging.getLogger(__name__)
  10. router = APIRouter(prefix="/local-backup", tags=["local-backup"])
  11. @router.get("/status")
  12. async def get_status(
  13. _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_BACKUP),
  14. ):
  15. """Get local backup scheduler status and configuration."""
  16. settings = await local_backup_service._load_settings()
  17. status = local_backup_service.get_status()
  18. return {
  19. **status,
  20. "enabled": settings["enabled"],
  21. "schedule": settings["schedule"],
  22. "time": settings["time"],
  23. "retention": settings["retention"],
  24. "path": settings["path"],
  25. "default_path": str(local_backup_service._resolve_backup_dir("")),
  26. }
  27. @router.post("/run")
  28. async def trigger_backup(
  29. _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_BACKUP),
  30. ):
  31. """Trigger a local backup immediately."""
  32. result = await local_backup_service.run_backup()
  33. return result
  34. @router.get("/backups")
  35. async def list_backups(
  36. _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_BACKUP),
  37. ):
  38. """List existing backup files."""
  39. settings = await local_backup_service._load_settings()
  40. return local_backup_service.list_backups(settings["path"])
  41. @router.get("/backups/{filename}/download")
  42. async def download_backup(
  43. filename: str = Path(..., description="Backup filename to download"),
  44. _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_BACKUP),
  45. ):
  46. """Download a specific backup file."""
  47. settings = await local_backup_service._load_settings()
  48. file_path = local_backup_service.resolve_backup_file(settings["path"], filename)
  49. if file_path is None:
  50. return JSONResponse(status_code=404, content={"success": False, "message": "Backup not found"})
  51. return FileResponse(
  52. path=file_path,
  53. filename=filename,
  54. media_type="application/zip",
  55. )
  56. @router.post("/backups/{filename}/restore")
  57. async def restore_backup(
  58. filename: str = Path(..., description="Backup filename to restore"),
  59. _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_RESTORE),
  60. ):
  61. """Restore from a scheduled backup file on the server."""
  62. import io
  63. from fastapi import UploadFile
  64. from fastapi.responses import JSONResponse
  65. settings = await local_backup_service._load_settings()
  66. file_path = local_backup_service.resolve_backup_file(settings["path"], filename)
  67. if file_path is None:
  68. return JSONResponse(status_code=404, content={"success": False, "message": "Backup not found"})
  69. from backend.app.api.routes.settings import restore_backup as settings_restore_backup
  70. from backend.app.core.database import async_session
  71. content = file_path.read_bytes()
  72. upload = UploadFile(filename=filename, file=io.BytesIO(content))
  73. async with async_session() as db:
  74. return await settings_restore_backup(file=upload, db=db)
  75. @router.delete("/backups/{filename}")
  76. async def delete_backup(
  77. filename: str = Path(..., description="Backup filename to delete"),
  78. _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_BACKUP),
  79. ):
  80. """Delete a specific backup file."""
  81. settings = await local_backup_service._load_settings()
  82. return local_backup_service.delete_backup(settings["path"], filename)