diff --git a/backend/api/admin_api.py b/backend/api/admin_api.py index c56c4be..015b76f 100644 --- a/backend/api/admin_api.py +++ b/backend/api/admin_api.py @@ -1,4 +1,4 @@ -"""Routes du dashboard admin — authentification requise.""" +"""Routes du dashboard admin -- authentification requise.""" import logging from pathlib import Path @@ -25,13 +25,13 @@ def _require_auth(request: Request): return None -# ── Auth ────────────────────────────────────────────────────────────────────── +# -- Auth ---------------------------------------------------------------------- @router.get("/admin/login", response_class=HTMLResponse) async def login_page(request: Request): if _is_auth(request): return RedirectResponse(url="/admin", status_code=302) - return _templates.TemplateResponse("admin/login.html", {"request": request, "error": None}) + return _templates.TemplateResponse(request, "admin/login.html", {"error": None}) @router.post("/admin/login") @@ -41,8 +41,9 @@ async def login(request: Request, password: str = Form(...)): request.session["authenticated"] = True return RedirectResponse(url="/admin", status_code=302) return _templates.TemplateResponse( + request, "admin/login.html", - {"request": request, "error": "Mot de passe incorrect"}, + {"error": "Mot de passe incorrect"}, ) @@ -52,7 +53,7 @@ async def logout(request: Request): return RedirectResponse(url="/admin/login", status_code=302) -# ── Pages admin ─────────────────────────────────────────────────────────────── +# -- Pages admin --------------------------------------------------------------- @router.get("/admin", response_class=HTMLResponse) async def admin_dashboard(request: Request): @@ -68,8 +69,7 @@ async def admin_dashboard(request: Request): stats = sys_svc.get_stats() services = sys_svc.get_services_status() - return _templates.TemplateResponse("admin/dashboard.html", { - "request": request, + return _templates.TemplateResponse(request, "admin/dashboard.html", { "config": cfg, "stats": stats, "services": services, @@ -85,8 +85,7 @@ async def admin_gallery(request: Request): if redirect: return redirect cfg = request.app.state.config - return _templates.TemplateResponse("admin/gallery.html", { - "request": request, + return _templates.TemplateResponse(request, "admin/gallery.html", { "config": cfg, }) @@ -102,8 +101,7 @@ async def admin_actions(request: Request): pb_config = await pb.read_pb_config() actions = pb_config.get("actions", {}).get("image", []) - return _templates.TemplateResponse("admin/actions.html", { - "request": request, + return _templates.TemplateResponse(request, "admin/actions.html", { "config": cfg, "pb_actions": actions, "button_mapping": cfg.button_actions, @@ -116,8 +114,7 @@ async def admin_settings(request: Request): if redirect: return redirect cfg = request.app.state.config - return _templates.TemplateResponse("admin/settings.html", { - "request": request, + return _templates.TemplateResponse(request, "admin/settings.html", { "config": cfg, "button": cfg.button, }) @@ -135,8 +132,7 @@ async def admin_print(request: Request): queue = await printer_svc.get_queue() printers = await printer_svc.get_printers_status() - return _templates.TemplateResponse("admin/print.html", { - "request": request, + return _templates.TemplateResponse(request, "admin/print.html", { "config": cfg, "queue": queue, "printers": printers, diff --git a/backend/api/gallery.py b/backend/api/gallery.py index 107abeb..035eebf 100644 --- a/backend/api/gallery.py +++ b/backend/api/gallery.py @@ -26,7 +26,7 @@ async def gallery_page(request: Request): cfg = request.app.state.config if not cfg.gallery.public_enabled: return HTMLResponse("

Galerie desactivee

