"""API de gestion des actions photobooth-app + mapping bouton.""" import logging from fastapi import APIRouter, Request, Body from fastapi.responses import JSONResponse logger = logging.getLogger(__name__) router = APIRouter() @router.get("/actions/photobooth") async def get_pb_actions(request: Request): """Retourne les actions image de photobooth-app + le mapping bouton actuel.""" pb = request.app.state.photobooth_service cfg = request.app.state.config pb_config = await pb.read_pb_config() actions = pb_config.get("actions", {}).get("image", []) # Enrichit avec l'index for i, action in enumerate(actions): action["_index"] = i return { "actions": actions, "button_mapping": cfg.button_actions, } @router.get("/actions/assets") async def get_assets(request: Request): """Liste les cadres et fonds disponibles dans userdata.""" pb = request.app.state.photobooth_service frames = await pb.list_userdata_frames() backgrounds = await pb.list_userdata_backgrounds() return {"frames": frames, "backgrounds": backgrounds} @router.put("/actions/mapping") async def update_button_mapping( request: Request, mapping: dict = Body(...), ): """ Met à jour le mapping clics → actions. Body: { "1": {"label": "...", "photobooth_index": 0}, ... } """ config_svc = request.app.state.config_service # Validation basique for k, v in mapping.items(): if not isinstance(v, dict) or "photobooth_index" not in v: return JSONResponse({"error": f"Format invalide pour clic {k}"}, status_code=400) config_svc.save_button_actions(mapping) request.app.state.config.button_actions = mapping # Met aussi à jour le button_service btn = request.app.state.button_service btn._btn_actions = mapping logger.info("Mapping bouton mis à jour: %s", mapping) return {"ok": True, "mapping": mapping} @router.put("/actions/photobooth/{index}") async def update_pb_action( request: Request, index: int, updates: dict = Body(...), ): """ Met à jour une action image de photobooth-app (cadre, fond, countdown, etc.) updates peut contenir: countdown_capture, img_frame_file, img_background_file, remove_background, image_filter, name """ pb = request.app.state.photobooth_service pb_config = await pb.read_pb_config() actions = pb_config.get("actions", {}).get("image", []) if index < 0 or index >= len(actions): return JSONResponse({"error": f"Index {index} invalide (max: {len(actions)-1})"}, status_code=400) action = actions[index] # Mise à jour des champs autorisés allowed_root = {"name"} allowed_processing = {"remove_background", "img_frame_file", "img_background_file", "image_filter", "fill_background_enable", "fill_background_color", "img_background_enable", "texts_enable"} allowed_jobcontrol = {"countdown_capture"} for key, value in updates.items(): if key in allowed_root: action[key] = value elif key in allowed_processing: action.setdefault("processing", {})[key] = value elif key in allowed_jobcontrol: action.setdefault("jobcontrol", {})[key] = value pb_config["actions"]["image"][index] = action await pb.write_pb_config(pb_config) logger.info("Action %d mise à jour: %s", index, list(updates.keys())) return {"ok": True, "index": index, "action": action} @router.post("/actions/trigger/{index}") async def trigger_action(request: Request, index: int): """Déclenche une action directement (test).""" pb = request.app.state.photobooth_service led = request.app.state.led_service btn = request.app.state.button_service btn.relay_off() try: result = await pb.trigger_image_action(index) return {"ok": True, "index": index, "result": result} except Exception as e: led.play("error") btn.relay_on() return JSONResponse({"error": str(e)}, status_code=500)