feat: per-photo permanent delete + discarded thumbnail treatment
Discarded photos now look discarded in the grid (50% opacity + grayscale)
with a red trash badge in the corner instead of a bare icon. The discard
action bar gains a "Delete N" button that permanently deletes only the
current selection, complementing the existing "Empty discard pile".
Backend: new DELETE /discard endpoint accepting {photo_ids: [...]} that
permanently removes only listed photos. Skips ids that aren't in the
discard pile so it can never bypass the soft-delete safety net.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ Discard API router
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import APIRouter, Depends, HTTPException, Body
|
||||
from sqlalchemy import select, and_
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -47,7 +47,33 @@ async def empty_discard(db: AsyncSession = Depends(get_db)):
|
||||
select(Photo).where(Photo.is_discarded == True)
|
||||
)
|
||||
photos = result.scalars().all()
|
||||
return await _permanently_delete(db, photos)
|
||||
|
||||
|
||||
@router.delete("")
|
||||
async def delete_discarded(
|
||||
photo_ids: list[str] = Body(..., embed=True),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Permanently delete a specific subset of discarded photos. The photos
|
||||
must already be in the discard pile — non-discarded ids are skipped so
|
||||
this can never bypass the soft-delete safety net.
|
||||
"""
|
||||
if not photo_ids:
|
||||
return {"status": "success", "deleted": 0, "file_errors": 0}
|
||||
result = await db.execute(
|
||||
select(Photo).where(
|
||||
and_(Photo.id.in_(photo_ids), Photo.is_discarded == True)
|
||||
)
|
||||
)
|
||||
photos = result.scalars().all()
|
||||
return await _permanently_delete(db, photos)
|
||||
|
||||
|
||||
async def _permanently_delete(db: AsyncSession, photos: list[Photo]) -> dict:
|
||||
"""Shared helper: unlink files for the given photos and delete their
|
||||
rows. Per-file errors are counted but don't abort the batch.
|
||||
"""
|
||||
deleted = 0
|
||||
file_errors = 0
|
||||
for photo in photos:
|
||||
|
||||
Reference in New Issue
Block a user