import json import logging import shutil import uuid from pathlib import Path from backend.config import RACINE, DOSSIER_CADRES, FORMATS_CADRES, charger_config, mettre_a_jour_config log = logging.getLogger("photobooth.evenements") DOSSIER_EVENEMENTS = RACINE / "data" / "evenements" DOSSIER_EVENEMENTS.mkdir(parents=True, exist_ok=True) def _chemin_event(event_id: str) -> Path: return DOSSIER_EVENEMENTS / f"{event_id}.json" def _chemin_cadres_event(event_id: str) -> Path: d = DOSSIER_EVENEMENTS / event_id / "cadres" d.mkdir(parents=True, exist_ok=True) return d def lister_evenements() -> list[dict]: events = [] config = charger_config() actif_id = config.get("evenement", {}).get("event_id") for f in sorted(DOSSIER_EVENEMENTS.glob("*.json")): try: data = json.loads(f.read_text("utf-8")) data["actif"] = (data.get("id") == actif_id) events.append(data) except (json.JSONDecodeError, KeyError): continue return events def creer_evenement(nom: str, **kwargs) -> dict: event_id = uuid.uuid4().hex[:8] event = { "id": event_id, "nom": nom, "theme": kwargs.get("theme", "base"), "couleur_primaire": kwargs.get("couleur_primaire", "#e91e63"), "couleur_secondaire": kwargs.get("couleur_secondaire", "#ffffff"), "media_accueil": kwargs.get("media_accueil"), "formats_actifs": kwargs.get("formats_actifs", ["10x15", "15x20", "strip"]), "cadres": {}, } _chemin_event(event_id).write_text(json.dumps(event, ensure_ascii=False, indent=2), "utf-8") log.info(f"Evenement cree : {nom} ({event_id})") return event def obtenir_evenement(event_id: str) -> dict | None: chemin = _chemin_event(event_id) if not chemin.exists(): return None return json.loads(chemin.read_text("utf-8")) def modifier_evenement(event_id: str, modifications: dict) -> dict | None: event = obtenir_evenement(event_id) if not event: return None for k, v in modifications.items(): if k != "id": event[k] = v _chemin_event(event_id).write_text(json.dumps(event, ensure_ascii=False, indent=2), "utf-8") return event def supprimer_evenement(event_id: str) -> bool: chemin = _chemin_event(event_id) if not chemin.exists(): return False chemin.unlink() dossier_cadres = DOSSIER_EVENEMENTS / event_id if dossier_cadres.exists(): shutil.rmtree(dossier_cadres) config = charger_config() if config.get("evenement", {}).get("event_id") == event_id: mettre_a_jour_config({"evenement": {"event_id": None}}) log.info(f"Evenement supprime : {event_id}") return True def activer_evenement(event_id: str) -> dict | None: event = obtenir_evenement(event_id) if not event: return None mettre_a_jour_config({ "evenement": { "event_id": event_id, "nom": event["nom"], "theme": event.get("theme", "base"), "couleur_primaire": event.get("couleur_primaire", "#e91e63"), "couleur_secondaire": event.get("couleur_secondaire", "#ffffff"), "media_accueil": event.get("media_accueil"), "formats_actifs": event.get("formats_actifs", ["10x15", "15x20", "strip"]), } }) log.info(f"Evenement active : {event['nom']} ({event_id})") return event def lister_cadres_event(event_id: str, format_papier: str) -> list[str]: dossier = _chemin_cadres_event(event_id) / format_papier if not dossier.exists(): return [] return sorted(f.name for f in dossier.iterdir() if f.suffix.lower() == ".png") def config_cadre_event(event_id: str) -> dict: """Retourne la config cadres de l'evenement : {format: {mode, cadre}} mode: 'disponible' (choix user), 'impose' (force), 'defaut' (pre-selectionne) """ event = obtenir_evenement(event_id) if not event: return {} return event.get("cadres", {}) def set_cadre_event(event_id: str, format_papier: str, mode: str, cadre: str | None) -> bool: """mode: 'aucun', 'disponible', 'impose', 'defaut'""" event = obtenir_evenement(event_id) if not event: return False if "cadres" not in event: event["cadres"] = {} event["cadres"][format_papier] = {"mode": mode, "cadre": cadre} _chemin_event(event_id).write_text(json.dumps(event, ensure_ascii=False, indent=2), "utf-8") return True def cadre_actif_pour_impression(format_papier: str) -> tuple[str | None, str]: """Retourne (nom_cadre, mode) en tenant compte de l'evenement actif. mode: 'aucun', 'disponible', 'impose', 'defaut' Strips exclus du cadre impose/defaut. """ if format_papier == "strip": return None, "aucun" config = charger_config() event_id = config.get("evenement", {}).get("event_id") if not event_id: return None, "aucun" event = obtenir_evenement(event_id) if not event: return None, "aucun" cadres = event.get("cadres", {}) fmt_conf = cadres.get(format_papier, {}) return fmt_conf.get("cadre"), fmt_conf.get("mode", "aucun")