feat: impression galerie utilisateur (enable/quota/max_copies)
🚀 Deploy — JH Photomaton / 🔍 Vérification (push) Has been cancelled
🚀 Deploy — JH Photomaton / 🍓 Deploy sur le Pi (push) Has been cancelled

This commit is contained in:
2026-07-17 17:44:47 +02:00
parent 4388503102
commit d6642c2519
3 changed files with 101 additions and 1 deletions
+24 -1
View File
@@ -4,7 +4,7 @@ import asyncio
import logging import logging
from pathlib import Path from pathlib import Path
from fastapi import APIRouter, Request, Query from fastapi import APIRouter, Request, Query, Body
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -125,6 +125,29 @@ async def set_print_mode(request: Request, mode: str = Query(...)):
return {"ok": True, "mode": mode} return {"ok": True, "mode": mode}
@router.post("/print/user-print-config")
async def set_user_print_config(request: Request, body: dict = Body(...)):
"""Configure l'impression depuis la galerie utilisateur."""
enabled = bool(body.get("user_print_enabled", False))
quota = max(0, int(body.get("user_print_quota", 0)))
max_copies = max(1, min(10, int(body.get("user_print_max_copies", 1))))
config_svc = request.app.state.config_service
config_svc.save_user_print_config(enabled, quota, max_copies)
logger.info("User print config: enabled=%s quota=%d max_copies=%d", enabled, quota, max_copies)
return {"ok": True, "user_print_enabled": enabled, "user_print_quota": quota, "user_print_max_copies": max_copies}
@router.get("/print/user-print-config")
async def get_user_print_config(request: Request):
"""Retourne la config impression galerie utilisateur."""
cfg = request.app.state.config.print
return {
"user_print_enabled": cfg.user_print_enabled,
"user_print_quota": cfg.user_print_quota,
"user_print_max_copies": cfg.user_print_max_copies,
}
# ── Gestion avancée des imprimantes CUPS ────────────────────────────────────── # ── Gestion avancée des imprimantes CUPS ──────────────────────────────────────
@router.post("/print/printers/{printer_name}/enable") @router.post("/print/printers/{printer_name}/enable")
+19
View File
@@ -83,6 +83,10 @@ class PrintConfig:
script_path: str = "/home/pi/photobooth-data/script/script_print.sh" script_path: str = "/home/pi/photobooth-data/script/script_print.sh"
default_copies: int = 1 default_copies: int = 1
printers: list = field(default_factory=list) printers: list = field(default_factory=list)
# Impression depuis la galerie utilisateur
user_print_enabled: bool = False
user_print_quota: int = 0 # 0 = illimité
user_print_max_copies: int = 1 # copies max par demande
@dataclass @dataclass
@@ -209,6 +213,21 @@ class ConfigService:
self._config.event.slug = slug self._config.event.slug = slug
self._config.event.started_at = started_at self._config.event.started_at = started_at
def save_user_print_config(self, enabled: bool, quota: int, max_copies: int):
with open(self.path, encoding="utf-8") as f:
raw = yaml.safe_load(f) or {}
raw.setdefault("print", {}).update({
"user_print_enabled": enabled,
"user_print_quota": quota,
"user_print_max_copies": max_copies,
})
with open(self.path, "w", encoding="utf-8") as f:
yaml.dump(raw, f, allow_unicode=True, default_flow_style=False)
if self._config:
self._config.print.user_print_enabled = enabled
self._config.print.user_print_quota = quota
self._config.print.user_print_max_copies = max_copies
def save_print_mode(self, mode: str): def save_print_mode(self, mode: str):
with open(self.path, encoding="utf-8") as f: with open(self.path, encoding="utf-8") as f:
raw = yaml.safe_load(f) or {} raw = yaml.safe_load(f) or {}
+58
View File
@@ -256,6 +256,51 @@
</div> </div>
</div> </div>
<!-- ── IMPRESSION GALERIE UTILISATEUR ───────────────────────────────── -->
<div>
<div class="section-title">👥 Impression galerie utilisateur</div>
<div class="mode-card">
<p class="mode-hint" style="margin-bottom:.85rem">
Autorise (ou non) les visiteurs de la galerie publique à demander l'impression d'une photo,
avec un quota et un nombre de copies maximum par demande.
</p>
<div style="display:flex;flex-direction:column;gap:.75rem">
<label style="display:flex;align-items:center;gap:.65rem;cursor:pointer;font-size:.95rem">
<input type="checkbox" id="uprint-enabled"
{% if config.print.user_print_enabled %}checked{% endif %}
style="accent-color:var(--primary);width:1.1rem;height:1.1rem">
Permettre aux utilisateurs de demander une impression
</label>
<div style="display:flex;gap:1.5rem;flex-wrap:wrap;align-items:flex-end">
<div class="form-group" style="margin:0">
<label class="mode-hint" style="display:block;margin-bottom:.3rem;font-weight:600">
Quota d'impressions par session
</label>
<div style="display:flex;align-items:center;gap:.5rem">
<input type="number" id="uprint-quota" class="copies-input"
value="{{ config.print.user_print_quota }}" min="0" max="99" style="width:70px">
<span class="mode-hint">0 = illimité</span>
</div>
</div>
<div class="form-group" style="margin:0">
<label class="mode-hint" style="display:block;margin-bottom:.3rem;font-weight:600">
Copies max par demande
</label>
<input type="number" id="uprint-max-copies" class="copies-input"
value="{{ config.print.user_print_max_copies }}" min="1" max="10" style="width:70px">
</div>
</div>
</div>
<button class="btn-sm btn-print" style="margin-top:.85rem" onclick="saveUserPrintConfig()">
💾 Sauvegarder
</button>
</div>
</div>
<!-- ── FILE D'ATTENTE ─────────────────────────────────────────────────── --> <!-- ── FILE D'ATTENTE ─────────────────────────────────────────────────── -->
<div> <div>
<div class="queue-card"> <div class="queue-card">
@@ -486,6 +531,19 @@ async function cancelPrint(id) {
} catch(err) { showToast('Erreur', 'error'); } } catch(err) { showToast('Erreur', 'error'); }
} }
// ── Config impression utilisateur ─────────────────────────────────────────────
async function saveUserPrintConfig() {
const payload = {
user_print_enabled: document.getElementById('uprint-enabled').checked,
user_print_quota: parseInt(document.getElementById('uprint-quota').value) || 0,
user_print_max_copies: parseInt(document.getElementById('uprint-max-copies').value) || 1,
};
try {
await api('POST', '/api/print/user-print-config', payload);
showToast('✅ Configuration sauvegardée', 'success');
} catch(e) { showToast('❌ Erreur : ' + e.message, 'error'); }
}
// ── WebSocket + auto-refresh ─────────────────────────────────────────────────── // ── WebSocket + auto-refresh ───────────────────────────────────────────────────
function onWsMessage(msg) { function onWsMessage(msg) {
if (['print_request','print_result','print_cancelled'].includes(msg.type)) { if (['print_request','print_result','print_cancelled'].includes(msg.type)) {