src/Controller/BaseController.php line 86

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Alert;
  4. use App\Entity\Availabilities;
  5. use App\Entity\EnumValues;
  6. use App\Entity\FavoriteOffer;
  7. use App\Entity\Guarantor;
  8. use App\Entity\MD5HashCheck;
  9. use App\Entity\MailingSearch;
  10. use App\Entity\Offer;
  11. use App\Entity\OfferImage;
  12. use App\Entity\OfferTenantApplication;
  13. use App\Entity\Page;
  14. use App\Entity\User;
  15. use App\Entity\WorkStatus;
  16. use App\Form\ModalOfferType;
  17. use App\Form\OfferType;
  18. use App\Form\RegisterFormType;
  19. use App\Form\SearchFrontFormType;
  20. use App\Form\SignConventionType;
  21. use App\Form\UpdatePasswordType;
  22. use App\Repository\AgencyRepository;
  23. use App\Repository\EnumValuesRepository;
  24. use App\Repository\FavoriteOfferRepository;
  25. use App\Repository\MailingSearchRepository;
  26. use App\Repository\OfferRepository;
  27. use App\Repository\OfferTenantApplicationRepository;
  28. use App\Repository\UserRepository;
  29. use App\Security\LoginFormAuthenticator;
  30. use App\Service\CustomMailer;
  31. use App\Service\CustomPdfGenerator;
  32. use App\Service\FormLabelHydrater;
  33. use App\Service\PhoneNumberHelper;
  34. use App\Service\SearchParameterChecker;
  35. use App\Service\Securizer;
  36. use App\Service\SignConvention;
  37. use Doctrine\DBAL\DBALException;
  38. use Doctrine\ORM\EntityManagerInterface;
  39. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  40. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  41. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
  42. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  43. use Symfony\Bundle\FrameworkBundle\Controller\createFormBuilder;
  44. use Symfony\Bundle\FrameworkBundle\Controller\denyAccessUnlessGranted;
  45. use Symfony\Bundle\FrameworkBundle\Controller\redirectToRoute;
  46. use Symfony\Component\EventDispatcher\EventDispatcher;
  47. use Symfony\Component\Filesystem\Filesystem;
  48. use Symfony\Component\Form\Extension\Core\Type\EmailType;
  49. use Symfony\Component\Form\Extension\Core\Type\TextType;
  50. use Symfony\Component\Form\FormError;
  51. use Symfony\Component\HttpFoundation\File\Exception\FileException;
  52. use Symfony\Component\HttpFoundation\JsonResponse;
  53. use Symfony\Component\HttpFoundation\Request;
  54. use Symfony\Component\HttpFoundation\Response;
  55. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  56. use Symfony\Component\Routing\Annotation\Route;
  57. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  58. use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  59. use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
  60. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  61. use Symfony\Component\Validator\Constraints\Email;
  62. use Symfony\Component\Validator\Constraints\NotBlank;
  63. use Symfony\Component\Validator\Constraints\Type;
  64. class BaseController extends AbstractController
  65. {
  66.     public $parkingType;
  67.     public $buildingType;
  68.     public $constructionType;
  69.     public $nbrRooms;
  70.     public function __construct(FormLabelHydrater $hydraterEnumValuesRepository $enumrepo)
  71.     {
  72.         $labels $hydrater->getOfferLabels();
  73.         $this->nbrRooms $enumrepo->findOneBy(['name' => 'nbrRooms'])->getData();
  74.         $this->buildingType array_flip($labels['buildingType']);
  75.         $this->parkingType array_flip($labels['parkingType']);
  76.         $this->constructionType array_flip($labels['constructionType']);
  77.     }
  78.     /**
  79.      * @Route("/", name="homepage")
  80.      */
  81.     public function index(OfferRepository $repoRequest $request)
  82.     {
  83.         $sums $repo->getNbrOffersByDepartments();
  84.         $latests $repo->getLatest();
  85.         $congratulations $request->get('congratulations')??null;
  86.         //$buildingType = $enumrepo->findOneBy(['name' => 'buildingType'])->getData();
  87.         //$constructionType = $enumrepo->findOneBy(['name' => 'constructionType'])->getData();
  88.         return $this->render('base/index.html.twig', [
  89.             'controller_name'    => 'BaseController',
  90.             'sums'                => $sums,
  91.             'latests'            => $latests,
  92.             'nbrRooms'            => $this->nbrRooms,
  93.             'buildingType'        => $this->buildingType,
  94.             'constructionType'    => $this->constructionType,
  95.             'total'                => array_sum($sums),
  96.             'show_free_estimate_modal' => true,
  97.             'congratulations'   => $congratulations??null,
  98.         ]);
  99.     }
  100.     /**
  101.      * @Route("/annonces/departement/{department}", name="list_offers_by_department")
  102.      */
  103.     public function listOffersByDepartment($department nullOfferRepository $repoEnumValuesRepository $enumrepo)
  104.     {
  105.         if ($department == null && !in_array($department, ['75''77''78''91''92''93''94''95']))
  106.         {
  107.             return $this->redirectToRoute('homepage');
  108.         }
  109.         $results $repo->searchFrontSide(['departments' => [$department]]);
  110.         $latest $repo->getLatest();
  111.         $sums $repo->getNbrOffersByDepartments();
  112.         $buildingType $enumrepo->findOneBy(['name' => 'buildingType'])->getData();
  113.         $nbrRoom $enumrepo->findOneBy(['name' => 'nbrRooms'])->getData();
  114.         $constructionType $enumrepo->findOneBy(['name' => 'constructionType'])->getData();
  115.         return $this->render('base/search_results.html.twig', [
  116.             'controller_name'    => 'BaseController',
  117.             'results'            => $results ?? [],
  118.             'latests'            => $latest,
  119.             'sums'                => $sums,
  120.             'buildingType'        => $this->buildingType,
  121.             'nbrRoom'            => $this->nbrRooms,
  122.             'departments'        => $department,
  123.             'constructionType'    => $this->constructionType,
  124.         ]);
  125.     }
  126.     /**
  127.      * @Route("/resultats-recherche", name="search_results")
  128.      */
  129.     public function searchResults(Request $requestEntityManagerInterface $managerOfferRepository $repoSessionInterface $sessionEnumValuesRepository $enumrepo)
  130.     {
  131.         if ($session->has('searchParameters'))
  132.         {
  133.             $parameters $session->get('searchParameters');
  134.             $session->remove('searchParameters');
  135.         }
  136.         $user $this->getUser();
  137.         $results $repo->searchFrontSide($parameters ?? nullFALSE$user $user->getId() : null);
  138.         $buildingType $enumrepo->findOneBy(['name' => 'buildingType'])->getData();
  139.         $nbrRoom $enumrepo->findOneBy(['name' => 'nbrRooms'])->getData();
  140.         $constructionType $enumrepo->findOneBy(['name' => 'constructionType'])->getData();
  141.         return $this->render('base/search_results.html.twig', [
  142.             'controller_name'        => 'BaseController',
  143.             'buildingType'            => $this->buildingType,
  144.             'buildingTypeParameter'    => $parameters['buildingType'] ?? null,
  145.             'departments'            => $parameters['departments'] ?? null,
  146.             'price'                    => $parameters['price'] ?? null,
  147.             'surface'                => $parameters['surface'] ?? null,
  148.             'nbrRooms'                => $parameters['nbrRooms'] ?? null,
  149.             'nbrRoom'                => $this->nbrRooms,
  150.             'constructionType'    => $this->constructionType,
  151.             'results'                => $results ?? [],
  152.         ]);
  153.     }
  154.     /**
  155.      * @Route("/annonce/{slug}", name="view_offer_profile")
  156.     
  157.     public function viewOffer(Offer $offer = null)
  158.     {
  159.         if ($offer == null)
  160.         {
  161.             $this->addFlash('danger', 'Cette annonce n\'est plus disponible !');
  162.             return $this->redirectToRoute('homepage');
  163.         }
  164.         $user = $offer->getUser();
  165.         $values = $valuesRepo->findAllEnums();
  166.         // see App\Security\Voter\CheckMethodsAccessVoter
  167.         $this->denyAccessUnlessGranted('OWNER_OR_ADMIN', $user);
  168.         return $this->render('offer/view_offer.html.twig', [
  169.                 'offer'        => $offer,
  170.                 'values'    => $values,
  171.             ]
  172.         );
  173.     } */
  174.     /**
  175.      * @Route("/save-parameters", name="save_parameters")
  176.      */
  177.     public function saveParameters(Request $requestSessionInterface $sessionSearchParameterChecker $checker)
  178.     {
  179.         // get search parameters from homepage, check it, put it in session, and redirect to search page
  180.         if ($request->isXmlHttpRequest() && isset($request->request))
  181.         {
  182.             $search $request->request->get('searchParameters');
  183.             // lazy & ugly solution, doesn't mind
  184.             $login_route $request->request->get('login_route_plz') ?? false;
  185.             $path $login_route $this->generateUrl('login') : $this->generateUrl('search_results');
  186.             $parameters $checker->checkParameters($search);
  187.             // if search is empty, it's cool, we just send ok status to trigger the redirection
  188.             if (empty($parameters))
  189.             {
  190.                 $session->remove('searchParameters');
  191.                 return new JsonResponse(['status' => 'ok''path' => $path]);
  192.             }
  193.             $session->set('searchParameters'$parameters);
  194.             return new JsonResponse(['status' => 'ok''path' => $path]);
  195.         }
  196.         return new JsonResponse(['status' => 'ko''error' => 'Not xmlhttp']);
  197.     }
  198.     /**
  199.      * @Route("/save-offer-session", name="save_offer_session")
  200.      */
  201.     public function saveOfferSession(Request $requestSessionInterface $sessionSearchParameterChecker $checker)
  202.     {
  203.         // get search parameters from homepage, check it, put it in session, and redirect to search page
  204.         if ($request->isXmlHttpRequest() && isset($request->request))
  205.         {
  206.             $offerId $request->request->get('offerId');
  207.             // lazy & ugly solution, doesn't mind
  208.             $login_route $request->request->get('login_route_plz') ?? false;
  209.             $path $this->generateUrl('login');
  210.             $session->set('offerId'$offerId);
  211.             return new JsonResponse(['status' => 'ok''path' => $path'offerId' => $offerId]);
  212.         }
  213.         return new JsonResponse(['status' => 'ko''error' => 'Not xmlhttp']);
  214.     }
  215.     /**
  216.      * @Route("/set_favorite_offer", name="set_favorite_offer")
  217.      */
  218.     public function        setFavoriteOffer(Request $requestEntityManagerInterface $managerFavoriteOfferRepository $repo)
  219.     {
  220.         if ($request->isXmlHttpRequest() && isset($request->request))
  221.         {
  222.             // get data
  223.             $userId $request->get('userId');
  224.             $offerId $request->get('offerId');
  225.             $tenant $this->getDoctrine()->getRepository(User::class)->find($userId);
  226.             if ($tenant == null || $offerId == null)
  227.                 return new JsonResponse(['status' => 'ko''error' => 'Impossible de trouver cette offre ou cet utilisateur avec les informations spécifiées.']);
  228.             $favorite $repo->findOneBy(['offerId' => $offerId'userId' => $userId]);
  229.             if ($favorite == null)
  230.                 $manager->persist(new FavoriteOffer($offerId$userId));
  231.             else
  232.                 $manager->remove($favorite);
  233.             $manager->flush();
  234.             // return users, please let me die a week or two
  235.             return new JsonResponse(['status' => 'ok']);
  236.             // go and take urself something to eat in the kitchen. A fruit, ffs, stop the sugar
  237.         }
  238.         return new JsonResponse(['error' => 'Not xmlhttp']);
  239.     }
  240.     /**
  241.      * @Route("/get-search-results", name="get_search_results")
  242.      */
  243.     public function getSearchResults(Request $requestEntityManagerInterface $managerOfferRepository $repoSessionInterface $sessionSearchParameterChecker $checkerEnumValuesRepository $enumrepo)
  244.     {
  245.         $enumRepo $this->getDoctrine()->getRepository(EnumValues::class);
  246.         $buildingType $enumRepo->findOneBy(['name' => 'buildingType'])->getData();
  247.         $offerRepo $this->getDoctrine()->getRepository(Offer::class);
  248.         if ($request->isXmlHttpRequest() && isset($request->request))
  249.         {
  250.             $search $request->request->get('searchParameters');
  251.             $parameters $checker->checkParameters($search);
  252.             $nbrRoom $enumrepo->findOneBy(['name' => 'nbrRooms'])->getData();
  253.             $constructionType $enumrepo->findOneBy(['name' => 'constructionType'])->getData();
  254.             $user $this->getUser();
  255.             // if search is empty, it's cool, we just dump everything we got
  256.             if (empty($parameters))
  257.             {
  258.                 $results $offerRepo->searchFrontSide(nullFALSE$user $user->getId() : null);
  259.                 $html $this->renderView('partials/search/_search_results_container.html.twig', [
  260.                     'buildingType'            => $this->buildingType,
  261.                     'constructionType'        => $this->constructionType,
  262.                     'buildingTypeParameter'    => null,
  263.                     'departments'            => null,
  264.                     'price'                    => null,
  265.                     'surface'                => null,
  266.                     'nbrRooms'                => null,
  267.                     'results'                => $results,
  268.                     'nbrRoom'                => $this->nbrRooms,
  269.                 ]);
  270.                 return new JsonResponse(['status' => 'ok''html' => $html]);
  271.             }
  272.             $results $offerRepo->searchFrontSide($parametersFALSE$user $user->getId() : null);
  273.             $html $this->renderView('partials/search/_search_results_container.html.twig', [
  274.                 'buildingType'            => $this->buildingType,
  275.                 'constructionType'        => $this->constructionType,
  276.                 'buildingTypeParameter'    => $parameters['buildingType'] ?? null,
  277.                 'departments'            => $parameters['departments'] ?? null,
  278.                 'price'                    => $parameters['price'] ?? null,
  279.                 'surface'                => $parameters['surface'] ?? null,
  280.                 'nbrRooms'                => $parameters['nbrRooms'] ?? null,
  281.                 'results'                => $results ?? [],
  282.                 'nbrRoom'                => $this->nbrRooms,
  283.             ]);
  284.             return new JsonResponse(['status' => 'ok''html' => $html'dump' => $results'data' => $parameters]);
  285.         }
  286.         return new JsonResponse(['status' => 'ko''error' => 'Not xmlhttp']);
  287.     }
  288.     /**
  289.      * @Route("/inscription", name="register")
  290.      */
  291.     public function register(Request $requestEntityManagerInterface $managerUserPasswordEncoderInterface $encoderGuardAuthenticatorHandler $guardHandlerLoginFormAuthenticator $authenticatorCustomMailer $mailerSecurizer $securizerUserRepository $repo)
  292.     {
  293.         $user $this->getUser();
  294.         if ($user != null && $securizer->isGranted($user'ROLE_LANDLORD'))
  295.             return $this->redirectToRoute('landlord_profile', ['id' => $user->getId()]);
  296.         else if ($user != null && $securizer->isGranted($user'ROLE_TENANT'))
  297.             return $this->redirectToRoute('tenant_profile', ['id' => $user->getId()]);
  298.         else if ($user != null && $securizer->isGranted($user'ROLE_ADMIN'))
  299.             return $this->redirectToRoute('admin_home');
  300.         /*else if ($user != null && $user->isGranted('ROLE_TENANT'))
  301.             return $this->redirectToRoute('tenant_profile', ['id' => $user->getId()]);*/
  302.         $user = new User();
  303.         $formFactory $this->get('form.factory');
  304.         $form $this->createForm(RegisterFormType::class, $user);
  305.         $form->handleRequest($request);
  306.         if ($form->isSubmitted() && $form->isValid())
  307.         {
  308.             //$isTenant flag utilisé pour conditionner l'envoie de mail d'activation
  309.             $isTenant false;
  310.             $role $form->get('roles')->getData() ? array('ROLE_TENANT') : array('ROLE_LANDLORD');
  311.             $user->setRoles($role);
  312.             // if user is Tenant, he must give additional data
  313.             if ($form->get('roles')->getData())
  314.             {
  315.                 $user->setWorkStatus(new WorkStatus());
  316.                 $user->setGuarantor(new Guarantor());
  317.                 //Activation du compte du locataire
  318.                 $user->setActivated(true);
  319.                 $isTenant true;
  320.             }
  321.             $hash $encoder->encodePassword($user$user->getPassword());
  322.             $user->setPassword($hash);
  323.             $manager->persist($user);
  324.             $manager->flush();
  325.             //sending activation mail
  326.             $email $user->getEmail();
  327.             $id $user->getId();
  328.             $d = new \DateTime();
  329.             $hash md5($email.$d->format('Y-m-d\TH:i:s.u'));
  330.             $newActChk = new MD5HashCheck($id$hash);
  331.             $manager->persist($newActChk);
  332.             while ($repo->findOneBy(['token' => $hash]) != null)
  333.             {
  334.                 $d = new \DateTime();
  335.                 $hash md5($email.$d->format('Y-m-d\TH:i:s.u'));
  336.             }
  337.             $user->setToken($hash);
  338.             $manager->persist($user);
  339.             $manager->persist(new Availabilities($user->getId(), []));
  340.             $manager->flush();
  341.             // sending mail only for landlord
  342.             $messageFlash="Compte créé avec succès ! ";
  343.             if (!$isTenant){
  344.                 $mailer->sendActivationLink($hash$id$email);
  345.                 $messageFlash .= "Un email d'activation vous a été envoyé sur $email !";
  346.             }
  347.             $this->addFlash('success'$messageFlash);
  348.             // auto login after register success
  349.             return $guardHandler->authenticateUserAndHandleSuccess($user$request$authenticator'main');
  350.         }
  351.         return $this->render('register.html.twig', [
  352.             'controller_name'    => 'BaseController',
  353.             'form'                => $form->createView(),
  354.         ]);
  355.     }
  356.     /**
  357.      * @Route("/changement-de-mot-de-passe/id={id}", name="update_password")
  358.      */
  359.     public function updatePassword(User $user nullRequest $requestEntityManagerInterface $managerUserPasswordEncoderInterface $encoderSecurizer $securizer)
  360.     {
  361.         if ($user == null)
  362.             return $this->redirectToRoute('homepage');
  363.         // see App\Security\Voter\CheckMethodsAccessVoter
  364.         $this->denyAccessUnlessGranted('OWNER_OR_ADMIN'$user);
  365.         $logged $this->getUser();
  366.         // if we're trying to modify an admin password that is NOT our account and we are NOT super_admin, we fuck off
  367.         if ($securizer->isGranted($user'ROLE_ADMIN') && $securizer->isGranted($logged'ROLE_ADMIN_MASTER') && $user->getId() != $logged->getId())
  368.         {
  369.             $this->addFlash('danger''Vous n\'avez pas l\'autorité nécessaire pour cette opération !');
  370.             return $this->redirectToRoute('admin_homepage');
  371.         }
  372.         $form $this->createForm(UpdatePasswordType::class, null);
  373.         $form->handleRequest($request); 
  374.         $redirectPath null;
  375.         $success true;
  376.         if ($form->isSubmitted() && $form->isValid())
  377.         {
  378.             // if the old password is not valid, we create an error on this field and f*** off
  379.             if (!$encoder->isPasswordValid($user$form['oldPassword']->getData()))
  380.             {
  381.                 $form['oldPassword']->addError(new FormError('Mot de passe incorrect.'));
  382.                 $success false;
  383.             }
  384.             $password $form['newPassword']->getData();
  385.             if (strcmp($password$form['oldPassword']->getData()) == 0)
  386.             {
  387.                 $form['newPassword']->addError(new FormError('Le nouveau mot de passe ne peut pas être identique à l\'ancien.'));
  388.                 $success false;
  389.             }
  390.             // password must contain lowercase, uppercase and number
  391.             if (!preg_match('@[A-Z]@'$password) || !preg_match('@[a-z]@'$password) || !preg_match('@[0-9]@'$password) || strlen($password) < 10)
  392.             {
  393.                 $form['newPassword']->addError(new FormError('Le mot de passe doit avoir au minimum 10 caractères et contenir au moins une minuscule, une majuscule et un chiffre.'));
  394.                 $success false;
  395.             }
  396.             if ($success)
  397.             {
  398.                 $newPassword $encoder->encodePassword($user$password);
  399.                 $user->setPassword($newPassword);
  400.                 $manager->persist($user);
  401.                 $manager->flush();
  402.             }
  403.             $this->addFlash('success''Votre mot de passe a été modifié.');
  404.             if ($securizer->isGranted($user'ROLE_LANDLORD'))
  405.                 $redirectPath 'landlord_profile';
  406.             else if ($securizer->isGranted($user'ROLE_TENANT'))
  407.                 $redirectPath 'tenant_profile';
  408.             else if ($securizer->isGranted($user'ROLE_ADMIN'))
  409.                 $redirectPath 'admin_homepage';
  410.         }
  411.         if ($success == true && $redirectPath != null)
  412.             return $this->redirectToRoute($redirectPath, ['id' => $user->getId()]);
  413.         return $this->render('update_password.html.twig', [
  414.             'form'                => $form->createView(),
  415.             'userId'            => $user->getId(),
  416.             'user'                => $user,
  417.         ]);
  418.     }
  419.     /**
  420.      * @Route("/changement-de-mot-de-passe/key={hash}", name="reset_password")
  421.      * @ParamConverter("key", options={"mapping"={"hash"="hash"}})
  422.      */
  423.     public function resetPassword(MD5HashCheck $key nullRequest $requestEntityManagerInterface $managerUserPasswordEncoderInterface $encoderUserRepository $repo)
  424.     {
  425.         $date = new \Datetime();
  426.         // key must exists, be 7 days old MAX and user must exists
  427.         if ($key == null || date_diff($key->getCreationDate(), $date)->format('d') > || ($user $repo->findOneBy(['id' => $key->getUserId()])) == null)
  428.         {
  429.             $this->addFlash('danger''Cet lien n\'est plus valide (plus de sept jours).');
  430.             return $this->$this->redirectToRoute('homepage');
  431.         }
  432.         // todo create a form with repetedtype, check it, hash it, update user, done
  433.         $form $this->createForm(UpdatePasswordType::class, null, ['reset' => true]);
  434.         $form->handleRequest($request);
  435.         $redirectPath null;
  436.         if ($form->isSubmitted() && $form->isValid())
  437.         {
  438.             $password $form['newPassword']->getData();
  439.             // password must contain lowercase, uppercase and number
  440.             //if (!preg_match('@[A-Z]@', $password) || !preg_match('@[a-z]@', $password) || !preg_match('@[0-9]@', $password) || strlen($password) < 10)
  441.             if (strlen($password) < 10)
  442.             {
  443.                 $form['newPassword']->addError(new FormError('Le mot de passe doit avoir au minimum 10 caractères.'));
  444.                 return $this->render('reset_password.html.twig', ['form' => $form->createView()]);
  445.             }
  446.             $newPassword $encoder->encodePassword($user$password);
  447.             $user->setPassword($newPassword);
  448.             $manager->persist($user);
  449.             $manager->flush();
  450.             $this->addFlash('success''Votre mot de passe a été modifié.');
  451.             $redirectPath 'login';
  452.         }
  453.         if ($redirectPath != null)
  454.             return $this->redirectToRoute($redirectPath);
  455.         return $this->render('reset_password.html.twig', [
  456.             'form'                => $form->createView()
  457.         ]);
  458.     }
  459.     /**
  460.      * @Route("/demande-changement-mot-de-passe", name="reset_password_request")
  461.      */
  462.     public function sendResetPasswordMail(Request $requestUserRepository $repoEntityManagerInterface $managerCustomMailer $mailer)
  463.     {
  464.         $form $this->createFormBuilder()
  465.             ->add('email'EmailType::class, [
  466.                 'label'                => 'Renseignez votre adresse email',
  467.                 'constraints'            => [
  468.                     new NotBlank([
  469.                         'message'        => "Veuillez renseigner votre email."
  470.                     ]),
  471.                     new Email([
  472.                         'mode'            => 'html5',
  473.                         'message'        => "L'email {{ value }} n'est pas un email valide.",
  474.                     ]),
  475.                 ],
  476.                 'required'            => true,
  477.                 'attr'                => array('placeholder' => 'Adresse email*'),
  478.             ])
  479.             ->getForm();
  480.         $success false;
  481.         $form->handleRequest($request);
  482.         if ($form->isSubmitted() && $form->isValid())
  483.         {
  484.             $email $form['email']->getData();
  485.             // wether or not the email was in our database, we send a happy message to fool our enemies.
  486.             $success true;
  487.             $this->addFlash('success''Un email de réinitialisation vous a été envoyé sur '.$email.' !');
  488.             // password must contain lowercase, uppercase and number
  489.             if (($user $repo->findOneBy(['email' => $email])) != null)
  490.             {
  491.                 $d = new \DateTime();
  492.                 $hash md5($email.$d->format('Y-m-d\TH:i:s.u'));
  493.                 $newActChk = new MD5HashCheck($user->getId(), $hash);
  494.                 $manager->persist($newActChk);
  495.                 $manager->flush();
  496.                 // sending mail
  497.                 //$mail = new CustomMailer($mailer, $this->get('twig'));
  498.                 $mailer->sendResetPasswordLink($hash$email);
  499.             }
  500.         }
  501.         if ($success)
  502.             return $this->redirectToRoute('login');
  503.         return $this->render('email_form.html.twig', [
  504.             'form'                => $form->createView(),
  505.         ]);
  506.     }
  507.     /**
  508.      * @Route("/demande_activation/id={id}", name="activation_request")
  509.      */
  510.     public function sendActivationMail(User $user nullEntityManagerInterface $managerCustomMailer $mailerSecurizer $securizer)
  511.     {
  512.         if ($user == null)
  513.             return $this->redirectToRoute('homepage');
  514.         // see App\Security\Voter\CheckMethodsAccessVoter
  515.         $this->denyAccessUnlessGranted('OWNER_OR_ADMIN'$user);
  516.         $id $user->getId();
  517.         $email $user->getEmail();
  518.         $d = new \DateTime();
  519.         $hash md5($email.$d->format('Y-m-d\TH:i:s.u'));
  520.         $newActChk = new MD5HashCheck($id$hash);
  521.         $manager->persist($newActChk);
  522.         $manager->flush();
  523.         // sending mail
  524.         $mailer->sendActivationLink($hash$id$email);
  525.         $this->addFlash('success''Un email d\'activation vous a été envoyé sur '.$email.' !');
  526.         if ($securizer->isGranted($user'ROLE_LANDLORD'))
  527.             return $this->redirectToRoute('landlord_profile', ['id' => $user->getId()]);
  528.         return $this->redirectToRoute('tenant_profile', ['id' => $user->getId()]);
  529.     }
  530.     /**
  531.      * @Route("/activation/key={hash}", name="activate_user")
  532.      * @ParamConverter("activationKey", options={"mapping"={"hash"="hash"}})
  533.      */
  534.     public function activateUser(MD5HashCheck $activationKey nullEntityManagerInterface $manager)
  535.     {
  536.         if ($activationKey == null)
  537.         {
  538.             $this->addFlash('danger''Cette clef n\'est pas valide.');
  539.             return $this->$this->redirectToRoute('homepage');
  540.         }
  541.         $user $this->getDoctrine()->getRepository(User::class)->findOneById($activationKey->getUserId());
  542.         if ($user != null && $user->getActivated() != true)
  543.         {
  544.             $user->setActivated(true);
  545.             $manager->persist($user);
  546.             $manager->flush();
  547.             $this->addFlash('success''Votre profil a été activé !');
  548.         }
  549.         return $this->redirectToRoute('login');
  550.     }
  551.     /**
  552.      * @Route("/annonce/{slug}", name="view_offer_profile")
  553.      */
  554.     public function viewOfferProfile(Offer $offer nullEntityManagerInterface $managerUserRepository $urepoOfferRepository $orepoSessionInterface $sessionEnumValuesRepository $erepoFavoriteOfferRepository $fAgencyRepository $arepo)
  555.     {
  556.         if ($offer == null || $offer->getIsPublished() == false)
  557.         {
  558.             $this->addFlash('danger''Cette annonce n\'est plus disponible !');
  559.             return $this->redirectToRoute('homepage');
  560.         }
  561.         if ($session->has('offerId'))
  562.             $session->remove('offerId');
  563.         $nearest $orepo->getNearest($offer->getDepartment(), $offer->getId());
  564.         $agency $arepo->find($offer->getAgency());
  565.         $contractType $erepo->findOneBy(['name' => 'contractType'])->getData();
  566.         $buildingType $erepo->findOneBy(['name' => 'buildingType'])->getData();
  567.         $nbrRooms $erepo->findOneBy(['name' => 'nbrRooms'])->getData();
  568.         $energyRating $erepo->findOneBy(['name' => 'energyRating'])->getData();
  569.         $parkingType $erepo->findOneBy(['name' => 'parkingType'])->getData();
  570.         $kitchenType $erepo->findOneBy(['name' => 'kitchenType'])->getData();
  571.         $constructionType $erepo->findOneBy(['name' => 'constructionType'])->getData();
  572.         $logged $this->getUser();
  573.         $saved $logged $f->findOneBy(['userId' => $logged->getId(), 'offerId' => $offer->getId()]) ? true false false;
  574.         return $this->render('base/view_offer_profile.html.twig', [
  575.                 'offer'                => $offer,
  576.                 'nearest'            => $nearest,
  577.                 'contractType'        => $contractType,
  578.                 'buildingType'        => $this->buildingType,
  579.                 'nbrRooms'            => $this->nbrRooms,
  580.                 'energyRating'        => $energyRating,
  581.                 'parkingType'        => $this->parkingType,
  582.                 'kitchenType'        => $kitchenType,
  583.                 'constructionType'    => $this->constructionType,
  584.                 'saved'                => $saved,
  585.                 'agency'            => $agency,
  586.             ]
  587.         );
  588.     }
  589.     /**
  590.      * @Route("/visite/{md5slug}/{landlordId}", name="view_offer_profile_visit")
  591.      * @ParamConverter("landlord", options={"mapping"={"landlordId"="id"}})
  592.      */
  593.     public function viewOfferProfileVisit(Offer $offer nullUser $landlord nullEntityManagerInterface $managerUserRepository $urepoOfferRepository $orepoEnumValuesRepository $erepoAgencyRepository $arepo)
  594.     {
  595.         if ($offer == null || $offer->getIsPublished() == false)
  596.         {
  597.             $this->addFlash('danger''Cette annonce n\'est plus disponible !');
  598.             return $this->redirectToRoute('homepage');
  599.         }
  600.         if ($landlord != null && $landlord->getId() !== $offer->getUser()->getId())
  601.         {
  602.             $landlord null;
  603.         }
  604.         $agency $arepo->find($offer->getAgency());
  605.         $nearest $orepo->getNearest($offer->getDepartment(), $offer->getId());
  606.         $contractType $erepo->findOneBy(['name' => 'contractType'])->getData();
  607.         $buildingType $erepo->findOneBy(['name' => 'buildingType'])->getData();
  608.         $nbrRooms $erepo->findOneBy(['name' => 'nbrRooms'])->getData();
  609.         $energyRating $erepo->findOneBy(['name' => 'energyRating'])->getData();
  610.         $parkingType $erepo->findOneBy(['name' => 'parkingType'])->getData();
  611.         $kitchenType $erepo->findOneBy(['name' => 'kitchenType'])->getData();
  612.         $constructionType $erepo->findOneBy(['name' => 'constructionType'])->getData();
  613.         return $this->render('base/view_offer_profile_visit.html.twig', [
  614.                 'agency'            => $agency,
  615.                 'offer'                => $offer,
  616.                 'nearest'            => $nearest,
  617.                 'contractType'        => $contractType,
  618.                 'buildingType'        => $this->buildingType,
  619.                 'nbrRooms'            => $this->nbrRooms,
  620.                 'energyRating'        => $energyRating,
  621.                 'parkingType'        => $this->parkingType,
  622.                 'kitchenType'        => $kitchenType,
  623.                 'constructionType'    => $this->constructionType,
  624.                 'landlord'            => $landlord,
  625.             ]
  626.         );
  627.     }
  628.     /**
  629.      * @Route("/page/{pageSlug}", name="page_display")
  630.      * @ParamConverter("page", options={"mapping"={"pageSlug"="slug"}})
  631.      */
  632.     public function pageDisplay(Page $page null)
  633.     {
  634.         if ($page == null)
  635.             throw $this->createNotFoundException('Cette page n\'existe pas.');
  636.         if ($page->getStatus() != && !$this->isGranted('ROLE_ADMIN'))
  637.             return $this->redirectToRoute('homepage');
  638.         return $this->render($page->getTemplate().'.html.twig', [
  639.             'page'                => $page,
  640.             'metadescription'    => $page->getMetadescription(),
  641.             'title'                => $page->getTitle(),
  642.         ]);
  643.     }
  644.     function checkArray($array)
  645.     {
  646.         foreach($array as $value)
  647.         {
  648.             if(!is_int($value))
  649.                 return false;
  650.         }
  651.         return true;
  652.     }
  653.     /**
  654.      * @Route("/create-mailing", name="create_mailing")
  655.      */
  656.     public function createMailing(Request $requestEntityManagerInterface $managerUserRepository $uMailingSearchRepository $mSessionInterface $sessionSearchParameterChecker $checkerSecurizer $securizer)
  657.     {
  658.         if ($request->isXmlHttpRequest() && isset($request->request))
  659.         {
  660.             // get data
  661.             // check data
  662.             $search $request->request->get('searchParameters');
  663.             $parameters $checker->checkParameters($search);
  664.             $session->set('searchParameters'$parameters);
  665.             $user $this->getUser();
  666.             if ($user == null || !$securizer->isGranted($user'ROLE_TENANT'))
  667.             {
  668.                 return new JsonResponse(['status' => 'ko''error' => 'login']);
  669.             }
  670.             $mailing = new MailingSearch();
  671.             $contractType    $parameters['contractType'];
  672.             $surface        $parameters['surface'];
  673.             $price            $parameters['price'];
  674.             $buildingType    $parameters['buildingType'] ?? null;
  675.             $nbrRooms        array_filter($parameters['nbrRooms'] ?? []);
  676.             $departments    $parameters['departments'] ?? null;
  677.             if (!empty($contractType) && is_int($contractType)) {
  678.                 $mailing->setContractType($contractType);
  679.             }
  680.             if (!empty($price) && is_int($price)) {
  681.                 $mailing->setPrice($price);
  682.             }
  683.             if (!empty($surface) && is_int($surface)) {
  684.                 $mailing->setSurface($surface);
  685.             }
  686.             if (!empty($departments) && $this->checkArray($departments)) {
  687.                 $mailing->setDepartments($departments);
  688.             }
  689.             if (!empty($nbrRooms) && $this->checkArray($nbrRooms)) {
  690.                 $mailing->setNbrRooms($nbrRooms);
  691.             }
  692.             if (!empty($buildingType) && $this->checkArray($buildingType)) {
  693.                 $mailing->setBuildingType($buildingType);
  694.             }
  695.             try {
  696.                 $user->addMailing($mailing);
  697.                 $manager->persist($user);
  698.                 $manager->flush();
  699.             } catch (DBALException $e) {
  700.                 return new JsonResponse(['status' => 'ko''error' => 'duplicate']);
  701.             }
  702.             return new JsonResponse(['status' => 'ok']);
  703.         }
  704.         return new JsonResponse(['status' => 'ko''error' => 'Not xmlhttp']);
  705.     }
  706.     /**
  707.      * @Route("/ajax-sign-conv/{id}", name="ajax_sign_conv")
  708.      */
  709.     public function ajaxSignConvention(Offer $offerSignConvention $signConventionServiceRequest $request)
  710.     {
  711.         if ($offer == null){
  712.             $this->addFlash('danger'"Cette annonce n'est plus disponible");
  713.             return $this->redirectToRoute('homepage');
  714.         }
  715.         $retour $signConventionService->signConvention($offer$request);
  716.         if (count($retour['erreur_bloquante']) > 0){
  717.             return $this->json(['status' => 'missingInfo2''errors' => $retour['erreur_bloquante']]);
  718.         }
  719.         if(isset($retour['errors']) && count($retour['errors'])>0){
  720.             foreach ($retour['errors'] as $error){
  721.                 $this->addFlash($error['type'], $error['message']);
  722.             }
  723.         }
  724.         if($retour['status'] == 'success'){
  725.             $this->addFlash('success''Merci beaucoup 👍, vous venez de valider la convention de votre annonce avec succès 🎉 Nous allons des à présent, proposer votre bien à nos candidats et nous reviendrons vers vous pour l’organisation des visites');
  726.             $redirectUrl $this->generateUrl('homepage', ['congratulations' => true]);
  727.             return $this->json(['status' => 'success''redirectUrl' => $redirectUrl]);
  728.         }else{
  729.             return $this->json(['status' => 'error''redirectUrl'=>$this->generateUrl('homepage')]);
  730.         }
  731.     }
  732.     private function getMask(array $strings):array
  733.     {
  734.         //mask de l'adresse email
  735.         list($nom$domaineComplet) = explode('@'$strings['email']);
  736.         $nomVisible substr($nom02);
  737.         $nomMasque str_repeat('*'max(1strlen($nom) - 2));
  738.         $lastDotPos strrpos($domaineComplet'.');
  739.         if ($lastDotPos === false) {
  740.             // Pas d'extension : on masque tout
  741.             $domaineMasque str_repeat('*'strlen($domaineComplet));
  742.             $extension '';
  743.         } else {
  744.             $extension substr($domaineComplet$lastDotPos); // ex: ".fr"
  745.             $domaineMasque str_repeat('*'$lastDotPos);     // masque tout avant le ".fr"
  746.         }
  747.         $retour['email']=$nomVisible $nomMasque '@' $domaineMasque $extension;
  748.         //Mask du numéro de téléphone
  749.         $longueur strlen($strings['phone']);
  750.         $subLength = ($strings['phone'][0]==='+')?4:2;
  751.         $debut substr($strings['phone'], 0$subLength);
  752.         $fin substr($strings['phone'], -2);
  753.         $masque str_repeat('*'$longueur - (2+$subLength));
  754.         $retour['phone']=$debut $masque $fin;
  755.         return $retour;
  756.     }
  757.     /**
  758.      * @Route("/confirm/{action}/{hash}", name="confir_user", requirements={"action":"sign|del", "key": "[A-Za-z0-9]+"})
  759.      */
  760.     public function confirmUser($action$hashEntityManagerInterface $emRequest $requestSessionInterface $session):Response
  761.     {
  762.         $tentative $session->get('tentative'0);
  763.         if($tentative >=3){
  764.             $params = ['action'=>$action'hash'=>$hash'ERROR'=>1];
  765.             return  $this->render('base/confirm_user.html.twig'$params);
  766.         }
  767.         if($hash == null){
  768.             $this->addFlash('danger'"⛔ Lien erroné, absence de hash !");
  769.             return $this->redirectToRoute('homepage');
  770.         }
  771.         //Vérification si le lien provient du mail ou de SMS
  772.         $origineLien substr($hash, -1);
  773.         $hash substr($hash0, -1);
  774.         $hashCheck $em->getRepository(MD5HashCheck::class)->findOneBy(['hash' => $hash]);
  775.         if($hashCheck == null){
  776.             $this->addFlash('danger'"⛔ Cette hash n'existe pas");
  777.             return $this->redirectToRoute('homepage');
  778.         }
  779.         $offerId $hashCheck->getUserId();
  780.         if($offerId == null){
  781.             $this->addFlash('danger'"⛔ Cette annonce n'est plus disponible");
  782.             return $this->redirectToRoute('homepage');
  783.         }
  784.         $user $em->getRepository(Offer::class)->findOneBy(['id' => $offerId])->getUser();
  785.         $userMail $user->getEmail();
  786.         $userPhone $user->getPhone();
  787.         $masques $this->getMask(['email' => $userMail'phone' => $userPhone]);
  788.         $params =['offerId'=> $offerId'action'=>$action'hash'=>$hash'ERROR'=>'''origineLien'=>$origineLien];
  789.         if($origineLien == 'M'){
  790.             //Le lien provient d'un mail
  791.             $params ['masqueMail'] = $masques['email'];
  792.         }elseif ($origineLien == 'S'){
  793.             //Le lien provient d'un SMS
  794.             $params['masquePhone'] = $masques['phone'];
  795.         }
  796.         return $this->render('base/confirm_user.html.twig'array_merge($params, ['ERROR'=>$request->query->get('ERROR''')]));
  797.     }
  798.     /**
  799.      * @Route("/verif-user", name="verif_user")
  800.      */
  801.     public function verifUser(Request $requestEntityManagerInterface $emSessionInterface  $sessionPhoneNumberHelper $helper):Response
  802.     {
  803.         if($request->isMethod('POST')){
  804.             //récupération de la valeur saisie par l'utilisateur
  805.             $hash $request->request->get('hash'false);
  806.             $offerId $request->request->get('offerId'false);
  807.             $action $request->request->get('action'false);
  808.             $origineLien $request->request->get('origineLien'false);
  809.             //récupération de la valeur saisie par l'utilisateur
  810.             $email $request->request->get('email'false);
  811.             $tel $helper->normalizePhoneToE164($request->request->get('tel'false));
  812.             if(!$hash || !$offerId || !$action || !$origineLien || (!$email && !$tel)){
  813.                 $this->addFlash('danger''⛔ Accès refusé');
  814.                 return $this->redirectToRoute('homepage');
  815.             }
  816.             $user $em->getRepository(Offer::class)->findOneBy(['id' => $offerId])->getUser();
  817.             $userMail $user->getEmail();
  818.             $userPhone $helper->normalizePhoneToE164($user->getPhone());
  819.             $verifError false;
  820.             if($email && $email !== $userMail){
  821.                 $this->addFlash('danger'"⛔ L'adresse email saisie ne correspond pas à l'adresse email attendue !");
  822.                 $verifError true;
  823.             }elseif ($tel && $tel !== $userPhone){
  824.                 $this->addFlash('danger''⛔ Le numéro saisi ne correspond pas au numéro de téléphone attendu');
  825.                 $verifError true;
  826.             }
  827.             $tentative $session->get('tentative'0);
  828.             if ($verifError){
  829.                 $tentative++;
  830.                 $session->set('tentative'$tentative);
  831.                 $params = ['action'=>$action'hash'=>$hash.$origineLien];
  832.                 return  $this->redirectToRoute('confir_user'$params);
  833.             }
  834.             switch ($action) {
  835.                 case 'del':
  836.                     return $this->redirectToRoute('del_conv', ['hash' => $hash]);
  837.                     break;
  838.                 case 'sign':
  839.                     return $this->redirectToRoute('sign_offer', ['hash'=>$hash]);
  840.                     break;
  841.                 default:
  842.                     $this->addFlash('danger''⛔ Accès refusé');
  843.                     return $this->redirectToRoute('homepage');
  844.             }
  845.         }
  846.         $this->addFlash('danger''⛔ Accès refusé');
  847.         return $this->redirectToRoute('homepage');
  848.     }
  849.     /**
  850.      * @Route("/del_conv/key={hash}", name="del_conv")
  851.      */
  852.     public function delConvention($hashEntityManagerInterface $emOfferTenantApplicationRepository $offerTenantApplicationRepo)
  853.     {
  854.         if ($hash == null)
  855.         {
  856.             $this->addFlash('danger''Pas de hash.');
  857.             return $this->redirectToRoute('homepage');
  858.         }
  859.         $hashCheck $em->getRepository(MD5HashCheck::class)->findOneBy(['hash' => $hash]);
  860.         if ($hashCheck == null){
  861.             $this->addFlash('danger''Pas de hash.');
  862.             return $this->redirectToRoute('homepage');
  863.         }
  864.         $offer $em->getRepository(Offer::class)->find($hashCheck->getUserId());
  865.         if ($offer == null || $offer->getIsSigned()){
  866.             $this->addFlash('danger'"Cette offre n'est plus disponible ou elle est déjà signée");
  867.             return $this->redirectToRoute('homepage');
  868.         }
  869.         $offer->setIsPublished(0);
  870.         $offer->setStatus(3);
  871.         $offerTenantApplicationRepo->disableAllOfferApplications($offer->getId());
  872.         $em->persist($offer);
  873.         $em->flush();
  874.         $this->addFlash('success'"🗑️ L'offre a bien été supprimée");
  875.         return $this->redirectToRoute('homepage');
  876.     }
  877.     /**
  878.      * @Route("/sign_conv/key={hash}", name="sign_offer")
  879.      */
  880.     public function signConvention($hashRequest $requestEnumValuesRepository $valuesRepoFormLabelHydrater $hydraterSessionInterface $session)
  881.     {
  882.         // I had a perfectly working nice method, but no, I had to change it because the client is king.
  883.         if ($hash == null)
  884.         {
  885.             $this->addFlash('danger''Pas de hash.');
  886.             return $this->redirectToRoute('homepage');
  887.         }
  888.         $offerId $this->getDoctrine()->getRepository(MD5HashCheck::class)->findOneBy(['hash' => $hash]);
  889.         if ($offerId == null)
  890.         {
  891.             $this->addFlash('danger''Pas de id.');
  892.             return $this->redirectToRoute('homepage');
  893.         }
  894.         $offer $this->getDoctrine()->getRepository(Offer::class)->find($offerId->getUserId());
  895.         // if offer is already signed, what the hell are you doing here?
  896.         if ($offer == null )
  897.         {
  898.             $this->addFlash('danger'"⛔ L'accès a cette offre n'est plus disponible, pour plus d'information contacter l'agence");
  899.             return $this->redirectToRoute('homepage');
  900.         }
  901.         if($offer->getIsSigned() == true){
  902.             $this->addFlash('danger'"⛔ L'accès a cette offre n'est plus disponible. L'offre a déjà été validé. Pour plus d'information contacter l'agence");
  903.             return $this->redirectToRoute('homepage');
  904.         }
  905.         //Si l'offre est supprimée status = 3
  906.         if($offer->getStatus() == 3){
  907.             $this->addFlash('danger'"⛔ L'accès a cette offre n'est plus disponible. L'offre a déjà été supprimée. Pour plus d'information contacter l'agence");
  908.             return $this->redirectToRoute('homepage');
  909.         }
  910.         if($offer->getIsPublished() == true){
  911.             $this->addFlash('danger'"⛔ L'accès a cette offre n'est plus disponible. L'offre a déjà été publiée. Pour plus d'information contacter l'agence");
  912.             return $this->redirectToRoute('homepage');
  913.         }
  914.         $user $offer->getUser();
  915.         if ($user == null)
  916.         {
  917.                 $this->addFlash('danger''Impossible de trouver un propriétaire.');
  918.             return $this->redirectToRoute('homepage');
  919.         }
  920.         $values $valuesRepo->findAllEnums();
  921.         $labels $hydrater->getOfferLabels('flip');
  922.         $form $this->createForm(SignConventionType::class, $offer);
  923.         $form->handleRequest($request);
  924.         $session->set('magic_access_offer_id'$offer->getId());
  925.         return $this->render('offer/sign_offer.html.twig', [
  926.                 'form'            => $form->createView(),
  927.                 'formOffer'        => $this->createForm(ModalOfferType::class, $offer)->createView(),
  928.                 'offer'            => $offer,
  929.                 'user'            => $user,
  930.                 'values'        => $values,
  931.                 'labelHydrater' => $hydrater->getOfferLabels('flip'),
  932.                 'offerDetailsLabels' => $hydrater->getOfferDetailsLabels(),
  933.                 'nbrRooms'        => $labels['nbrRooms'],
  934.                 'heatingType'    => $labels['heatingType'],
  935.                 'allowUpdate'   => true,
  936.                 'ajaxSignConventionRoute' => $this->generateUrl('ajax_sign_conv', ['id'=>$offer->getId(),'hash'=> $hash]),
  937.             ]
  938.         );
  939.     }
  940.     /**
  941.      * @Route("/ajax-edit-landlord-contact", name="ajax_edit_landlord_contact", methods={"POST"})
  942.      */
  943.     public function ajaxEditLandlordContact(Request $requestOfferRepository $repoEntityManagerInterface $em)
  944.     {
  945.         //cas d'accès par lien magique avec le hash
  946.         $session $request->getSession();
  947.         $offer_id $session->get('magic_access_offer_id');
  948.         if(!$offer_id) {
  949.             //cas d'accès par authentification
  950.             $offer_id $request->request->get('offer_id');
  951.         }
  952.         $landLordContactInfo $request->request->get('formOffer');
  953.         $offer $repo->findOneBy(['id' => $offer_id]);
  954.         $form $this->createForm(OfferType::class, $offer);
  955.         // On soumet uniquement les données envoyées sans supprimer les autres champs
  956.         $form->submit($landLordContactInfofalse);
  957.         if ($form->isSubmitted() && $form->isValid()) {
  958.             $em->flush();
  959.             return new JsonResponse(['status' => 'success']);
  960.         }
  961.         $errors = [];
  962.         foreach ($form->getErrors(truefalse) as $error) {
  963.             $errors[] = $error->getMessage();
  964.         }
  965.         return new JsonResponse(['status' => 'error''message' => 'Form not valid''errors' => $errors], 400);
  966.     }
  967.     /**
  968.      * @Route("/partial-offer-contact/{id}", name="partial_offer_contact")
  969.      */
  970.     public function getPartialOfferContact(Offer $offer): Response
  971.     {
  972.         return $this->render('partials/offer/_landlordContact.html.twig', [
  973.             'offer' => $offer,
  974.             'user' => $offer->getUser()
  975.         ]);
  976.     }
  977.     /**
  978.      * @Route("/ajax-edit-offer-description", name="ajax_edit_offer_description", methods={"POST"})
  979.      */
  980.     public function ajaxEditOfferDescription(Request $requestOfferRepository $repoEntityManagerInterface $em)
  981.     {
  982.         $offer_id $request->request->get('offer_id');
  983.         $offerDescription $request->request->get('formOffer');
  984.         $offer $repo->findOneBy(['id' => $offer_id]);
  985.         $form $this->createForm(OfferType::class, $offer);
  986.         $form->submit($offerDescriptionfalse);
  987.         if ($form->isSubmitted() && $form->isValid()) {
  988.             $em->flush();
  989.             return new JsonResponse(['status' => 'success']);
  990.         }
  991.         $errors = [];
  992.         foreach ($form->getErrors(truefalse) as $error) {
  993.             $errors[] = $error->getMessage();
  994.         }
  995.         return new JsonResponse(['status' => 'error''message' => 'Form not valid''errors' => $errors], 400);
  996.     }
  997.     /**
  998.      * @Route("/partial-offer-description/{id}", name="partial_offer_description")
  999.      */
  1000.     public function getPartialOfferDescription(Offer $offerFormLabelHydrater $formLabelHydrater): Response
  1001.     {
  1002.         return $this->render('partials/offer/_description.html.twig', [
  1003.             'offer' => $offer,
  1004.             'labelHydrater' => $formLabelHydrater->getOfferLabels('flip'),
  1005.             'offerDetailsLabels' => $formLabelHydrater->getOfferDetailsLabels(),
  1006.         ]);
  1007.     }
  1008.     /**
  1009.      * @Route("/ajax-edit-offer-address", name="ajax_edit_offer_address", methods={"POST"})
  1010.      */
  1011.     public function ajaxEditOfferAddress(Request $requestOfferRepository $repoEntityManagerInterface $em): JsonResponse
  1012.     {
  1013.         $offer_id $request->request->get('offer_id');
  1014.         $offerAddress $request->request->get('formOffer');
  1015.         $offer $repo->findOneBy(['id' => $offer_id]);
  1016.         $form $this->createForm(OfferType::class, $offer);
  1017.         $form->submit($offerAddressfalse);
  1018.         if ($form->isSubmitted() && $form->isValid()) {
  1019.             $em->flush();
  1020.             return new JsonResponse(['status' => 'success']);
  1021.         }
  1022.         $errors = [];
  1023.         foreach ($form->getErrors(truefalse) as $error) {
  1024.             $errors[] = $error->getMessage();
  1025.         }
  1026.         return new JsonResponse(['status' => 'error''message' => 'Form not valid''errors' => $errors], 400);
  1027.     }
  1028.     /**
  1029.      * @Route("/partial-offer-address/{id}", name="partial_offer_address")
  1030.      */
  1031.     public function getPartialOfferAddress(Offer $offer): Response
  1032.     {
  1033.         return $this->render('partials/offer/_address.html.twig', [
  1034.             'offer' => $offer
  1035.         ]);
  1036.     }
  1037.     /**
  1038.      * @Route("/ajax-edit-offer-price", name="ajax_edit_offer_price", methods={"POST"})
  1039.      */
  1040.     public function ajaxEditOfferPrice(Request $requestOfferRepository $repoEntityManagerInterface $em): JsonResponse
  1041.     {
  1042.         $offer_id $request->request->get('offer_id');
  1043.         $offerPrice $request->request->get('formOffer');
  1044.         $offer $repo->findOneBy(['id' => $offer_id]);
  1045.         $form $this->createForm(OfferType::class, $offer);
  1046.         $form->submit($offerPricefalse);
  1047.         if ($form->isSubmitted() && $form->isValid()) {
  1048.             $em->flush();
  1049.             return new JsonResponse(['status' => 'success']);
  1050.         }
  1051.         $errors = [];
  1052.         foreach ($form->getErrors(truefalse) as $error) {
  1053.             $errors[] = $error->getMessage();
  1054.         }
  1055.         return new JsonResponse(['status' => 'error''message' => 'Form not valid''errors' => $errors], 400);
  1056.     }
  1057.     /**
  1058.      * @Route("/partial-offer-price/{id}", name="partial_offer_price")
  1059.      */
  1060.     public function getPartialOfferPrice(Offer $offer): Response
  1061.     {
  1062.         return $this->render('partials/offer/_price.html.twig', [
  1063.             'offer' => $offer
  1064.         ]);
  1065.     }
  1066.     /**
  1067.      * @Route("/ajax-reset-consumption-emission/{id}", name="ajax_reset_consumption_emission")
  1068.      */
  1069.     public function ajaxResetConsumptionEmission(Offer $offerEntityManagerInterface $emRequest $request):JsonResponse
  1070.     {
  1071.         $resetValue $request->request->get('reset');
  1072.         $offerDetails $offer->getDetails();
  1073.         $offerDetails->setEnergyConsumption($resetValue);
  1074.         $offerDetails->setGhgEmission($resetValue);
  1075.         $em->flush();
  1076.         return new JsonResponse(['status' => 'success']);
  1077.     }
  1078.     /**
  1079.      * @Route("/ajax-update-energy-consumption/{id}", name="ajax_update_energy_consumption")
  1080.      */
  1081.     public function ajaxUpdateEnergyConsumption(Offer $offerRequest $requestEntityManagerInterface $em) : JsonResponse
  1082.     {
  1083.         $offerDetails $offer->getDetails();
  1084.         $offerDetails->setEnergyConsumption($request->request->get('consumption'));
  1085.         $em->flush();
  1086.         return new JsonResponse(['status' => 'success']);
  1087.     }
  1088.     /**
  1089.      * @Route("/ajax-update-emission/{id}", name="ajax_update_emission")
  1090.      */
  1091.     public function ajaxUpdateEmission(Offer $offerRequest $requestEntityManagerInterface $em) : JsonResponse
  1092.     {
  1093.         $offerDetails $offer->getDetails();
  1094.         $offerDetails->setGhgEmission($request->request->get('emission'));
  1095.         $em->flush();
  1096.         return new JsonResponse(['status' => 'success']);
  1097.     }
  1098.     /**
  1099.      * @Route("/offer-image/remove/{id}", name="offer_remove_image", methods={"POST"})
  1100.      */
  1101.     public function ajaxRemoveOfferImage(OfferImage $offerImageFilesystem $filesystemEntityManagerInterface $em):JsonResponse
  1102.     {
  1103.         if (!$offerImage) {
  1104.             return new JsonResponse(['status' => 'error''message' => 'Image not found'], 404);
  1105.         }
  1106.         $filePath $this->getParameter('kernel.project_dir').'/public'.$offerImage->getFullPath();
  1107.         if ($filesystem->exists($filePath)) {
  1108.             $filesystem->remove($filePath);
  1109.         }
  1110.         $em->remove($offerImage);
  1111.         $em->flush();
  1112.         return new JsonResponse(['status' => 'success']);
  1113.     }
  1114.     /**
  1115.      * @Route("/partial-offer-images/{id}", name="partial_offer_images")
  1116.      */
  1117.     public function getPartialOfferPhotos(Offer $offer)
  1118.     {
  1119.         return $this->render('partials/offer/_offerPhotos.html.twig', ['offer'=>$offer'allowUpdate'   => true,]);
  1120.     }
  1121.     /**
  1122.      * @Route("/offer/{id}/upload-image", name="offer_upload_image", methods={"POST"})
  1123.      */
  1124.     public function uploadImage(Request $requestOffer $offerEntityManagerInterface $em)
  1125.     {
  1126.         $uploadedFiles $request->files->get('files');
  1127.         if (!$uploadedFiles) {
  1128.             return new JsonResponse(['status' => 'error''message' =>"Aucun fichier n'a été téléchargé."], 500);
  1129.         }else {
  1130.             //Modification pour avoir le path d'upload sous forme de /offer-images/yyyy/mm/file.extension
  1131.             //préparation du path
  1132.             $publicDirectory $this->getParameter('kernel.project_dir').'/public';
  1133.             $offerImagesDirectory $this->getParameter('offer_images_directory').date('/Y/m');
  1134.             $uploadDirectory $publicDirectory.$offerImagesDirectory;
  1135.             if(!is_dir($uploadDirectory)) {
  1136.                 mkdir($uploadDirectory0777true);
  1137.             }
  1138.             foreach ($uploadedFiles as $file)
  1139.             {
  1140.                 if ($file->isValid()) {
  1141.                     $newFilename uniqid();
  1142.                     $fileExtension $file->guessExtension();
  1143.                     try {
  1144.                         $file->move(
  1145.                             $uploadDirectory,
  1146.                             $newFilename '.' $fileExtension
  1147.                         );
  1148.                         // Créer une nouvelle instance de l'entité OfferImage
  1149.                         $offerImage = new OfferImage();
  1150.                         $offerImage->setFilename($offerImagesDirectory.'/'.$newFilename'.' $fileExtension);
  1151.                         $offerImage->setOffer($offer);
  1152.                         // Enregistre l'entité en base de données
  1153.                         $em->persist($offerImage);
  1154.                         $em->flush();
  1155.                     } catch (FileException $e) {
  1156.                         return new JsonResponse(['status' => 'error''message' => $e->getMessage()], 500);
  1157.                     }
  1158.                 }else {
  1159.                     return new JsonResponse(['status' => 'error''message' => 'Invalid file'], 400);
  1160.                 }
  1161.             }
  1162.         }
  1163.         return new JsonResponse(['status' => 'success']);
  1164.     }
  1165.     /**
  1166.      * @Route("/proprietaire/questionnaire/key={token};app={appId}", name="landlord_quizz")
  1167.      * @ParamConverter("app", options={"mapping"={"appId"="id"}})
  1168.      */
  1169.     public function        landlordQuizz(User $landlord nullOfferTenantApplication $app nullSecurizer $securizerUserRepository $uRepoAgencyRepository $aRepoOfferRepository $oRepoRequest $requestCustomMailer $mailer)
  1170.     {
  1171.         if ($app == null || $landlord == null)
  1172.         {
  1173.             $this->addFlash('danger''Un problème a été rencontré avec cette application, le questionnaire est par conséquent inaccessible.');
  1174.             return $this->redirectToRoute('homepage');
  1175.         }
  1176.         // Create user for login event
  1177.         $token = new UsernamePasswordToken($landlord$landlord->getPassword(), "main"$landlord->getRoles());
  1178.         $this->get("security.token_storage")->setToken($token);
  1179.         // Fire the login event
  1180.         $event = new InteractiveLoginEvent($request$token);
  1181.         $dispatcher = new EventDispatcher();
  1182.         $dispatcher->dispatch($event"security.interactive_login");
  1183.         if ($landlord->getId() != $app->getLandlordId())
  1184.         {
  1185.             $this->addFlash('danger''Vous n\'avez pas le droit d\'accéder à ce questionnaire.');
  1186.             return $this->redirectToRoute('homepage');
  1187.         }
  1188.         $tenant        $uRepo->find($app->getTenantId());
  1189.         $offer        $oRepo->find($app->getOfferId());
  1190.         // check that we have the landlord, the tenant and the offer entities
  1191.         if ($tenant == null || $offer == null)
  1192.         {
  1193.             $this->addFlash('danger''Un problème a été rencontré avec cette application, le questionnaire est par conséquent inaccessible.');
  1194.             return $this->redirectToRoute('homepage');
  1195.         }
  1196.         $form $this->createFormBuilder([])
  1197.             ->add('name'TextType::class, [
  1198.                 'label'                => 'Nom du futur locataire',
  1199.                 'constraints'            => [
  1200.                     new Type('string'),
  1201.                     new NotBlank([
  1202.                         'message'        => "Veuillez renseigner le nom."
  1203.                     ]),
  1204.                 ],
  1205.                 'required'            => true,
  1206.             ])
  1207.             ->getForm();
  1208.         $form->handleRequest($request);
  1209.         if ($form->isSubmitted() && $form->isValid()) {
  1210.             // data is an array with "name", "email", and "message" keys
  1211.             $data $form->getData();
  1212.             $name $data['name'];
  1213.             $agencyMail $aRepo->find($offer->getAgency())->getEmail();
  1214.             $mailer->sendVisitSuccessful($landlord$offer$name$agencyMail);
  1215.             return $this->redirectToRoute('landlord_profile', ['id' => $landlord->getId()]);
  1216.         }
  1217.         return $this->render('landlord/landlord_quizz.html.twig', [
  1218.             'landlordId'    => $landlord->getId(),
  1219.             'tenantId'        => $tenant->getId(),
  1220.             'offerId'        => $offer->getId(),
  1221.             'appId'            => $app->getId(),
  1222.             'form'            => $form->createView(),
  1223.         ]);
  1224.     }
  1225.     /**
  1226.      * @Route("/locataire/questionnaire/key={token};app={appId}", name="tenant_quizz")
  1227.      * @ParamConverter("app", options={"mapping"={"appId"="id"}})
  1228.      */
  1229.     public function        tenantQuizz(User $tenant nullOfferTenantApplication $app nullSecurizer $securizerUserRepository $uRepoAgencyRepository $aRepoOfferRepository $oRepoRequest $requestCustomMailer $mailer)
  1230.     {
  1231.         if ($app == null || $tenant == null)
  1232.         {
  1233.             $this->addFlash('danger''Un problème a été rencontré avec cette application, le questionnaire est par conséquent inaccessible.');
  1234.             return $this->redirectToRoute('homepage');
  1235.         }
  1236.         // Create user for login event
  1237.         $token = new UsernamePasswordToken($tenant$tenant->getPassword(), "main"$tenant->getRoles());
  1238.         $this->get("security.token_storage")->setToken($token);
  1239.         // Fire the login event
  1240.         $event = new InteractiveLoginEvent($request$token);
  1241.         $dispatcher = new EventDispatcher();
  1242.         $dispatcher->dispatch($event"security.interactive_login");
  1243.         if ($tenant->getId() != $app->getTenantId())
  1244.         {
  1245.             $this->addFlash('danger''Vous n\'avez pas le droit d\'accéder à ce questionnaire.');
  1246.             return $this->redirectToRoute('homepage');
  1247.         }
  1248.         $landlord    $uRepo->find($app->getLandlordId());
  1249.         $offer        $oRepo->find($app->getOfferId());
  1250.         // check that we have the landlord, the tenant and the offer entities
  1251.         if ($landlord == null || $offer == null)
  1252.         {
  1253.             $this->addFlash('danger''Un problème a été rencontré avec cette application, le questionnaire est par conséquent inaccessible.');
  1254.             return $this->redirectToRoute('homepage');
  1255.         }
  1256.         $form $this->createFormBuilder([])
  1257.             ->add('name'TextType::class, [
  1258.                 'label'                => 'Nom du futur locataire',
  1259.                 'constraints'            => [
  1260.                     new Type('string'),
  1261.                     new NotBlank([
  1262.                         'message'        => "Veuillez renseigner le nom."
  1263.                     ]),
  1264.                 ],
  1265.                 'required'            => true,
  1266.             ])
  1267.             ->getForm();
  1268.         $form->handleRequest($request);
  1269.         if ($form->isSubmitted() && $form->isValid()) {
  1270.             // data is an array with "name", "email", and "message" keys
  1271.             $data $form->getData();
  1272.             $name $data['name'];
  1273.             $agencyMail $aRepo->find($offer->getAgency())->getEmail();
  1274.             $mailer->sendVisitSuccessful($landlord$offer$name$agencyMail);
  1275.             return $this->redirectToRoute('tenant_profile', ['id' => $tenant->getId()]);
  1276.         }
  1277.         return $this->render('landlord/landlord_quizz.html.twig', [
  1278.             'landlordId'    => $landlord->getId(),
  1279.             'tenantId'        => $tenant->getId(),
  1280.             'offerId'        => $offer->getId(),
  1281.             'appId'            => $app->getId(),
  1282.             'form'            => $form->createView(),
  1283.         ]);
  1284.     }
  1285.     /**
  1286.      * @Route("/mentions-legales", name="mentions_legales")
  1287.      */
  1288.     public function mentionsLegales(): Response
  1289.     {
  1290.         return $this->render('pages/mentions-legales.html.twig');
  1291.     }
  1292.     /**
  1293.      * @Route("/honoraires", name="honoraires")
  1294.      */
  1295.     public function honoraires(): Response
  1296.     {
  1297.         return $this->render('pages/honoraires.html.twig');
  1298.     }
  1299.     /**
  1300.      * @Route("/service-descriptif", name="service_descriptif")
  1301.      */
  1302.     public function serviceDescriptif(): Response
  1303.     {
  1304.         return $this->render('pages/service-descriptif.html.twig');
  1305.     }
  1306. }