<?php
namespace App\Factory\Security;
use App\Entity\Interfaces\SpotHitCampaignInterface;
use App\Entity\Regate;
use App\Entity\RequestRegistration;
use App\Entity\SmsSpotHitCampaign;
use App\Entity\User;
use App\Factory\Platform\MailerFactory;
use App\Services\Common\Email\MailTypes;
use App\Services\Common\MailerService;
use App\Services\Common\Sms\SmsTypes;
use App\Services\Common\User\WorkflowUser;
use App\Services\ConfigService;
use App\Services\DTV\YamlConfig\YamlReader;
use App\Services\Portal\PortalService;
use App\Services\Security\RegisterService;
use App\Services\SpotHitService;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use RuntimeException;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
class SecurityFormFactory
{
private string $domain;
private FormFactoryInterface $formFactory;
private UserPasswordHasherInterface $userPasswordHasher;
private EntityManagerInterface $em;
private ValidatorInterface $validator;
private MailerService $mailerService;
private YamlReader $yamlReader;
private WorkflowUser $workflowUser;
private RegisterService $registerService;
private PortalService $portalService;
private SpotHitService $spotHitService;
public function __construct(
ConfigService $configService,
FormFactoryInterface $formFactory,
UserPasswordHasherInterface $userPasswordHasher,
EntityManagerInterface $em,
ValidatorInterface $validator,
YamlReader $yamlReader,
MailerService $mailerService,
WorkflowUser $workflowUser,
RegisterService $registerService,
PortalService $portalService,
SpotHitService $spotHitService
) {
$this->domain = $configService->get('subdomain');
$this->formFactory = $formFactory;
$this->userPasswordHasher = $userPasswordHasher;
$this->em = $em;
$this->validator = $validator;
$this->yamlReader = $yamlReader;
$this->mailerService = $mailerService;
$this->workflowUser = $workflowUser;
$this->registerService = $registerService;
$this->portalService = $portalService;
$this->spotHitService = $spotHitService;
}
private function getGlobalRegisterConfig(): array
{
return $this->yamlReader->getRegister();
}
/**
* Retourne le formulaire d'inscription selon le projet
*
* @param User $user
*
* @return FormInterface
*
* @throws Exception
*/
public function generateRegisterForm(User $user): FormInterface
{
// on regarde si le register est actif sur la partie login de security ou s'il est actif sur une page à part
if ($this->isRegisterEnabled()) {
$formType = 'App\Form\Type\Registration\\' . $this->getGlobalRegisterConfig()[ 'type' ];
return $this->formFactory->create($formType, $user);
}
throw new RuntimeException('impossible de trouver le projet pour la génération du formulaire d\'inscription, projet : ' . $this->domain);
}
/**
* @return bool|mixed
*/
public function isRegisterEnabled()
{
$globalEnabled = $this->getGlobalRegisterConfig()[ 'enabled' ];
$isEnabled = $globalEnabled;
// $frontConfig = $this->yamlReader->getFrontSecurity();
// $loginEnabled = $frontConfig[ 'login' ][ 'sections' ][ 'section_register' ][ 'enabled' ];
// $registerEnabled = $frontConfig[ 'register' ][ 'enabled' ];
// if ($isEnabled) {
// $isEnabled = $loginEnabled !== $registerEnabled;
// }
return $isEnabled;
}
/**
* Fait le post traitement du formulaire d'inscription selon le projet
*
* @param FormInterface $form
* @param User $user
*
* @return array
*
* @throws LoaderError
* @throws RuntimeError
* @throws SyntaxError
* @throws Exception|TransportExceptionInterface
*/
public function postProcessingRegisterForm(FormInterface $form, User $user): array
{
$globalRegisterConfig = $this->getGlobalRegisterConfig();
// Registration pour les plateformes qui n'ont pas de mot de passe à renseigner lors de l'inscription
if ($form->has('password')) {
$plainPassword = $form->get('password')->getData();
$user->setPassword($this->userPasswordHasher->hashPassword($user, $plainPassword));
} else {
$user->setPassword('pending-validation');
}
// TODO changer si besoin de personnalisation
$email_validate = $globalRegisterConfig[ 'email_validate' ];
$emails = [];
if (!in_array($email_validate, [NULL, ''], TRUE)) {
$email_validate = str_replace(' ', '', $email_validate);
$emails = explode(';', $email_validate);
} else {
$emails[] = 'dev@37deux.com';
}
$contactRegisterValidate = [];
foreach ($emails as $email) {
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$contactRegisterValidate[] = [
"name" => $email,
"email" => $email,
];
}
}
switch ($globalRegisterConfig[ 'process' ]) {
case 'register_validate': // challenge-eastim-peugeotfi.dtv.loc & citroentf
///check doublon email en BDD
$userDoublon = $this->em->getRepository(User::class)->findOneBy(['email' => $form->get('email')->getData()]);
if($userDoublon && $userDoublon->getId() !== $form->getData()->getId()) {
$result = [
'type' => 'danger',
'route' => 'app_login',
'message' => new TranslatableMessage('cette email existe déjà'),
];
break;
}
$user->setRoles(['ROLE_USER']);
$this->em->persist($user);
$requestRegistration = new RequestRegistration();
$requestRegistration->setUser($user);
$this->em->persist($requestRegistration);
$this->em->flush();
$this->workflowUser->needAdminValidation($user);
// Mail validation inscription
$this->mailerService->createApiMailRequest(MailTypes::REGISTRATION_TO_VALIDATE);
foreach ($contactRegisterValidate as $item) {
$this->mailerService->addRecipientToRequest(
[
'name' => $item[ 'name' ],
'email' => $item[ 'email' ],
],
MailerFactory::buildRegistrationToValidate($user)
);
}
$this->mailerService->send();
$result = [
'type' => 'success',
'route' => 'app_login',
'message' => new TranslatableMessage('votre inscription a été envoyée'),
];
break;
case 'register_regate_job': // animation-lpm
$job = $form->get('job')->getData();
$regateCode = $form->get('regate')->getData();
$regate = $this->em->getRepository(Regate::class)
->findOneBy(['affectation' => $regateCode,])
;
$user->setRoles(['ROLE_USER'])
->setJob($job)
->setRegate($regate)
;
$this->em->persist($user);
$requestRegistration = new RequestRegistration();
$requestRegistration->setUser($user);
$this->em->persist($requestRegistration);
$this->em->flush();
$this->workflowUser->needAdminValidation($user);
// Mail validation inscription
$this->mailerService->createApiMailRequest(MailTypes::REGISTRATION_TO_VALIDATE);
foreach ($contactRegisterValidate as $item) {
$this->mailerService->addRecipientToRequest(
[
'name' => $item[ 'name' ],
'email' => $item[ 'email' ],
],
MailerFactory::buildRegistrationToValidate($user)
);
}
$this->mailerService->send();
$result = [
'type' => 'success',
'route' => 'app_login',
'message' => new TranslatableMessage('votre inscription a été envoyée'),
];
break;
case 'register_validate_zipcode_commercial': // Rehau
$user->setRoles(['ROLE_USER'])->setJob('installer');
///check doublon email en BDD
$userDoublon = $this->em->getRepository(User::class)->findOneBy(['email' => $form->get('email')->getData()]);
if($userDoublon && $userDoublon->getId() !== $form->getData()->getId()) {
$result = [
'type' => 'danger',
'route' => 'app_register',
'message' => new TranslatableMessage('cette email existe déjà'),
];
break;
}
// Validation par un commercial
$linkedCommercial = NULL;
if (!isset($globalRegisterConfig[ 'validation_by_commercial' ]) || $globalRegisterConfig[ 'validation_by_commercial' ] === TRUE)
{
$linkedCommercials = $this->em->getRepository(User::class)->findCommercialByDepartment(substr($user->getPostcode(), 0, 2));
if (count($linkedCommercials) > 0) {
/** @var User $linkedCommercial */
$linkedCommercial = $linkedCommercials[ 0 ];
$user->setCommercial($linkedCommercial);
} else {
$result = [
'type' => 'danger',
'route' => 'app_register',
'message' => new TranslatableMessage('impossible de trouver un commercial dans votre département'),
];
break;
}
}
$this->em->persist($user);
$requestRegistration = new RequestRegistration();
$requestRegistration->setUser($user)->setReferent($linkedCommercial);
$this->em->persist($requestRegistration);
// Mail de validation par un commercial
if ((!isset($globalRegisterConfig[ 'validation_by_commercial' ]) || $globalRegisterConfig[ 'validation_by_commercial' ] === TRUE) && $linkedCommercial instanceof User)
{
$validateurs = [$linkedCommercial];
if(!empty($globalRegisterConfig[ 'validation_by_admin']))
{
$admins = !is_array($globalRegisterConfig['validation_by_admin']) ? [$globalRegisterConfig['validation_by_admin']] : $globalRegisterConfig['validation_by_admin'];
foreach($admins as $admin)
{
$admin = $this->em->getRepository(User::class)->createQueryBuilder('u')
->where('u.roles LIKE \'%ROLE_ADMIN%\'')
->andWhere('u.status IN (\'cgu_pending\', \'enabled\')')
->andWhere('u.email = :email')->setParameter('email', $admin)
->setMaxResults(1)
->getQuery()->getOneOrNullResult()
;
if($admin) $validateurs[] = $admin;
}
}
foreach($validateurs as $validateur)
{
$this->mailerService
->createApiMailRequest(MailTypes::REGISTRATION_TO_VALIDATE)
->addRecipientToRequest($validateur, MailerFactory::buildRegistrationToValidate($user))
->send()
;
}
}
$this->workflowUser->needAdminValidation($user);
$this->em->flush();
$result = [
'type' => 'success',
'route' => 'app_register_waiting_validation',
'message' => new TranslatableMessage('votre inscription a été envoyée'),
];
break;
case 'register_replace_fake_user_by_sellerCode':
$user = $this->registerService->registerReplaceFakeUserBySellerCode(
$user,
$form->get('sellerCode')->getData()
);
$result = $this->handleUserResult($user);
break;
case 'register_replace_fake_user_with_accountId_by_sellerCode':
$user = $this->registerService->registerReplaceAccountIdFakeUserBySellerCodeOrAccountId(
$user,
$form,
false,
'sellerCode'
);
$result = $this->handleUserResult($user);
break;
case 'register_replace_fake_user_with_accountId_by_accountId':
$user = $this->registerService->registerReplaceAccountIdFakeUserBySellerCodeOrAccountId(
$user,
$form,
false,
'accountId'
);
$result = $this->handleUserResult($user);
break;
default:
throw new RuntimeException(
'impossible de trouver le process pour post-traiter le formulaire d\'inscription. process : ' . $globalRegisterConfig[ 'process' ],
);
}
if($user instanceof User && $result['type'] === 'success' && $form->has('sendCguBySms') && $form->get('sendCguBySms')->getData())
{
$smsCampaign = $this->spotHitService->createSmsCampaign(
SmsSpotHitCampaign::CAMPAIGN_TYPE_ACCEPT_CGU_FIRST,
$this->yamlReader->getMailer()['transactional_sms'][SmsTypes::ACCEPT_CGU_FIRST],
$user,
'SMS_' . SmsTypes::ACCEPT_CGU_FIRST . '_' . $user->getId() . '_' . (new \DateTime())->format('YmdHis')
);
$smsCampaign->setStatut(SpotHitCampaignInterface::STATUT_EN_COURS);
$this->em->flush();
$return = $this->spotHitService->sendSmsCampaign($smsCampaign);
if(is_string($return)) {
$smsCampaign->setStatut(SpotHitCampaignInterface::STATUT_EN_ERREUR);
$smsCampaign->setErreur($return);
$result = [
'type' => 'danger',
'route' => 'app_register',
'message' => new TranslatableMessage("une erreur est survenue lors de l'envoi du sms"),
];
}
else {
$smsCampaign->setStatut(SpotHitCampaignInterface::STATUT_ENVOYEE);
$result = [
'type' => 'success',
'route' => 'app_register',
'message' => new TranslatableMessage("vous allez recevoir un email ainsi qu'un sms pour confirmer votre inscription"),
];
}
$this->em->flush();
}
return $result;
}
private function handleUserResult($result): array
{
if ($result instanceof User) {
return [
'type' => 'success',
'route' => 'app_login',
'message' => new TranslatableMessage('vous allez recevoir un email pour confirmer votre inscription'),
];
}
return [
'type' => 'danger',
'route' => 'app_login',
'message' => new TranslatableMessage("une erreur s'est produite, veuillez réessayer"),
];
}
/**
* @param FormInterface $form
*
* @return FormInterface
*
* @throws Exception
*/
public function postValidateRegisterForm(FormInterface $form): FormInterface
{
return $this->registerService->postValidateForm($this->getGlobalRegisterConfig()[ 'post_validate' ], $form);
}
}