<?php
declare(strict_types=1);
namespace App\Controller;
use App\Entity\Account;
use App\Entity\AccountOrganization;
use App\Entity\AccountPro;
use App\Entity\UserInterface;
use App\Form\AccountOrganizationRegistrationProfilType;
use App\Form\AccountProRegistrationProfilType;
use App\Form\AccountProRegistrationType;
use App\Form\AccountRegistrationProfilType;
use App\Form\AccountRegistrationType;
use App\Form\ResetPasswordRequestFormType;
use App\Kernel;
use App\Repository\AccountOrganizationRepository;
use App\Repository\AccountProRepository;
use App\Repository\AccountRepository;
use App\Repository\OrganizationRepository;
use App\Repository\PermissionRepository;
use App\Repository\PraticienRepository;
use App\Service\AccountOrganizationService;
use App\Service\AccountProService;
use App\Service\AccountService;
use App\Service\AclService;
use App\Service\Mail\AccountOrganizationPasswordMailer;
use App\Service\Mail\AccountPasswordMailer;
use App\Service\Mail\AccountProPasswordMailer;
use App\Service\Mail\AccountProRegistrationMailer;
use App\Service\Mail\AccountRegistrationMailer;
use App\Service\Security;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class SecurityController extends AbstractController
{
#[Route('/deconnexion', name: 'account_logout')]
public function accountLogout(Security $security): RedirectResponse
{
$security->logout();
return $this->redirectToRoute('home');
}
#[Route('/app/connexion', name: 'account_login')]
public function accountLogin(Security $security, Request $request, AccountService $accountService): Response
{
return $this->redirectToRoute("home");
}
#[Route('/pro/connexion', name: 'accountpro_login')]
public function accountProLogin(Security $security, Request $request, AccountProService $accountProService): Response
{
// Redirige l'utilisateur déjà connecté
if ($security->getUser() instanceof AccountPro) {
return $this->redirectToRoute('pro_home');
}
// Traite le formulaire de connexion
if ($request->isMethod('POST') && $this->isCsrfTokenValid('authenticate', $request->request->get('csrf'))) {
// On récupère le compte qui s'authentifie
$account = $accountProService->getByLogin(
$request->request->get('email'),
$request->request->get('password'),
);
// Si un compte est valide et non supprimé, on le monte en session
if ($account instanceof AccountPro && !$account->isDeleted()) {
$security->login($account,$request);
return $this->redirectToRoute('pro_home');
}
// Gestion d'un message d'erreur
$this->addFlash('warning', 'Ces identifiants ne permettent pas de retrouver votre compte');
}
// Affiche le formulaire de connexion
return $this->render('security/accountpro_login.html.twig');
}
#[Route('/gestion/connexion', name : 'manager_login')]
public function managerLogin(
Security $security,
Request $request,
AccountOrganizationService $accountOrganizationService
):Response {
// Redirige l'utilisateur déjà connecté
if ($security->getUser() instanceof AccountOrganization) {
return $this->redirectToRoute('manager_home');
}
// Traite le formulaire de connexion
if ($request->isMethod('POST') && $this->isCsrfTokenValid('authenticate', $request->request->get('csrf'))) {
// On récupère le compte qui s'authentifie
$account = $accountOrganizationService->getByLogin(
$request->request->get('email'),
$request->request->get('password'),
);
// Si un compte est valide et non supprimé, on le monte en session
if ($account instanceof AccountOrganization) {
$security->login($account, $request);
return $this->redirectToRoute('manager_home');
}
// Gestion d'un message d'erreur
$this->addFlash('warning', 'Ces identifiants ne permettent pas de retrouver votre compte');
}
// Affiche le formulaire de connexion
return $this->render('security/manager_login.html.twig');
}
#[Route('/pro/inscription', name : 'accountpro_registration')]
public function index(
Request $request,
AccountProService $accountProService,
AccountProRegistrationMailer $accountProRegistrationMailer,
PraticienRepository $praticienRepository,
Security $security
):Response {
if ($security->getUser()) {
return $this->redirectToRoute('pro_home');
}
// Créé et peuple le formulaire
$form = $this
->createForm(AccountProRegistrationType::class)
->handleRequest($request);
// Traite le formulaire
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$praticien = $praticienRepository->findOneBy([
'idPP' => $data['rpps'],
'isDeleted' => 0,
]);
if ($praticien) {
$accountPro = new AccountPro();
$accountPro
->setFirstname($data['firstname'])
->setLastname($data['lastname'])
->setEmail($data['email'])
->setProfession($data['profession'])
->setMobile($data['mobile'])
->setRpps($data['rpps'])
->setIsDeleted(false);
// Enregistre le compte en base de données
try {
$accountProService->register($accountPro);
// Envoie du mail de confirmation d'inscription
$accountProRegistrationMailer->send($accountPro);
return $this->render('registration/accountpro/index_confirmation.html.twig', [
'account' => $accountPro,
]);
} catch (UniqueConstraintViolationException $e) {
// Todo : Gérer avec @UniqueEntity plutôt qu'avec l'exception
$form->get('email')->addError(new FormError('Ce compte existe déjà'));
}
} else {
$form->get('rpps')->addError(new FormError('Ce numéro n\'est pas autorisé, vérifiez votre carte ou contactez-nous.'));
}
}
return $this->render('registration/accountpro/index.html.twig', [
'form' => $form->createView(),
]);
}
#[Route('/pro/activation/{token}', name: 'accountpro_registration_profil')]
public function proProfil(
$token,
Request $request,
AccountProService $accountProService,
Security $security
): Response {
if ($security->getUser()) {
return $this->redirectToRoute('pro_home');
}
$accountPro = $accountProService->getByActivationToken($token);
if (!$accountPro instanceof AccountPro) {
$this->addFlash('error', [
"Le lien d'activation n'est plus valide.",
"Indiquez votre adresse email pour récupérer un nouveau lien."
]);
return $this->redirectToRoute('pro_forgot_password_request');
}
$form = $this
->createForm(AccountProRegistrationProfilType::class, $accountPro)
->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accountProService->activate($accountPro);
$security->login($accountPro, $request);
return $this->redirectToRoute('pro_home');
}
return $this->render('registration/accountpro/profil.html.twig', [
'form' => $form->createView(),
'account' => $accountPro,
]);
}
#[Route('/app/inscription/{urlCode}', name : 'account_registration')]
public function appInscription(
Request $request,
AccountService $accountService,
AccountRegistrationMailer $accountRegistrationMailer,
Security $security,
OrganizationRepository $organizationRepository,
Kernel $kernel,
?string $urlCode = null,
PermissionRepository $permissionRepository
):Response {
if ($security->getUser()) {
return $this->redirectToRoute('app');
}
// Récupère le code dans l'url puis l'organisme correspondant s'il existe
$organization = $organizationRepository->findOneBy(['registrationCode' => $urlCode]);
// S'il y a un code dans l'url et que le code n'est pas un code d'activation valide, la page est redirigée
if ($urlCode && !$organization) {
return $this->redirectToRoute('account_registration', ['urlCode' => null]);
}
// Créé et peuple le formulaire
$form = $this
->createForm(AccountRegistrationType::class, null, ["activationCode" => $urlCode])
->handleRequest($request);
// Traite le formulaire s'il est soumis et valide
if ($form->isSubmitted() && $form->isValid()) {
/** @var Account $account */
$data = $form->getData();
// Récupère le code d'activation correspondant au code saisie dans le formulaire
$code = $form->get('activationCode')->getData();
$organization = $organizationRepository->findOneBy(['registrationCode' => $code]);
if ($organization?->isEnabledRegistration()) {
$account = new Account();
$account->setFirstname($data['firstname'])
->setName($data['name'])
->setEmail($data['email'])
->setOrganization($organization)
->setEnable(true)
;
// En dev ou beta, les comptes créés sont des comptes de demo
if ($kernel->getEnvironment() !== 'prod') {
$account->addRole('ROLE_DEMO');
}
} else {
//Si le code d'activation n'existe pas ou est désactivé, la création du compte n'est pas possible
$this->addFlash('warning', [
'Code d\'activation invalide',
'Le code d\'activation est fourni par votre entreprise ou votre association.',
]);
return $this->render('registration/account/index.html.twig', [
'form' => $form->createView(),
]);
}
try {
// Assigne les permissions à l'utilisateur en fonction de ses roles
$aclService = new AclService($security);
$permissionNames = [];
$rolePermissionMap = $aclService->getRolePermissionMap();
foreach ($account->getRoles() as $role) {
if (isset($rolePermissionMap[$role])) {
$permissionNames += $rolePermissionMap[$role];
}
}
$permissions = $permissionRepository->findBy(['name' => $permissionNames]);
$account->setPermissions($permissions);
// Enregistre le compte en base de données
$accountService->register($account);
// Envoie du mail de confirmation d'inscription
$accountRegistrationMailer->send($account);
return $this->render('registration/account/index_confirmation.html.twig', [
'account' => $account,
]);
} catch (UniqueConstraintViolationException $e) {
// Todo : Gérer avec @UniqueEntity plutôt qu'avec l'exception
$form->get('email')->addError(new FormError('Ce compte existe déjà'));
}
}
return $this->render('registration/account/index.html.twig', [
'form' => $form->createView(),
]);
}
#[Route('/app/activation/{token}', name: 'account_registration_profil')]
public function appProfil(
$token,
Request $request,
AccountService $accountService,
Security $security
): Response {
if ($security->getUser()) {
return $this->redirectToRoute('app');
}
$account = $accountService->getByActivationToken($token);
if (!$account instanceof Account) {
$this->addFlash('error', [
"Le lien d'activation n'est plus valide.",
"Indiquez votre adresse email pour récupérer un nouveau lien."
]);
return $this->redirectToRoute('app_forgot_password_request');
}
$form = $this
->createForm(AccountRegistrationProfilType::class, $account)
->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accountService->activate($account);
$security->login($account, $request);
return $this->redirectToRoute('app');
}
return $this->render('registration/account/profil.html.twig', [
'form' => $form->createView(),
'account' => $account,
]);
}
#[Route('/gestion/activation/{token}', name : 'account_organization_registration_profil')]
public function managerProfil(
$token,
Request $request,
AccountOrganizationService $accountOrganizationService,
Security $security
):Response {
if ($security->getOrganization()) {
return $this->redirectToRoute('manager_home');
}
$account = $accountOrganizationService->getByActivationToken($token);
if (!$account instanceof AccountOrganization) {
$this->addFlash('error', [
"Le lien d'activation n'est plus valide.",
'Indiquez votre adresse email pour récupérer un nouveau lien.',
]);
return $this->redirectToRoute('manager_forgot_password_request');
}
$form = $this
->createForm(AccountOrganizationRegistrationProfilType::class, $account)
->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$accountOrganizationService->activate($account);
$security->login($account, $request);
return $this->redirectToRoute('manager_home');
}
return $this->render('registration/manager/profil.html.twig', [
'form' => $form->createView(),
'account' => $account,
]);
}
#[Route('/app/mot-de-passe', name : 'app_forgot_password_request')]
public function password(
Request $request,
Security $security,
AccountService $accountService,
AccountRepository $accountRepository,
AccountProRepository $accountProRepository,
AccountPasswordMailer $accountPasswordMailer
):Response {
if ($security->getUser() instanceof Account) {
return $this->redirectToRoute('app');
}
$form = $this->createForm(ResetPasswordRequestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $accountRepository->findOneBy([
'email' => $form->get('email')->getData(),
]);
if ($user === null) {
$user = $accountProRepository->findOneBy([
'email' => $form->get('email')->getData(),
]);
}
if ($user instanceof UserInterface) {
$token = $accountService->tokenRequest($user);
$accountPasswordMailer->send($user, $token);
}
return $this->render('reset_password/check_email.html.twig');
}
return $this->render('reset_password/request.html.twig', [
'requestForm' => $form->createView(),
]);
}
#[Route('/pro/mot-de-passe', name: 'pro_forgot_password_request')]
public function proPassword(
Request $request,
Security $security,
AccountProService $accountProService,
AccountRepository $accountRepository,
AccountProRepository $accountProRepository,
AccountProPasswordMailer $accountProPasswordMailer
): Response {
if ($security->getUser() instanceof AccountPro) {
return $this->redirectToRoute('app');
}
$form = $this->createForm(ResetPasswordRequestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $accountProRepository->findOneBy([
'email' => $form->get('email')->getData(),
]);
if ($user === null) {
$user = $accountRepository->findOneBy([
'email' => $form->get('email')->getData(),
]);
}
if ($user instanceof UserInterface) {
$token = $accountProService->tokenRequest($user);
$accountProPasswordMailer->send($user, $token);
}
return $this->render('reset_password/check_email.html.twig', [
'context' => 'pro',
]);
}
return $this->render('reset_password/request.html.twig', [
'requestForm' => $form->createView(),
'context' => 'pro',
]);
}
#[Route('/gestion/mot-de-passe', name : 'manager_forgot_password_request')]
public function managerPassword(
Request $request,
Security $security,
AccountOrganizationRepository $accountOrganizationRepository,
AccountOrganizationService $accountOrganizationService,
AccountOrganizationPasswordMailer $accountOrganizationPasswordMailer
):Response {
if ($security->getOrganization() instanceof AccountOrganization) {
return $this->redirectToRoute('manager_home');
}
$form = $this->createForm(ResetPasswordRequestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $accountOrganizationRepository->findOneBy([
'email' => $form->get('email')->getData(),
]);
if ($user instanceof AccountOrganization) {
$token = $accountOrganizationService->tokenRequest($user);
$accountOrganizationPasswordMailer->send($user, $token);
}
return $this->render('reset_password/check_email.html.twig', [
'context' => 'manager',
]);
}
return $this->render('reset_password/request.html.twig', [
'requestForm' => $form->createView(),
'context' => 'manager',
]);
}
}