From bdf1e69860040dbe33653bbeb864be7b85c88ee6 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Wed, 21 Jan 2026 13:37:26 +0100 Subject: [PATCH] =?UTF-8?q?```=20=E2=9C=A8=20feat(Product):=20Ajoute=20m?= =?UTF-8?q?=C3=A9thode=20json=20pour=20s=C3=A9rialiser=20les=20donn=C3=A9e?= =?UTF-8?q?s=20du=20produit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ feat(analytics): Intègre suivi Umami pour catalogue, contact et produits. ✨ feat(caddy): Ajoute header Cloudflare et script UTM, améliore config PHP. ✨ feat(nelmio): Autorise tools-security.esy-web.dev dans CSP. ✨ feat(template): Ajoute suivi Umami sur pages catalogue, contact et produit. ``` --- ansible/templates/caddy.j2 | 18 +++- assets/reserve.js | 4 + assets/tools/UtmEvent.js | 58 ++++++++++++ config/packages/nelmio_security.yaml | 1 + docker/caddy/Caddyfile | 3 + src/Entity/Product.php | 9 ++ templates/revervation/base.twig | 10 +- templates/revervation/catalogue.twig | 1 + templates/revervation/contact.twig | 2 + templates/revervation/produit.twig | 137 ++++++++++++++------------- 10 files changed, 177 insertions(+), 66 deletions(-) create mode 100644 assets/tools/UtmEvent.js diff --git a/ansible/templates/caddy.j2 b/ansible/templates/caddy.j2 index 44eff0f..3010a83 100644 --- a/ansible/templates/caddy.j2 +++ b/ansible/templates/caddy.j2 @@ -14,20 +14,36 @@ intranet.ludikevent.fr, signature.ludikevent.fr, reservation.ludikevent.fr { @noindex_hosts host intranet.ludikevent.fr signature.ludikevent.fr header @noindex_hosts X-Robots-Tag "noindex, nofollow" - # SUPPRIME le noindex sur la réservation (au cas où PHP ou un autre bloc l'ajouterait) @index_host host reservation.ludikevent.fr header @index_host -X-Robots-Tag + handle_path /utm_reserve.js { + redir https://tools-security.esy-web.dev/script.js + } + # --- BLOC HEADER AVEC CSP --- header { X-Content-Type-Options "nosniff" X-Frame-Options "DENY" Referrer-Policy "strict-origin-when-cross-origin" + + # Injection des headers Cloudflare pour PHP + # Cela permet à PHP de les lire via $_SERVER['HTTP_CF_CONNECTING_IP'] etc. + CF-Connecting-IP {header.CF-Connecting-IP} + CF-IPCountry {header.CF-IPCountry} + CF-RegionCode {header.CF-RegionCode} + CF-IPCity {header.CF-IPCity} + X-Real-IP {remote_host} } + # --- PHP FASTCGI --- + # Ici, Caddy transmet automatiquement tous les headers définis ci-dessus au socket PHP php_fastcgi unix//run/php/php8.3-fpm.sock { read_timeout 300s write_timeout 300s dial_timeout 100s + + # Optionnel : Forcer explicitement certains paramètres FastCGI si nécessaire + env REMOTE_ADDR {header.CF-Connecting-IP} } } diff --git a/assets/reserve.js b/assets/reserve.js index c60f253..5598291 100644 --- a/assets/reserve.js +++ b/assets/reserve.js @@ -1,5 +1,6 @@ import './reserve.scss'; import * as Sentry from "@sentry/browser"; +import {UtmEvent,UtmAccount} from "./tools/UtmEvent.js"; import * as Turbo from "@hotwired/turbo" // --- INITIALISATION SENTRY --- @@ -103,6 +104,9 @@ document.addEventListener('DOMContentLoaded', () => { initLoader(); initMobileMenu(); initCatalogueSearch(); + customElements.define('utm-event',UtmEvent) + customElements.define('utm-account',UtmAccount) + }); document.addEventListener('turbo:load', () => { diff --git a/assets/tools/UtmEvent.js b/assets/tools/UtmEvent.js new file mode 100644 index 0000000..fd25b90 --- /dev/null +++ b/assets/tools/UtmEvent.js @@ -0,0 +1,58 @@ +export class UtmAccount extends HTMLElement { + connectedCallback() { + if (typeof umami === 'undefined') { + console.warn('Umami script non détecté.'); + return; + } + const umamiScript = document.querySelector('script[data-website-id]'); + const websiteId = umamiScript ? umamiScript.getAttribute('data-website-id') : null; + umami.identify('user_'+this.getAttribute('id'), { name: this.getAttribute('name'), email: this.getAttribute('email') }); + + } +} +export class UtmEvent extends HTMLElement { + connectedCallback() { + // On attend un court instant pour s'assurer qu'umami est chargé + // ou on vérifie s'il existe déjà + if (typeof umami === 'undefined') { + console.warn('Umami script non détecté.'); + return; + } + + const event = this.getAttribute('event'); + const dataRaw = this.getAttribute('data'); + + // Extraction dynamique du website-id depuis le script existant + const umamiScript = document.querySelector('script[data-website-id]'); + const websiteId = umamiScript ? umamiScript.getAttribute('data-website-id') : null; + + if (!websiteId) { + console.error('Impossible de trouver le data-website-id umami.'); + return; + } + + try { + if (event === "view_catalogue") { + umami.track('Affichage du catalogue'); + } + if (event === "view_contact") { + umami.track('Affichage du page contact'); + umami.track('Affichage du page contact'); + } + + if (event === "view_product" && dataRaw) { + const data = JSON.parse(dataRaw); + + // Umami track accepte soit un nom seul, + // soit un objet complet pour des propriétés personnalisées + umami.track({ + website: websiteId, + name:'Affichage produit', + data: data + }); + } + } catch (e) { + console.error('Erreur lors du tracking Umami:', e); + } + } +} diff --git a/config/packages/nelmio_security.yaml b/config/packages/nelmio_security.yaml index 5a3082c..23e3d30 100644 --- a/config/packages/nelmio_security.yaml +++ b/config/packages/nelmio_security.yaml @@ -36,6 +36,7 @@ nelmio_security: - "https://auth.esy-web.dev" - "https://cloudflareinsights.com" - "https://challenges.cloudflare.com" + - "https://tools-security.esy-web.dev" frame-src: - "'self'" - "https://chat.esy-web.dev" diff --git a/docker/caddy/Caddyfile b/docker/caddy/Caddyfile index 12741ca..337a7d8 100644 --- a/docker/caddy/Caddyfile +++ b/docker/caddy/Caddyfile @@ -30,6 +30,9 @@ output stdout format json } + handle_path /utm_reserve.js { + redir https://tools-security.esy-web.dev/script.js + } handle_path /ts.js { redir https://widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js } diff --git a/src/Entity/Product.php b/src/Entity/Product.php index ec223ae..faca38d 100644 --- a/src/Entity/Product.php +++ b/src/Entity/Product.php @@ -80,6 +80,15 @@ class Product return$s->slugify($this->id."-".$this->name); } + public function json() + { + return json_encode([ + 'id' => $this->id, + 'ref' => $this->ref, + 'name' => $this->name, + ]); + } + public function getId(): ?int { return $this->id; diff --git a/templates/revervation/base.twig b/templates/revervation/base.twig index bd047c0..6b55672 100644 --- a/templates/revervation/base.twig +++ b/templates/revervation/base.twig @@ -81,13 +81,21 @@ {# --- PWA (Configuré via manifest.json) --- #} {% if app.environment != 'dev' %} {{ pwa(swAttributes={ 'nonce': csp_nonce('script') }) }} + + {% else %} + + {% endif %} {{ vite_asset('reserve.js',{}) }} {% block stylesheets %}{% endblock %} + + - +{% if is_granted('ROLE_USER') %} + +{% endif %} {# --- NAVIGATION --- #}