Add cookie consent widget with analytics tunnel bypass for adblock

- Create cookie-consent.js module: banner show/hide, cookie management, conditional analytics loading
- Add cookie banner widget in base.html.twig (accept/refuse buttons)
- Analytics script loaded from /stats/ tunnel (bypass adblock) with data-host-url
- Add Caddy reverse proxy tunnel /stats/* -> tools-security.esy-web.dev
- Add tools-security.esy-web.dev to CSP connect-src
- Add 9 JS tests for cookie consent
- Revert manual composer.json edit for amazon-mailer (needs composer require)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-03-20 16:02:36 +01:00
parent 99e5428208
commit 518642551c
7 changed files with 168 additions and 1 deletions

View File

@@ -2,9 +2,11 @@ import "./app.scss"
import { initMobileMenu } from "./modules/mobile-menu.js"
import { initTabs } from "./modules/tabs.js"
import { registerEditor } from "./modules/editor.js"
import { initCookieConsent } from "./modules/cookie-consent.js"
document.addEventListener('DOMContentLoaded', () => {
initMobileMenu()
initTabs()
registerEditor()
initCookieConsent()
})

View File

@@ -0,0 +1,67 @@
const COOKIE_NAME = 'e_ticket_consent'
const COOKIE_DAYS = 365
function getCookie(name) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'))
return match ? match[2] : null
}
function setCookie(name, value, days) {
const date = new Date()
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000)
document.cookie = name + '=' + value + ';expires=' + date.toUTCString() + ';path=/;SameSite=Lax;Secure'
}
function loadAnalytics() {
if (document.querySelector('script[data-analytics]')) {
return
}
const script = document.createElement('script')
script.defer = true
script.src = '/stats/script.js'
script.dataset.websiteId = 'a1f85dd5-741f-4df7-840a-7ef0931ed0cc'
script.dataset.hostUrl = '/stats'
script.dataset.analytics = '1'
document.head.appendChild(script)
}
export function initCookieConsent() {
const consent = getCookie(COOKIE_NAME)
if ('accepted' === consent) {
loadAnalytics()
return
}
if ('refused' === consent) {
return
}
const banner = document.getElementById('cookie-banner')
if (!banner) {
return
}
banner.classList.remove('hidden')
const acceptBtn = document.getElementById('cookie-accept')
const refuseBtn = document.getElementById('cookie-refuse')
if (acceptBtn) {
acceptBtn.addEventListener('click', () => {
setCookie(COOKIE_NAME, 'accepted', COOKIE_DAYS)
banner.classList.add('hidden')
loadAnalytics()
})
}
if (refuseBtn) {
refuseBtn.addEventListener('click', () => {
setCookie(COOKIE_NAME, 'refused', COOKIE_DAYS)
banner.classList.add('hidden')
})
}
}