- AuditLog entity: action, entityType, entityId, data (JSON), performedBy, ipAddress - AuditService: logs actions with current user and IP - Audit on: order_created, order_paid, order_cancelled, order_refunded - Admin /admin/logs: paginated table with action badges, details, user, IP - Navigation link 'Logs' in admin header Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
565 lines
22 KiB
PHP
565 lines
22 KiB
PHP
<?php
|
|
|
|
namespace App\Controller;
|
|
|
|
use App\Entity\AuditLog;
|
|
use App\Entity\OrganizerInvitation;
|
|
use App\Entity\User;
|
|
use App\Service\MailerService;
|
|
use App\Service\MeilisearchService;
|
|
use App\Service\SiretService;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Knp\Component\Pager\PaginatorInterface;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|
use Symfony\Component\Routing\Attribute\Route;
|
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|
|
|
#[Route('/admin')]
|
|
#[IsGranted('ROLE_ROOT')]
|
|
class AdminController extends AbstractController
|
|
{
|
|
#[Route('', name: 'app_admin_dashboard')]
|
|
public function dashboard(): Response
|
|
{
|
|
return $this->render('admin/dashboard.html.twig');
|
|
}
|
|
|
|
#[Route('/sync-meilisearch', name: 'app_admin_sync_meilisearch', methods: ['POST'])]
|
|
public function syncMeilisearch(EntityManagerInterface $em, MeilisearchService $meilisearch): Response
|
|
{
|
|
$allUsers = $em->getRepository(User::class)->findAll();
|
|
$buyers = array_filter($allUsers, fn (User $u) => $u->isVerified() && !\in_array('ROLE_ORGANIZER', $u->getRoles(), true) && !\in_array('ROLE_ROOT', $u->getRoles(), true));
|
|
|
|
$meilisearch->createIndexIfNotExists('buyers');
|
|
|
|
$documents = array_map(fn (User $u) => [
|
|
'id' => $u->getId(),
|
|
'firstName' => $u->getFirstName(),
|
|
'lastName' => $u->getLastName(),
|
|
'email' => $u->getEmail(),
|
|
'createdAt' => $u->getCreatedAt()->format('d/m/Y'),
|
|
], array_values($buyers));
|
|
|
|
if ([] !== $documents) {
|
|
$meilisearch->addDocuments('buyers', $documents);
|
|
}
|
|
|
|
$organizers = array_filter($allUsers, fn (User $u) => $u->isApproved() && \in_array('ROLE_ORGANIZER', $u->getRoles(), true));
|
|
|
|
$meilisearch->createIndexIfNotExists('organizers');
|
|
|
|
$orgaDocs = array_map(fn (User $u) => [
|
|
'id' => $u->getId(),
|
|
'firstName' => $u->getFirstName(),
|
|
'lastName' => $u->getLastName(),
|
|
'email' => $u->getEmail(),
|
|
'companyName' => $u->getCompanyName(),
|
|
'siret' => $u->getSiret(),
|
|
'city' => $u->getCity(),
|
|
], array_values($organizers));
|
|
|
|
if ([] !== $orgaDocs) {
|
|
$meilisearch->addDocuments('organizers', $orgaDocs);
|
|
}
|
|
|
|
$this->addFlash('success', sprintf('%d acheteur(s) et %d organisateur(s) synchronise(s) dans Meilisearch.', \count($documents), \count($orgaDocs)));
|
|
|
|
return $this->redirectToRoute('app_admin_dashboard');
|
|
}
|
|
|
|
#[Route('/utilisateurs', name: 'app_admin_users')]
|
|
public function users(EntityManagerInterface $em): Response
|
|
{
|
|
$users = $em->getRepository(User::class)->findBy([], ['createdAt' => 'DESC']);
|
|
|
|
return $this->render('admin/users.html.twig', [
|
|
'users' => $users,
|
|
]);
|
|
}
|
|
|
|
#[Route('/acheteurs', name: 'app_admin_buyers')]
|
|
public function buyers(Request $request, EntityManagerInterface $em, PaginatorInterface $paginator, MeilisearchService $meilisearch): Response
|
|
{
|
|
$query = $request->query->getString('q', '');
|
|
$searchResults = null;
|
|
|
|
if ('' !== $query) {
|
|
try {
|
|
$searchResults = $meilisearch->search('buyers', $query, ['limit' => 50]);
|
|
} catch (\Throwable) {
|
|
$this->addFlash('error', 'Erreur de recherche Meilisearch.');
|
|
}
|
|
}
|
|
|
|
if (null !== $searchResults && isset($searchResults['hits'])) {
|
|
$hitIds = array_map(fn (array $hit) => $hit['id'], $searchResults['hits']);
|
|
$allUsers = $em->getRepository(User::class)->findBy(['id' => $hitIds]);
|
|
$buyers = $allUsers;
|
|
} else {
|
|
$allUsers = $em->getRepository(User::class)->findBy([], ['createdAt' => 'DESC']);
|
|
$buyers = array_values(array_filter($allUsers, fn (User $u) => !\in_array('ROLE_ORGANIZER', $u->getRoles(), true) && !\in_array('ROLE_ROOT', $u->getRoles(), true)));
|
|
}
|
|
|
|
$pagination = $paginator->paginate(
|
|
$buyers,
|
|
$request->query->getInt('page', 1),
|
|
10,
|
|
);
|
|
|
|
return $this->render('admin/buyers.html.twig', [
|
|
'buyers' => $pagination,
|
|
'query' => $query,
|
|
]);
|
|
}
|
|
|
|
#[Route('/organisateurs', name: 'app_admin_organizers')]
|
|
public function organizers(Request $request, EntityManagerInterface $em, PaginatorInterface $paginator, MeilisearchService $meilisearch): Response
|
|
{
|
|
$query = $request->query->getString('q', '');
|
|
$tab = $request->query->getString('tab', 'pending');
|
|
$searchResults = null;
|
|
|
|
if ('' !== $query) {
|
|
try {
|
|
$searchResults = $meilisearch->search('organizers', $query, ['limit' => 50]);
|
|
} catch (\Throwable) {
|
|
$this->addFlash('error', 'Erreur de recherche Meilisearch.');
|
|
}
|
|
}
|
|
|
|
if (null !== $searchResults && isset($searchResults['hits'])) {
|
|
$hitIds = array_map(fn (array $hit) => $hit['id'], $searchResults['hits']);
|
|
$organizers = $em->getRepository(User::class)->findBy(['id' => $hitIds]);
|
|
} else {
|
|
$allUsers = $em->getRepository(User::class)->findBy([], ['createdAt' => 'DESC']);
|
|
$organizers = array_values(array_filter($allUsers, fn (User $u) => \in_array('ROLE_ORGANIZER', $u->getRoles(), true)));
|
|
}
|
|
|
|
if ('' === $query) {
|
|
if ('approved' === $tab) {
|
|
$filtered = array_values(array_filter($organizers, fn (User $u) => $u->isApproved()));
|
|
} else {
|
|
$filtered = array_values(array_filter($organizers, fn (User $u) => !$u->isApproved()));
|
|
}
|
|
} else {
|
|
$filtered = $organizers;
|
|
}
|
|
|
|
$pagination = $paginator->paginate(
|
|
$filtered,
|
|
$request->query->getInt('page', 1),
|
|
10,
|
|
);
|
|
|
|
return $this->render('admin/organizers.html.twig', [
|
|
'organizers' => $pagination,
|
|
'tab' => $tab,
|
|
'query' => $query,
|
|
]);
|
|
}
|
|
|
|
#[Route('/acheteurs/creer', name: 'app_admin_create_buyer', methods: ['POST'])]
|
|
public function createBuyer(
|
|
Request $request,
|
|
EntityManagerInterface $em,
|
|
UserPasswordHasherInterface $passwordHasher,
|
|
ValidatorInterface $validator,
|
|
MailerService $mailerService,
|
|
): Response {
|
|
$user = new User();
|
|
$user->setFirstName(trim($request->request->getString('first_name')));
|
|
$user->setLastName(trim($request->request->getString('last_name')));
|
|
$user->setEmail(trim($request->request->getString('email')));
|
|
|
|
$user->setPassword($passwordHasher->hashPassword($user, bin2hex(random_bytes(16))));
|
|
|
|
$token = bin2hex(random_bytes(32));
|
|
$user->setEmailVerificationToken($token);
|
|
|
|
$errors = $validator->validate($user);
|
|
if (0 === count($errors)) {
|
|
$em->persist($user);
|
|
$em->flush();
|
|
|
|
$verificationUrl = $this->generateUrl('app_verify_email', [
|
|
'token' => $token,
|
|
], UrlGeneratorInterface::ABSOLUTE_URL);
|
|
|
|
$mailerService->sendEmail(
|
|
to: $user->getEmail(),
|
|
subject: 'Verifiez votre adresse email - E-Ticket',
|
|
content: $this->renderView('email/verification.html.twig', [
|
|
'firstName' => $user->getFirstName(),
|
|
'verificationUrl' => $verificationUrl,
|
|
]),
|
|
withUnsubscribe: false,
|
|
);
|
|
|
|
$this->addFlash('success', sprintf('Acheteur %s %s cree.', $user->getFirstName(), $user->getLastName()));
|
|
|
|
return $this->redirectToRoute('app_admin_buyers');
|
|
}
|
|
|
|
foreach ($errors as $error) {
|
|
$this->addFlash('error', $error->getMessage());
|
|
}
|
|
|
|
return $this->redirectToRoute('app_admin_buyers');
|
|
}
|
|
|
|
#[Route('/acheteur/{id}/renvoyer-verification', name: 'app_admin_resend_verification', methods: ['POST'])]
|
|
public function resendVerification(User $user, EntityManagerInterface $em, MailerService $mailerService): Response
|
|
{
|
|
$token = bin2hex(random_bytes(32));
|
|
$user->setEmailVerificationToken($token);
|
|
$em->flush();
|
|
|
|
$verificationUrl = $this->generateUrl('app_verify_email', [
|
|
'token' => $token,
|
|
], UrlGeneratorInterface::ABSOLUTE_URL);
|
|
|
|
$mailerService->sendEmail(
|
|
to: $user->getEmail(),
|
|
subject: 'Verifiez votre adresse email - E-Ticket',
|
|
content: $this->renderView('email/verification.html.twig', [
|
|
'firstName' => $user->getFirstName(),
|
|
'verificationUrl' => $verificationUrl,
|
|
]),
|
|
withUnsubscribe: false,
|
|
);
|
|
|
|
$this->addFlash('success', sprintf('Email de verification renvoye a %s.', $user->getEmail()));
|
|
|
|
return $this->redirectToRoute('app_admin_buyers');
|
|
}
|
|
|
|
#[Route('/acheteur/{id}/forcer-verification', name: 'app_admin_force_verification', methods: ['POST'])]
|
|
public function forceVerification(User $user, EntityManagerInterface $em): Response
|
|
{
|
|
$user->setIsVerified(true);
|
|
$user->setEmailVerifiedAt(new \DateTimeImmutable());
|
|
$user->setEmailVerificationToken(null);
|
|
$em->flush();
|
|
|
|
$this->addFlash('success', sprintf('Email de %s %s force comme verifie.', $user->getFirstName(), $user->getLastName()));
|
|
|
|
return $this->redirectToRoute('app_admin_buyers');
|
|
}
|
|
|
|
#[Route('/acheteur/{id}/reset-password', name: 'app_admin_reset_password', methods: ['POST'])]
|
|
public function resetPassword(User $user, MailerService $mailerService): Response
|
|
{
|
|
$resetUrl = $this->generateUrl('app_forgot_password', [], UrlGeneratorInterface::ABSOLUTE_URL);
|
|
|
|
$mailerService->sendEmail(
|
|
to: $user->getEmail(),
|
|
subject: 'Reinitialisation de votre mot de passe - E-Ticket',
|
|
content: $this->renderView('email/admin_reset_password.html.twig', [
|
|
'firstName' => $user->getFirstName(),
|
|
'email' => $user->getEmail(),
|
|
'resetUrl' => $resetUrl,
|
|
]),
|
|
withUnsubscribe: false,
|
|
);
|
|
|
|
$this->addFlash('success', sprintf('Lien de reinitialisation envoye a %s.', $user->getEmail()));
|
|
|
|
return $this->redirectToRoute('app_admin_buyers');
|
|
}
|
|
|
|
#[Route('/acheteur/{id}/supprimer', name: 'app_admin_delete_buyer', methods: ['POST'])]
|
|
public function deleteBuyer(User $user, EntityManagerInterface $em, MeilisearchService $meilisearch): Response
|
|
{
|
|
$name = sprintf('%s %s', $user->getFirstName(), $user->getLastName());
|
|
$userId = $user->getId();
|
|
|
|
$em->remove($user);
|
|
$em->flush();
|
|
|
|
try {
|
|
$meilisearch->deleteDocument('buyers', $userId);
|
|
} catch (\Throwable) {
|
|
// Meilisearch failure should not block user deletion
|
|
}
|
|
|
|
$this->addFlash('success', sprintf('Compte de %s supprime.', $name));
|
|
|
|
return $this->redirectToRoute('app_admin_buyers');
|
|
}
|
|
|
|
#[Route('/organisateur/{id}/approuver', name: 'app_admin_approve_organizer', methods: ['POST'])]
|
|
public function approveOrganizer(User $user, Request $request, EntityManagerInterface $em, MailerService $mailerService, MeilisearchService $meilisearch): Response
|
|
{
|
|
$offer = $request->request->getString('offer', 'free');
|
|
$commissionRate = (float) $request->request->getString('commission_rate', '3');
|
|
|
|
$user->setIsApproved(true);
|
|
$user->setOffer($offer);
|
|
$user->setCommissionRate($commissionRate);
|
|
$em->flush();
|
|
|
|
$meilisearch->createIndexIfNotExists('organizers');
|
|
$meilisearch->addDocuments('organizers', [[
|
|
'id' => $user->getId(),
|
|
'firstName' => $user->getFirstName(),
|
|
'lastName' => $user->getLastName(),
|
|
'email' => $user->getEmail(),
|
|
'companyName' => $user->getCompanyName(),
|
|
'siret' => $user->getSiret(),
|
|
'city' => $user->getCity(),
|
|
]]);
|
|
|
|
$loginUrl = $this->generateUrl('app_login', [], UrlGeneratorInterface::ABSOLUTE_URL);
|
|
|
|
$mailerService->sendEmail(
|
|
to: $user->getEmail(),
|
|
subject: 'Votre compte organisateur a ete approuve - E-Ticket',
|
|
content: $this->renderView('email/organizer_approved.html.twig', [
|
|
'firstName' => $user->getFirstName(),
|
|
'loginUrl' => $loginUrl,
|
|
]),
|
|
withUnsubscribe: false,
|
|
);
|
|
|
|
$this->addFlash('success', sprintf('Organisateur %s %s approuve.', $user->getFirstName(), $user->getLastName()));
|
|
|
|
return $this->redirectToRoute('app_admin_organizers');
|
|
}
|
|
|
|
#[Route('/organisateur/{id}/refuser', name: 'app_admin_reject_organizer', methods: ['POST'])]
|
|
public function rejectOrganizer(User $user, Request $request, EntityManagerInterface $em, MailerService $mailerService): Response
|
|
{
|
|
$reason = trim($request->request->getString('reason'));
|
|
$email = $user->getEmail();
|
|
$firstName = $user->getFirstName();
|
|
$lastName = $user->getLastName();
|
|
|
|
$em->remove($user);
|
|
$em->flush();
|
|
|
|
$mailerService->sendEmail(
|
|
to: $email,
|
|
subject: 'Votre demande de compte organisateur a ete refusee - E-Ticket',
|
|
content: $this->renderView('email/organizer_rejected.html.twig', [
|
|
'firstName' => $firstName,
|
|
'reason' => $reason,
|
|
]),
|
|
withUnsubscribe: false,
|
|
);
|
|
|
|
$this->addFlash('success', sprintf('Demande de %s %s refusee.', $firstName, $lastName));
|
|
|
|
return $this->redirectToRoute('app_admin_organizers');
|
|
}
|
|
|
|
#[Route('/organisateur/{id}/siret', name: 'app_admin_siret_check')]
|
|
public function siretCheck(User $user, SiretService $siretService): Response
|
|
{
|
|
if ($user->isApproved()) {
|
|
return $this->redirectToRoute('app_admin_organizers');
|
|
}
|
|
|
|
$siret = $user->getSiret();
|
|
|
|
if (!$siret) {
|
|
$this->addFlash('error', 'Aucun SIRET renseigne.');
|
|
|
|
return $this->redirectToRoute('app_admin_organizers');
|
|
}
|
|
|
|
$data = $siretService->lookup($siret);
|
|
$rna = $data['complements']['identifiant_association'] ?? null;
|
|
$rnaData = $rna ? $siretService->lookupRna($rna) : null;
|
|
|
|
return $this->render('admin/siret_check.html.twig', [
|
|
'user' => $user,
|
|
'siret' => $siret,
|
|
'data' => $data,
|
|
'rnaData' => $rnaData,
|
|
]);
|
|
}
|
|
|
|
#[Route('/organisateur/{id}/siret/refresh', name: 'app_admin_siret_refresh', methods: ['POST'])]
|
|
public function siretRefresh(User $user, SiretService $siretService): Response
|
|
{
|
|
$siret = $user->getSiret();
|
|
|
|
if ($siret) {
|
|
$data = $siretService->lookup($siret);
|
|
$rna = $data['complements']['identifiant_association'] ?? null;
|
|
$siretService->clearCache($siret, $rna);
|
|
$this->addFlash('success', 'Cache SIRET vide. Les donnees ont ete rechargees.');
|
|
}
|
|
|
|
return $this->redirectToRoute('app_admin_siret_check', ['id' => $user->getId()]);
|
|
}
|
|
|
|
#[Route('/organisateur/{id}/modifier', name: 'app_admin_edit_organizer', methods: ['GET', 'POST'])]
|
|
public function editOrganizer(User $user, Request $request, EntityManagerInterface $em): Response
|
|
{
|
|
if (!$user->isApproved()) {
|
|
return $this->redirectToRoute('app_admin_organizers');
|
|
}
|
|
|
|
if ($request->isMethod('POST')) {
|
|
$user->setFirstName(trim($request->request->getString('first_name')));
|
|
$user->setLastName(trim($request->request->getString('last_name')));
|
|
$user->setEmail(trim($request->request->getString('email')));
|
|
$user->setPhone(trim($request->request->getString('phone')));
|
|
$user->setCompanyName(trim($request->request->getString('company_name')));
|
|
$user->setSiret(trim($request->request->getString('siret')));
|
|
$user->setAddress(trim($request->request->getString('address')));
|
|
$user->setPostalCode(trim($request->request->getString('postal_code')));
|
|
$user->setCity(trim($request->request->getString('city')));
|
|
$user->setOffer($request->request->getString('offer'));
|
|
$user->setCommissionRate((float) $request->request->getString('commission_rate'));
|
|
$em->flush();
|
|
|
|
$this->addFlash('success', sprintf('Organisateur %s %s mis a jour.', $user->getFirstName(), $user->getLastName()));
|
|
|
|
return $this->redirectToRoute('app_admin_organizers', ['tab' => 'approved']);
|
|
}
|
|
|
|
return $this->render('admin/edit_organizer.html.twig', [
|
|
'user' => $user,
|
|
]);
|
|
}
|
|
|
|
#[Route('/evenements', name: 'app_admin_events')]
|
|
public function events(Request $request, PaginatorInterface $paginator, \App\Service\EventIndexService $eventIndex): Response
|
|
{
|
|
$searchQuery = $request->query->getString('q', '');
|
|
$eventsQuery = $eventIndex->searchEvents('event_admin', $searchQuery);
|
|
|
|
$events = $paginator->paginate($eventsQuery, $request->query->getInt('page', 1), 10);
|
|
|
|
return $this->render('admin/events.html.twig', [
|
|
'events' => $events,
|
|
'searchQuery' => $searchQuery,
|
|
]);
|
|
}
|
|
|
|
#[Route('/logs', name: 'app_admin_logs', methods: ['GET'])]
|
|
public function logs(Request $request, EntityManagerInterface $em, PaginatorInterface $paginator): Response
|
|
{
|
|
$logs = $em->getRepository(AuditLog::class)->findBy([], ['createdAt' => 'DESC']);
|
|
$paginatedLogs = $paginator->paginate($logs, $request->query->getInt('page', 1), 30);
|
|
|
|
return $this->render('admin/logs.html.twig', [
|
|
'logs' => $paginatedLogs,
|
|
]);
|
|
}
|
|
|
|
#[Route('/organisateurs/inviter', name: 'app_admin_invite_organizer', methods: ['GET', 'POST'])]
|
|
public function inviteOrganizer(Request $request, EntityManagerInterface $em, MailerService $mailerService): Response
|
|
{
|
|
$invitations = $em->getRepository(OrganizerInvitation::class)->findBy([], ['createdAt' => 'DESC']);
|
|
|
|
if ($request->isMethod('POST')) {
|
|
$companyName = trim($request->request->getString('company_name'));
|
|
$firstName = trim($request->request->getString('first_name'));
|
|
$lastName = trim($request->request->getString('last_name'));
|
|
$email = trim($request->request->getString('email'));
|
|
$message = trim($request->request->getString('message')) ?: null;
|
|
$offer = $request->request->getString('offer', 'free');
|
|
$commissionRate = (float) $request->request->getString('commission_rate', '3');
|
|
|
|
if ('' === $companyName || '' === $firstName || '' === $lastName || '' === $email) {
|
|
$this->addFlash('error', 'Tous les champs obligatoires doivent etre remplis.');
|
|
|
|
return $this->redirectToRoute('app_admin_invite_organizer');
|
|
}
|
|
|
|
$invitation = new OrganizerInvitation();
|
|
$invitation->setCompanyName($companyName);
|
|
$invitation->setFirstName($firstName);
|
|
$invitation->setLastName($lastName);
|
|
$invitation->setEmail($email);
|
|
$invitation->setMessage($message);
|
|
$invitation->setOffer($offer);
|
|
$invitation->setCommissionRate($commissionRate);
|
|
|
|
$em->persist($invitation);
|
|
$em->flush();
|
|
|
|
$viewUrl = $this->generateUrl('app_invitation_view', [
|
|
'token' => $invitation->getToken(),
|
|
], UrlGeneratorInterface::ABSOLUTE_URL);
|
|
|
|
$html = $this->renderView('email/organizer_invitation.html.twig', [
|
|
'invitation' => $invitation,
|
|
'viewUrl' => $viewUrl,
|
|
]);
|
|
|
|
$mailerService->sendEmail(
|
|
$email,
|
|
'Invitation organisateur - E-Ticket',
|
|
$html,
|
|
'E-Ticket <contact@e-cosplay.fr>',
|
|
);
|
|
|
|
$this->addFlash('success', 'Invitation envoyee a '.$email.'.');
|
|
|
|
return $this->redirectToRoute('app_admin_invite_organizer');
|
|
}
|
|
|
|
return $this->render('admin/invite_organizer.html.twig', [
|
|
'invitations' => $invitations,
|
|
]);
|
|
}
|
|
|
|
#[Route('/organisateurs/invitation/{id}/supprimer', name: 'app_admin_delete_invitation', methods: ['POST'])]
|
|
public function deleteInvitation(int $id, EntityManagerInterface $em): Response
|
|
{
|
|
$invitation = $em->getRepository(OrganizerInvitation::class)->find($id);
|
|
if (!$invitation) {
|
|
throw $this->createNotFoundException();
|
|
}
|
|
|
|
$em->remove($invitation);
|
|
$em->flush();
|
|
|
|
$this->addFlash('success', 'Invitation supprimee.');
|
|
|
|
return $this->redirectToRoute('app_admin_invite_organizer');
|
|
}
|
|
|
|
#[Route('/organisateurs/invitation/{id}/renvoyer', name: 'app_admin_resend_invitation', methods: ['POST'])]
|
|
public function resendInvitation(int $id, EntityManagerInterface $em, MailerService $mailerService): Response
|
|
{
|
|
$invitation = $em->getRepository(OrganizerInvitation::class)->find($id);
|
|
if (!$invitation) {
|
|
throw $this->createNotFoundException();
|
|
}
|
|
|
|
$viewUrl = $this->generateUrl('app_invitation_view', [
|
|
'token' => $invitation->getToken(),
|
|
], UrlGeneratorInterface::ABSOLUTE_URL);
|
|
|
|
$html = $this->renderView('email/organizer_invitation.html.twig', [
|
|
'invitation' => $invitation,
|
|
'viewUrl' => $viewUrl,
|
|
]);
|
|
|
|
$mailerService->sendEmail(
|
|
$invitation->getEmail(),
|
|
'Invitation organisateur - E-Ticket',
|
|
$html,
|
|
'E-Ticket <contact@e-cosplay.fr>',
|
|
);
|
|
|
|
$invitation->setStatus(OrganizerInvitation::STATUS_SENT);
|
|
$invitation->setRespondedAt(null);
|
|
$em->flush();
|
|
|
|
$this->addFlash('success', 'Invitation renvoyee a '.$invitation->getEmail().'.');
|
|
|
|
return $this->redirectToRoute('app_admin_invite_organizer');
|
|
}
|
|
}
|