feat: route app_unsubscribe + fix envoi email bienvenue

UnsubscribeController :
- Route GET /unsubscribe/{email}/{token} (app_unsubscribe)
- Vérifie le token HMAC via UnsubscribeManager::isValidToken
- Si valide : désabonne l'email + page succès
- Si invalide : page erreur avec contact unsubscribe@siteconseil.fr

Templates :
- unsubscribe/success.html.twig : confirmation glassmorphism
- unsubscribe/invalid.html.twig : erreur glassmorphism

ClientsController :
- sendWelcomeEmail : suppression try/catch silencieux pour laisser
  remonter les erreurs (sinon mail jamais envoyé sans diagnostic)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-04-04 19:06:50 +02:00
parent 4a9952e226
commit 5809c1a4df
4 changed files with 62 additions and 12 deletions

View File

@@ -156,18 +156,15 @@ class ClientsController extends AbstractController
'token' => $user->getTempPassword(),
], UrlGeneratorInterface::ABSOLUTE_URL);
try {
$mailer->sendEmail(
$user->getEmail(),
'CRM SITECONSEIL - Bienvenue dans votre espace client',
$twig->render('emails/client_created.html.twig', [
'firstName' => $user->getFirstName(),
'email' => $user->getEmail(),
'setPasswordUrl' => $setPasswordUrl,
]),
);
} catch (\Throwable) {
}
$mailer->sendEmail(
$user->getEmail(),
'CRM SITECONSEIL - Bienvenue dans votre espace client',
$twig->render('emails/client_created.html.twig', [
'firstName' => $user->getFirstName(),
'email' => $user->getEmail(),
'setPasswordUrl' => $setPasswordUrl,
]),
);
}
private function populateCustomerData(Request $request, Customer $customer): void

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Controller;
use App\Service\UnsubscribeManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class UnsubscribeController extends AbstractController
{
#[Route('/unsubscribe/{email}/{token}', name: 'app_unsubscribe', methods: ['GET'])]
public function __invoke(string $email, string $token, UnsubscribeManager $unsubscribeManager): Response
{
if (!$unsubscribeManager->isValidToken($email, $token)) {
return $this->render('unsubscribe/invalid.html.twig');
}
$unsubscribeManager->unsubscribe($email);
return $this->render('unsubscribe/success.html.twig', [
'email' => $email,
]);
}
}

View File

@@ -0,0 +1,14 @@
{% extends 'base.html.twig' %}
{% block title %}Lien invalide - CRM SITECONSEIL{% endblock %}
{% block body %}
<div class="flex items-center justify-center min-h-[calc(100vh-4rem)] px-4">
<div class="w-full max-w-sm glass-heavy p-8 text-center">
<div class="text-red-600 text-4xl mb-4">&#10007;</div>
<h1 class="text-lg font-bold uppercase mb-2">Lien invalide</h1>
<p class="text-sm text-gray-500">Ce lien de desabonnement est invalide ou a expire.</p>
<p class="text-xs text-gray-400 mt-4">Contactez <strong>unsubscribe@siteconseil.fr</strong> pour vous desabonner manuellement.</p>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,14 @@
{% extends 'base.html.twig' %}
{% block title %}Desabonnement - CRM SITECONSEIL{% endblock %}
{% block body %}
<div class="flex items-center justify-center min-h-[calc(100vh-4rem)] px-4">
<div class="w-full max-w-sm glass-heavy p-8 text-center">
<div class="text-green-600 text-4xl mb-4">&#10003;</div>
<h1 class="text-lg font-bold uppercase mb-2">Desabonnement confirme</h1>
<p class="text-sm text-gray-500">L'adresse <strong>{{ email }}</strong> ne recevra plus d'emails commerciaux de SITECONSEIL.</p>
<p class="text-xs text-gray-400 mt-4">Pour vous reabonner, contactez <strong>contact@siteconseil.fr</strong>.</p>
</div>
</div>
{% endblock %}