Delete associated files when proof or campaign is deleted

Previously, deleting a proof or campaign only removed database records,
leaving orphaned files in the storage directory. Now the delete endpoints
extract file_storage_key from proof versions and delete files via
storage_service before removing database records.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
michael 2025-12-19 06:25:02 -06:00
parent c3396be029
commit 8eb0821c9f

View file

@ -31,6 +31,7 @@ from app.repositories import (
AuditRepository,
DropdownRepository,
)
from app.services.storage_service import storage_service
router = APIRouter()
@ -192,12 +193,23 @@ async def delete_campaign(
db: AsyncSession = Depends(get_db),
user: dict = Depends(get_current_user),
):
"""Delete a campaign."""
"""Delete a campaign and all associated files."""
repo = CampaignRepository(db)
success = await repo.delete(campaign_id)
if not success:
# Get campaign with proofs and versions to extract file keys
campaign = await repo.get_by_id(campaign_id)
if not campaign:
raise HTTPException(status_code=404, detail="Campaign not found")
# Delete files from storage for all proofs
for proof in campaign.proofs:
for version in proof.versions:
if version.file_storage_key:
await storage_service.delete_file(version.file_storage_key)
# Delete database records (cascades to proofs and versions)
await repo.delete(campaign_id)
# Proof endpoints
@router.get("/campaigns/{campaign_id}/proofs", response_model=list[ProofResponse])
@ -279,12 +291,22 @@ async def delete_proof(
db: AsyncSession = Depends(get_db),
user: dict = Depends(get_current_user),
):
"""Delete a proof."""
"""Delete a proof and its associated files."""
repo = ProofRepository(db)
success = await repo.delete(proof_id)
if not success:
# Get proof with versions to extract file keys
proof = await repo.get_by_id(proof_id)
if not proof:
raise HTTPException(status_code=404, detail="Proof not found")
# Delete files from storage
for version in proof.versions:
if version.file_storage_key:
await storage_service.delete_file(version.file_storage_key)
# Delete database records
await repo.delete(proof_id)
# Audit endpoints
@router.post("/proofs/{proof_id}/versions/{version}/flag", response_model=FlaggedItemResponse, status_code=201)