feat: storage management — disk usage, cleanup API, scheduled cleanup task

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-03 22:32:36 +05:00
parent b1eafa4e0b
commit 397b999558
4 changed files with 117 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
from fastapi import APIRouter, Depends, HTTPException
from app.api.deps import get_current_user
from app.models.user import User, UserRole
from app.services.storage import get_disk_usage
from app.tasks.cleanup import cleanup_old_data_task
router = APIRouter(prefix="/api/settings", tags=["settings"])
@router.get("/storage")
async def storage_info(user: User = Depends(get_current_user)):
return get_disk_usage()
@router.post("/cleanup")
async def trigger_cleanup(
retention_days: int | None = None,
user: User = Depends(get_current_user),
):
if user.role != UserRole.admin:
raise HTTPException(403, "Admin access required")
cleanup_old_data_task.delay(retention_days)
return {"message": "Cleanup started"}
+57
View File
@@ -0,0 +1,57 @@
import os
import shutil
from datetime import datetime, timedelta, timezone
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.config import settings
from app.models.export_file import ExportFile
from app.models.recording import Recording
from app.models.transcription import Transcription
def get_disk_usage() -> dict:
upload_size = _dir_size(settings.upload_dir)
export_size = _dir_size(settings.export_dir)
return {
"uploads_bytes": upload_size,
"exports_bytes": export_size,
"total_bytes": upload_size + export_size,
"total_gb": round((upload_size + export_size) / (1024 ** 3), 2),
}
def _dir_size(path: str) -> int:
total = 0
if not os.path.exists(path):
return 0
for dirpath, _, filenames in os.walk(path):
for f in filenames:
fp = os.path.join(dirpath, f)
total += os.path.getsize(fp)
return total
def cleanup_old_data(db: Session, retention_days: int | None = None):
days = retention_days or settings.retention_days
cutoff = datetime.now(timezone.utc) - timedelta(days=days)
old_recordings = db.execute(
select(Recording).where(Recording.created_at < cutoff)
).scalars().all()
deleted_count = 0
for recording in old_recordings:
if os.path.exists(recording.file_path):
os.remove(recording.file_path)
if recording.transcription:
for protocol in recording.transcription.protocols:
for export_file in protocol.export_files:
if os.path.exists(export_file.file_path):
os.remove(export_file.file_path)
db.delete(recording)
deleted_count += 1
db.commit()
return {"deleted_recordings": deleted_count}
+10
View File
@@ -0,0 +1,10 @@
from app.tasks.celery_app import celery_app
from app.tasks.transcription import SyncSession
from app.services.storage import cleanup_old_data
@celery_app.task(name="app.tasks.cleanup.cleanup_old_data")
def cleanup_old_data_task(retention_days: int | None = None):
with SyncSession() as db:
result = cleanup_old_data(db, retention_days)
return result