", status_code=403) - return _templates.TemplateResponse("public/gallery.html", {"request": request, "config": cfg}) + return _templates.TemplateResponse(request, "public/gallery.html", {"config": cfg}) @router.get("/api/gallery/photos") diff --git a/config/settings.yaml b/config/settings.yaml index e60b308..84842b1 100644 --- a/config/settings.yaml +++ b/config/settings.yaml @@ -15,7 +15,7 @@ app: photobooth: base_url: "http://localhost:8000" data_dir: "/home/pi/photobooth-data" - config_file: "/home/pi/.config/photobooth-app/config.json" + config_file: "/home/pi/photobooth-data/config/config.json" media_dir: "/home/pi/photobooth-data/media/processed_full" userdata_dir: "/home/pi/photobooth-data/userdata" show_delete_button: false diff --git a/docs/INSTALL-FROM-SCRATCH.md b/docs/INSTALL-FROM-SCRATCH.md index 9fcd42a..7fd2db4 100644 --- a/docs/INSTALL-FROM-SCRATCH.md +++ b/docs/INSTALL-FROM-SCRATCH.md @@ -194,9 +194,7 @@ libcamera-hello --list-cameras photobooth-app est l'application kiosque qui gère la caméra, le décompte et les frames. ```bash -# Créer le dossier de données -mkdir -p /home/pi/photobooth-data/{media/processed_full,userdata,script} - +# photobooth-app crée lui-même ~/photobooth-data/ et ses sous-dossiers au premier lancement # Installer dans un venv avec accès aux paquets système (nécessaire pour picamera2) sudo apt install -y python3-venv python3 -m venv /home/pi/photobooth-venv --system-site-packages @@ -217,7 +215,7 @@ After=network.target [Service] Type=simple User=pi -WorkingDirectory=/home/pi +WorkingDirectory=/home/pi/photobooth-data/ ExecStart=/home/pi/photobooth-venv/bin/photobooth Restart=always RestartSec=5 @@ -227,6 +225,9 @@ Environment=HOME=/home/pi WantedBy=multi-user.target ``` +> **WorkingDirectory=/home/pi/photobooth-data/** — c'est le répertoire de travail de photobooth-app. +> Tous ses sous-dossiers (`config/`, `media/`, `userdata/`, `database/`...) y sont créés au premier lancement. + ```bash sudo systemctl daemon-reload sudo systemctl enable photobooth-app @@ -269,7 +270,7 @@ Copier la config depuis le dépôt après l'avoir cloné (étape 7) : ```bash # Après avoir cloné le dépôt JH Photomaton : cp /home/pi/jh-photomaton/photobooth-app/config/plugin_commander_jh.json \ - ~/.config/photobooth-app/plugin_commander.json + /home/pi/photobooth-data/config/plugin_commander.json sudo systemctl restart photobooth-app ``` @@ -334,7 +335,7 @@ app: photobooth: base_url: "http://localhost:8000" data_dir: "/home/pi/photobooth-data" - media_dir: "/home/pi/photobooth-data/media/processed_full" + media_dir: "/home/pi/photobooth-data/media/processed_full" # chemin réel créé par photobooth-app event: name: "Evenement" # sera modifié depuis l'admin @@ -407,10 +408,14 @@ Répéter pour `Selphy_Noire_WiFi`. ### Script d'impression -Vérifier que le script est exécutable et pointe vers les bons noms d'imprimantes : +> ⚠️ `script_print.sh` est un script **custom** — il n'existe pas par défaut. +> Il doit être copié depuis l'ancienne carte SD (voir Étape 12). ```bash -ls -la /home/pi/photobooth-data/script/script_print.sh +# Créer le dossier s'il n'existe pas +mkdir -p /home/pi/photobooth-data/script/ + +# Après copie depuis l'ancienne carte, rendre exécutable chmod +x /home/pi/photobooth-data/script/script_print.sh # Test manuel @@ -439,7 +444,7 @@ Ajouter dans `/etc/dhcpcd.conf` : ```ini interface wlan0 - static ip_address=192.168.4.1/24 + static ip_address=192.168.230.1/24 nohook wpa_supplicant ``` @@ -478,27 +483,27 @@ interface=wlan0 bind-interfaces # DHCP : distribue des IPs aux clients WiFi -dhcp-range=192.168.4.2,192.168.4.100,255.255.255.0,24h +dhcp-range=192.168.230.2,192.168.230.100,255.255.255.0,24h # Annonce le Pi comme serveur DNS aux clients -dhcp-option=6,192.168.4.1 +dhcp-option=6,192.168.230.1 # ── Portail captif ────────────────────────────────────────────── -# Tout le trafic DNS → Pi (192.168.4.1) +# Tout le trafic DNS → Pi (192.168.230.1) # google.com, instagram.com, lessapinsduweb.com... tout arrive ici. # Zoraxy fait le tri par HTTP Host header : # - *.lessapinsduweb.com → apps configurées dans Zoraxy # - tout le reste → redirect vers photomaton.lessapinsduweb.com -address=/#/192.168.4.1 +address=/#/192.168.230.1 # Sondes de détection portail captif — iOS et Android ouvrent # automatiquement le navigateur sur la galerie -address=/captive.apple.com/192.168.4.1 -address=/connectivitycheck.gstatic.com/192.168.4.1 -address=/detectportal.firefox.com/192.168.4.1 -address=/www.msftconnecttest.com/192.168.4.1 +address=/captive.apple.com/192.168.230.1 +address=/connectivitycheck.gstatic.com/192.168.230.1 +address=/detectportal.firefox.com/192.168.230.1 +address=/www.msftconnecttest.com/192.168.230.1 ``` -> **Note :** `address=/#/192.168.4.1` s'applique uniquement aux clients WiFi +> **Note :** `address=/#/192.168.230.1` s'applique uniquement aux clients WiFi > (DHCP sur wlan0). Le Pi lui-même utilise le DNS de son routeur via eth0. ### Activer les services @@ -558,7 +563,7 @@ sudo systemctl start zoraxy | **`*` (catch-all)** | **Redirect → `http://photomaton.lessapinsduweb.com`** | **Portail captif** | La règle catch-all est la clé : quand un client WiFi tape `google.com`, DNS -résout vers `192.168.4.1`, Zoraxy reçoit la requête, ne reconnaît pas l'hôte, +résout vers `192.168.230.1`, Zoraxy reçoit la requête, ne reconnaît pas l'hôte, et redirige vers la galerie photo. > **Limite HTTPS :** si un client tape `https://google.com`, le navigateur voit @@ -585,8 +590,9 @@ rsync -av /mnt/old-sd/home/pi/photobooth-data/script/ \ pi@:/home/pi/photobooth-data/script/ # Config photobooth-app (actions, frames configurées) -rsync -av /mnt/old-sd/home/pi/.config/photobooth-app/ \ - pi@:/home/pi/.config/photobooth-app/ +# photobooth-app stocke tout dans ~/photobooth-data/ (WorkingDirectory du service) +rsync -av /mnt/old-sd/home/pi/photobooth-data/ \ + pi@:/home/pi/photobooth-data/ # ⚠️ Après cette copie, vérifier que plugin_commander.json pointe bien vers :8090 (pas :1880) # Config JH Photomaton (settings.yaml + base SQLite) @@ -633,8 +639,8 @@ Interface admin : `http://:8090/admin` | JH Photomaton (admin) | 8090 | `http://admin.lessapinsduweb.com` ou `http://:8090/admin` | | photobooth-app (kiosque) | 8000 | `http://photomaton.lessapinsduweb.com` | | CUPS (imprimantes) | 631 | `http://:631` (réseau local uniquement) | -| Zoraxy (proxy admin) | 8888 | `http://192.168.4.1:8888` | -| WiFi hotspot | — | SSID `Photomaton-LSDW` — IP Pi : `192.168.4.1` | +| Zoraxy (proxy admin) | 8888 | `http://192.168.230.1:8888` | +| WiFi hotspot | — | SSID `Photomaton-LSDW` — IP Pi : `192.168.230.1` | --- diff --git a/scripts/install.sh b/scripts/install.sh index f31ac3f..3843af8 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -62,7 +62,15 @@ echo "" echo "▶ Création de l'environnement virtuel Python..." python3 -m venv "$VENV_DIR" --system-site-packages +# Le venv est créé par root (sudo) — le remettre à pi pour que pip fonctionne sans sudo +chown -R pi:pi "$VENV_DIR" + "$VENV_DIR/bin/pip" install --upgrade pip -q + +# Force jinja2 dans le venv pour ecraser la version systeme Debian +# (la version systeme sur Trixie a un bug LRUCache incompatible avec Starlette) +"$VENV_DIR/bin/pip" install --upgrade --ignore-installed jinja2 -q + "$VENV_DIR/bin/pip" install -r "$INSTALL_DIR/requirements.txt" -q # rpi_ws281x (nécessite les headers, installé depuis PyPI)