""" Folders API router. Source roots are config-driven (PHOTO_DIRS in .env → backend bootstrap on startup); this router only exposes read access and a manual rescan trigger. Adding/removing source roots happens by editing docker-compose.yml + .env and restarting the stack. """ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession import os from app.database import get_db from app.models import Folder, SourceRoot router = APIRouter() @router.get("") async def get_folders(db: AsyncSession = Depends(get_db)): """Get all source folders""" # Get source roots instead of regular folders result = await db.execute(select(SourceRoot).where(SourceRoot.is_active == True)) source_roots = result.scalars().all() folders_list = [] for root in source_roots: # Get photo count for this source root folder_result = await db.execute( select(Folder).where(Folder.source_root_id == root.id) ) folders = folder_result.scalars().all() photo_count = sum(f.photo_count for f in folders) folders_list.append({ "id": root.id, "name": root.name or os.path.basename(root.path), "path": root.path, "photo_count": photo_count }) return {"folders": folders_list} @router.post("/{folder_id}/scan") async def scan_folder(folder_id: str, db: AsyncSession = Depends(get_db)): """Trigger manual re-scan of source root folder""" from app.tasks.celery import celery_app result = await db.execute(select(SourceRoot).where(SourceRoot.id == folder_id)) source_root = result.scalar_one_or_none() if not source_root: raise HTTPException(status_code=404, detail="Source folder not found") # Queue scan task using the task name defined in the decorator task = celery_app.send_task('scan_folder', args=[source_root.path, source_root.id]) return {"status": "success", "message": f"Scan queued for {source_root.path}", "task_id": task.id}