src/Controller/EnquiryDefaultController.php line 88

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Enquiry;
  4. use App\Entity\EnquiryCV;
  5. use App\Form\EnquiryType;
  6. use App\Form\EnquiryCVType;
  7. use App\Annotation\CmsComponent;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Google\Cloud\RecaptchaEnterprise\V1\Event;
  11. use Symfony\Component\HttpFoundation\Response;
  12. use Symfony\Component\Routing\Annotation\Route;
  13. use Google\Cloud\RecaptchaEnterprise\V1\Assessment;
  14. use Google\Cloud\RecaptchaEnterprise\V1\CreateAssessmentRequest;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Google\Cloud\RecaptchaEnterprise\V1\TokenProperties\InvalidReason;
  17. use Google\Cloud\RecaptchaEnterprise\V1\Client\RecaptchaEnterpriseServiceClient;
  18. class EnquiryDefaultController extends AbstractController
  19. {
  20.     private ?RecaptchaEnterpriseServiceClient $client null;
  21.     private string $errorMessage '';
  22.     public function __construct(
  23.         private EntityManagerInterface $em,
  24.         private \Swift_Mailer $mailer,
  25.         private string $email_noreply,
  26.         private string $email_primary,
  27.         private readonly string $recaptcha_key,
  28.         private readonly string $recaptcha_project_id,
  29.         private readonly string $projectRoot
  30.     ) { }
  31.     /**
  32.      * @CmsComponent("Embed Enquiry Form", active=true, routeName="embed_enquiry")
  33.      */
  34.     #[Route(path'/cms-enquiry'name'embed_enquiry')]
  35.     public function embedEnquiry(Request $request, ): Response
  36.     {
  37.         $enquiry = new Enquiry();
  38.         $enquiry->setSubject('New Website Enquiry');
  39.         $form $this->createForm(EnquiryType::class, $enquiry);
  40.         $form->handleRequest($request);
  41.         $error false;
  42.         $success false;
  43.         $errorMessage '';
  44.         if ($form->isSubmitted()) {
  45.             if ($this->spamChecksPass($request)) {
  46.                 if ($form->isValid()) {
  47.                     $this->em->persist($enquiry);
  48.                     $this->em->flush();
  49.                     $success true;
  50.                     $this->sendEmail($enquiry);
  51.                 } else {
  52.                     $error true;
  53.                     $errorMessage 'Error - Check the form for errors';
  54.                 }
  55.             } else {
  56.                 $error true;
  57.                 $errorMessage $this->errorMessage;
  58.             }
  59.         }
  60.         return $this->render('@theme/enquiry/enquiry.html.twig', [
  61.             'enquiry' => $enquiry,
  62.             'error' => $error,
  63.             'success' => $success,
  64.             'errorMessage' => $errorMessage,
  65.             'form' => $form->createView(),
  66.         ]);
  67.     }
  68.     /**
  69.      * @CmsComponent("Embed Enquiry Form & Map", active=true, routeName="embed_enquiry_map")
  70.      */
  71.     #[Route(path'/cms-enquiry-map'name'embed_enquiry_map')]
  72.     public function embedEnquiryMap(Request $request, ): Response
  73.     {
  74.         $enquiry = new Enquiry();
  75.         $enquiry->setSubject('New Website Enquiry');
  76.         $form $this->createForm(EnquiryType::class, $enquiry);
  77.         $form->handleRequest($request);
  78.         $error false;
  79.         $success false;
  80.         $errorMessage '';
  81.         if ($form->isSubmitted()) {
  82.             if ($this->spamChecksPass($request)) {
  83.                 if ($form->isValid()) {
  84.                     $this->em->persist($enquiry);
  85.                     $this->em->flush();
  86.                     $success true;
  87.                     $this->sendEmail($enquiry);
  88.                 } else {
  89.                     $error true;
  90.                     $errorMessage 'Error - Check the form for errors';
  91.                 }
  92.             } else {
  93.                 $error true;
  94.                 $errorMessage 'Error - Captcha Invalid';
  95.             }
  96.         }
  97.         return $this->render('@theme/enquiry/enquiry_map.html.twig', [
  98.             'enquiry' => $enquiry,
  99.             'error' => $error,
  100.             'success' => $success,
  101.             'errorMessage' => $errorMessage,
  102.             'form' => $form->createView(),
  103.         ]);
  104.     }
  105.     /**
  106.      * @CmsComponent("Embed CV form", active=true, routeName="embed_enquiry_cv")
  107.      */
  108.     #[Route(path'/cms-enquiry-cv'name'embed_enquiry_cv')]
  109.     public function embedEnquiryCv(Request $request): Response
  110.     {
  111.         $enquiry = new EnquiryCV();
  112.         $form $this->createForm(EnquiryCVType::class, $enquiry);
  113.         $form->handleRequest($request);
  114.         $error false;
  115.         $success false;
  116.         $errorMessage '';
  117.         if ($form->isSubmitted()) {
  118.             if ($this->spamChecksPass($request)) {
  119.                 if ($form->isValid()) {
  120.                     $enquiry->uploadFile();
  121.                     $this->em->persist($enquiry);
  122.                     $this->em->flush();
  123.                     $success true;
  124.                     $this->sendCVEmail($enquiry);
  125.                 } else {
  126.                     $error true;
  127.                     $errorMessage 'Error - Check the form for errors';
  128.                 }
  129.             } else {
  130.                 $error true;
  131.                 $errorMessage 'Error - Captcha Invalid';
  132.             }
  133.         }
  134.         return $this->render('@theme/enquiry/enquiry_cv.html.twig', [
  135.             'enquiry' => $enquiry,
  136.             'error' => $error,
  137.             'success' => $success,
  138.             'errorMessage' => $errorMessage,
  139.             'form' => $form->createView(),
  140.         ]);
  141.     }
  142.     #[Route(path'/email-test'name'email_test')]
  143.     public function emailTest(): Response
  144.     {
  145.         return $this->render('@theme/emails/enquiry-confirmed.html.twig');
  146.     }
  147.     private function sendEmail(Enquiry $enquiry): void
  148.     {
  149.         $message_to_client = (new \Swift_Message())
  150.             ->setSubject('Enquiry Received via '.$this->getParameter('sitename').' website')
  151.             ->setFrom($this->email_noreply)
  152.             ->setTo($this->email_primary)
  153.             ->setBody(
  154.                 $this->renderView('@theme/emails/enquiry-to-client.html.twig', ['enquiry' => $enquiry]),
  155.                 'text/html'
  156.             )
  157.         ;
  158.         try {
  159.             $this->mailer->send($message_to_client);
  160.         } catch (\Throwable $th) {
  161.             // ignore
  162.         }
  163.         $this->sendConfirmationEmail($enquiry);
  164.     }
  165.     private function sendCVEmail(EnquiryCV $enquiry): void
  166.     {
  167.         $message_to_client = (new \Swift_Message())
  168.             ->setSubject('Enquiry Received via '.$this->getParameter('sitename').' website')
  169.             ->setFrom($this->email_noreply)
  170.             ->setTo($this->email_primary)
  171.             ->setBody(
  172.                 $this->renderView('@theme/emails/enquiry-to-client-cv.html.twig', ['enquiry' => $enquiry]),
  173.                 'text/html'
  174.             )
  175.         ;
  176.         try {
  177.             $this->mailer->send($message_to_client);
  178.         } catch (\Throwable $th) {
  179.             // ignore
  180.         }
  181.         $this->sendConfirmationEmail($enquiry);
  182.     }
  183.     private function sendConfirmationEmail($enquiry): void
  184.     {
  185.         $message_to_user = (new \Swift_Message())
  186.             ->setSubject('Enquiry sent to '.$this->getParameter('sitename').' confirmed')
  187.             ->setFrom($this->email_noreply)
  188.             ->setTo($enquiry->getEmail())
  189.             ->setBody(
  190.                 $this->renderView(
  191.                     '@theme/emails/enquiry-confirmed.html.twig',
  192.                     ['enquiry' => $enquiry]
  193.                 ),
  194.                 'text/html'
  195.             )
  196.         ;
  197.         // try {
  198.             $this->mailer->send($message_to_user);
  199.         // } catch (\Throwable $th) {
  200.             // ignore
  201.         // }
  202.     }
  203.     private function spamChecksPass(Request $request): bool
  204.     {
  205.         // also test form execution time
  206.         try {
  207.             $posted $request->request->All();
  208.             // check for captcha response
  209.             $recaptcha $posted['g-recaptcha-response'] ?? null;
  210.             if (empty($recaptcha)) {
  211.                 return false;
  212.             }
  213.             // check for form execution time
  214.             $loadedAt = (int) $posted['enquiry']['_loaded_at'] ?? 0;
  215.             if ($loadedAt && (time() - $loadedAt) < 3) {
  216.                 return false;
  217.             }
  218.             // check for $honeypot field
  219.             $honeypot $posted['enquiry']['website'] ?? null;
  220.             if (!empty($honeypot)) {
  221.                 return false;
  222.             }
  223.             return $this->verifyRecaptcha($recaptcha);
  224.         } catch (\Throwable $th) {
  225.             return false;
  226.         }
  227.     }
  228.     private function verifyRecaptcha($token): bool
  229.     {
  230.         $this->errorMessage '';
  231.         if (! $this->client) {
  232.             $this->client = new RecaptchaEnterpriseServiceClient([
  233.                 'credentials' => $this->projectRoot '/kasscaffolding-850ee80a9abf.json',
  234.             ]);
  235.             $projectName $this->client->projectName($this->recaptcha_project_id);
  236.         }
  237.         // Set the properties of the event to be tracked.
  238.         $event = (new Event())
  239.             ->setSiteKey($this->recaptcha_key)
  240.             ->setToken($token);
  241.         $assessment = (new Assessment())
  242.             ->setEvent($event);
  243.         $request = (new CreateAssessmentRequest())
  244.             ->setParent($projectName)
  245.             ->setAssessment($assessment);
  246.         try {
  247.             $response $this->client->createAssessment($request);
  248.             if ($response->getTokenProperties()->getValid() == false) {
  249.                 $this->errorMessage InvalidReason::name($response->getTokenProperties()->getInvalidReason());
  250.                 return false;
  251.             }
  252.             $score $response->getRiskAnalysis()->getScore();
  253.             if ($score 0.5) {
  254.                 $this->errorMessage 'Low score: ' $score;
  255.                 return false;
  256.             }
  257.         } catch (\Exception $e) {
  258.             return false;
  259.         }
  260.         return true;
  261.     }
  262. }