fix: photos folder_id filter accepts source root ids too
GET /folders returns SourceRoot rows (the top-level scan paths shown in the LeftSidebar tree), but photos.folder_id points to a Folder row (a directory under a source root), and the photos list endpoint was matching Photo.folder_id == folder_id literally. Result: clicking "MulitaTest" in the sidebar sent the source root id, which never matched any photo, so the timeline went empty even though the photo_count badge showed 5. Fix: when the folder_id param matches a SourceRoot, expand it to every child Folder.id under that root and use IN. Falls back to the literal match for actual folder ids. If a source root has no child folder rows yet, returns no photos (rather than the whole library) so a half-scanned root doesn't accidentally show everything. The longer-term cleanup is to deduplicate the source_root / folder rows the scanner is creating on each rescan, but this makes the navigation work today. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import Photo, Folder, Tag, PhotoTag
|
||||
from app.models.folders import SourceRoot
|
||||
from app.models.heaps import heap_photos
|
||||
from app.schemas.photos import PhotoResponse, PhotoUpdate, PhotoListResponse, BulkAction
|
||||
from app.config import settings
|
||||
@@ -67,9 +68,27 @@ async def list_photos(
|
||||
if date_to:
|
||||
filters.append(Photo.taken_at <= date_to)
|
||||
|
||||
# Folder filter
|
||||
# Folder filter — the sidebar exposes "source roots" (top-level scan
|
||||
# paths) under the same UI affordance as folders, so the same param has
|
||||
# to accept either a folder id or a source root id. If the value matches
|
||||
# a source root, expand to every folder under that root and use IN.
|
||||
if folder_id:
|
||||
filters.append(Photo.folder_id == folder_id)
|
||||
sr_check = await db.execute(
|
||||
select(SourceRoot.id).where(SourceRoot.id == folder_id)
|
||||
)
|
||||
if sr_check.scalar_one_or_none() is not None:
|
||||
child_folders = await db.execute(
|
||||
select(Folder.id).where(Folder.source_root_id == folder_id)
|
||||
)
|
||||
child_ids = [row[0] for row in child_folders.all()]
|
||||
if child_ids:
|
||||
filters.append(Photo.folder_id.in_(child_ids))
|
||||
else:
|
||||
# Source root with no folder rows yet — match nothing rather
|
||||
# than returning the entire library.
|
||||
filters.append(Photo.id == '__no_match__')
|
||||
else:
|
||||
filters.append(Photo.folder_id == folder_id)
|
||||
|
||||
# Media type filter
|
||||
if media_type:
|
||||
|
||||
Reference in New Issue
Block a user