"""API galerie admin — impression et suppression de photos.""" import logging from fastapi import APIRouter, Request, Query from fastapi.responses import JSONResponse, RedirectResponse logger = logging.getLogger(__name__) router = APIRouter() @router.get("/admin/api/gallery/photos") async def admin_get_photos( request: Request, page: int = Query(default=1, ge=1), limit: int = Query(default=24, ge=1, le=100), ): """Liste des photos pour la galerie admin.""" if not request.session.get("authenticated"): return JSONResponse({"error": "Non authentifié"}, status_code=401) pb = request.app.state.photobooth_service all_photos = await pb.get_media_collection(limit=500) photos = [p for p in all_photos if _is_image(p)] total = len(photos) start = (page - 1) * limit page_photos = photos[start:start + limit] for p in page_photos: pid = _get_id(p) p["full_url"] = pb.media_url(pid) p["thumb_url"] = pb.thumbnail_url(pid) return {"photos": page_photos, "total": total, "page": page, "pages": max(1, (total + limit - 1) // limit)} @router.post("/admin/api/gallery/print/{photo_id}") async def admin_print_photo( request: Request, photo_id: str, copies: int = Query(default=1, ge=1, le=3), ): """Impression directe depuis la galerie admin.""" if not request.session.get("authenticated"): return JSONResponse({"error": "Non authentifié"}, status_code=401) pb = request.app.state.photobooth_service printer_svc = request.app.state.printer_service led = request.app.state.led_service ws = request.app.state.ws_manager # Reconstruit le chemin du fichier depuis l'ID from pathlib import Path import re cfg = request.app.state.config # photobooth-app identifiant → chemin fichier media_dir = cfg.photobooth.media_dir # Cherche le fichier correspondant filename = _find_file(media_dir, photo_id) if not filename: return JSONResponse({"error": f"Fichier introuvable pour {photo_id}"}, status_code=404) thumb_url = pb.thumbnail_url(photo_id) entry = await printer_svc.add_request(str(filename), thumb_url, copies) if cfg.print.mode == "direct": led.play("printing") result = await printer_svc.execute_print(entry["id"], copies) await ws.broadcast({"type": "print_result", "result": result}) if result["success"]: led.play("finished") else: led.play("error") return result await ws.broadcast({"type": "print_request", "entry": entry}) return {"ok": True, "entry": entry, "mode": cfg.print.mode} @router.delete("/admin/api/gallery/{photo_id}") async def admin_delete_photo(request: Request, photo_id: str): """Supprime une photo via l'API photobooth-app.""" if not request.session.get("authenticated"): return JSONResponse({"error": "Non authentifié"}, status_code=401) pb = request.app.state.photobooth_service ws = request.app.state.ws_manager ok = await pb.delete_media(photo_id) if ok: await ws.broadcast({"type": "photo_deleted", "photo_id": photo_id}) return {"ok": ok, "photo_id": photo_id} def _is_image(item: dict) -> bool: t = item.get("type", item.get("mediaitem_type", "image")) return str(t).lower() in ("image", "still", "photo") def _get_id(item: dict) -> str: return str(item.get("id", item.get("filename", item.get("uid", "")))) def _find_file(media_dir: str, photo_id: str): """Cherche un fichier image correspondant à l'identifiant dans le répertoire media.""" from pathlib import Path base = Path(media_dir) if not base.exists(): return None # L'ID peut être le stem du filename for ext in (".jpg", ".jpeg", ".png"): f = base / f"{photo_id}{ext}" if f.exists(): return f # Cherche dans les sous-dossiers matches = list(base.rglob(f"{photo_id}{ext}")) if matches: return matches[0] return None