<?php
namespace App\Controller\Page;
use App\Component\Configuration\Util\Config;
use App\Entity\JobAlert;
use App\Entity\JobAlertSetting;
use App\Entity\OptionValue;
use App\Event\JobAlertCreatedEvent;
use App\EventListener\FeatureFlagListener;
use App\Form\CompanyJobAlertType;
use App\Form\JobAlertType;
use App\Geocode\Coordinates;
use App\Geocode\Geocode;
use App\Renderer\Page;
use App\Service\CompanyService;
use App\Service\JobAlertService;
use App\Service\LocalisedSettingService;
use App\Service\MotionRecruitService;
use Doctrine\ORM\EntityManagerInterface;
use Flagception\Manager\FeatureManagerInterface;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Error\LoaderError as Twig_Error_Loader;
use Twig\Error\RuntimeError as Twig_Error_Runtime;
use Twig\Error\SyntaxError as Twig_Error_Syntax;
#[Route(path: '/jobalert')]
class JobAlertController extends AbstractController
{
private Page $pageRenderer;
private Geocode $geocode;
private JobAlertService $jobAlertService;
private FeatureManagerInterface $featureManager;
private TranslatorInterface $translator;
private LocalisedSettingService $localisedSettingService;
private EventDispatcherInterface $eventDispatcher;
private CompanyService $companyService;
private Config $config;
public function __construct(
Page $pageRenderer,
Geocode $geocode,
JobAlertService $jobAlertService,
FeatureManagerInterface $featureManager,
TranslatorInterface $translator,
LocalisedSettingService $localisedSettingService,
EventDispatcherInterface $eventDispatcher,
CompanyService $companyService,
Config $config,
private readonly EntityManagerInterface $entityManager,
) {
$this->pageRenderer = $pageRenderer;
$this->geocode = $geocode;
$this->jobAlertService = $jobAlertService;
$this->featureManager = $featureManager;
$this->translator = $translator;
$this->localisedSettingService = $localisedSettingService;
$this->eventDispatcher = $eventDispatcher;
$this->companyService = $companyService;
$this->config = $config;
}
/**
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
* @throws \Exception
* @throws GuzzleException
*/
public function indexAction(Request $request, ParameterBagInterface $parameterBag): Response
{
if (
$this->featureManager->isActive(FeatureFlagListener::FEATURE_MOTION_RECRUIT) &&
$username = $parameterBag->get('site_motion_recruit_username')
) {
return $this->redirect(
MotionRecruitService::generateJobAlertUrl($username)
);
}
$jobAlert = new JobAlert();
$form = $this->createForm(JobAlertType::class, $jobAlert, [
'is_expanded' => true,
]);
if ($this->featureManager->isActive(FeatureFlagListener::FEATURE_CHILD_SITE)) {
$form = $this->jobAlertService->getJobAlertForm(
$jobAlert,
['attr' => ['class' => 'recaptcha-form']],
$request->getHost()
);
}
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
/* @var Coordinates $coordinates */
if ($jobAlert->getLocation()) {
$coordinates = $this->geocode->getCoordinatesByLocation($jobAlert->getLocation());
$jobAlert->setLatitude($coordinates->getLatitude())
->setLongitude($coordinates->getLongitude())
;
}
$jobAlert->setLocale($request->getLocale());
if (!empty($this->config->get('site_jobalert_default_interval'))) {
$jobAlert->setFrequency($this->config->get('site_jobalert_default_interval'));
}
if ($this->featureManager->isActive(FeatureFlagListener::FEATURE_CHILD_SITE)) {
$result = $this->jobAlertService->postJobalert($jobAlert, $request->getHost());
if ($result) {
$this->addFlash('success', 'Jobalert is created');
return $this->redirectToRoute('jobalert_thanks');
}
} else {
$this->entityManager->persist($jobAlert);
$this->entityManager->flush();
$this->eventDispatcher->dispatch(new JobAlertCreatedEvent($jobAlert));
$this->addFlash('success', 'Jobalert is created');
return $this->redirectToRoute('jobalert_thanks');
}
}
$this->addFlash('danger', 'Cannot create jobalert');
}
$response = $this
->pageRenderer
->renderPage(
'{jobalert_form}',
'@default/pages/jobalert.html.twig',
[
'jobalert' => $jobAlert,
'form' => $form->createView(),
'show_privacy_statement_text' => (JobAlertSetting::PRIVACY_STATEMENT_STRATEGY_TEXT
=== $this->config->get('site_jobalert_privacy_statement_option')),
'privacy_statement_text' => $this->config->get('site_jobalert_privacy_statement_text'),
]
);
$response->setSharedMaxAge(0);
return $response;
}
/**
* @throws \Exception
* @throws GuzzleException
*/
#[Route(path: '/modal/jobalert', name: 'jobalert_create_modal')]
public function indexModalAction(Request $request): Response
{
$jobAlert = new JobAlert();
$form = $this->createForm(JobAlertType::class, $jobAlert, [
'is_expanded' => true,
]);
if ($this->featureManager->isActive(FeatureFlagListener::FEATURE_CHILD_SITE)) {
$form = $this->jobAlertService->getJobAlertForm($jobAlert, [], $request->getHost());
}
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
/* @var Coordinates $coordinates */
if ($jobAlert->getLocation()) {
$coordinates = $this->geocode->getCoordinatesByLocation($jobAlert->getLocation());
$jobAlert->setLatitude($coordinates->getLatitude())
->setLongitude($coordinates->getLongitude())
;
}
if (!empty($this->config->get('site_jobalert_default_interval'))) {
$jobAlert->setFrequency($this->config->get('site_jobalert_default_interval'));
}
$jobAlert->setLocale($request->getLocale());
if ($this->featureManager->isActive(FeatureFlagListener::FEATURE_CHILD_SITE)) {
$result = $this->jobAlertService->postJobalert($jobAlert, $request->getHost());
if ($result) {
$this->addFlash('success', 'Jobalert is created');
return $this->redirectToRoute('jobalert_thanks');
}
} else {
$this->entityManager->persist($jobAlert);
$this->entityManager->flush();
$this->addFlash('success', 'Jobalert is created');
$this->eventDispatcher->dispatch(new JobAlertCreatedEvent($jobAlert));
return $this->redirectToRoute('jobalert_thanks');
}
}
$this->addFlash('danger', 'Cannot create jobalert');
}
$response = $this->render(
'@default/pages/Modal/jobalert_modal.html.twig',
[
'jobalert' => $jobAlert,
'form' => $form->createView(),
'show_privacy_statement_text' => (JobAlertSetting::PRIVACY_STATEMENT_STRATEGY_TEXT
=== $this->config->get('site_jobalert_privacy_statement_option')),
'privacy_statement_text' => $this->config->get('site_jobalert_privacy_statement_text'),
]
);
$response->setSharedMaxAge(0);
return $response;
}
/**
* @throws Twig_Error_Loader
* @throws Twig_Error_Runtime
* @throws Twig_Error_Syntax
*/
public function thanksAction(): Response
{
return $this
->pageRenderer
->renderPage(
'{jobalert_thanks}',
'@default/pages/jobalert_thanks.html.twig',
[]
);
}
#[Route(path: '/unsubscribe/{hash}', name: 'jobalert_unsubscribe')]
public function unsubscribe(string $hash): Response
{
$hash = json_decode(base64_decode($hash, false), true);
if (!\is_array($hash) || !\array_key_exists('email', $hash)) {
return $this->redirectToRoute('homepage');
}
$matchingJobAlertCollection = $this->entityManager->getRepository(JobAlert::class)->findBy([
'email' => $hash['email'],
]);
if (!$matchingJobAlertCollection) {
return $this->redirectToRoute('homepage');
}
foreach ($matchingJobAlertCollection as $matchingJobAlert) {
$this->entityManager->remove($matchingJobAlert);
}
$this->entityManager->flush();
return $this->render('pages/jobalert/unsubscribe.html.twig', [
'email' => $hash['email'],
]);
}
/**
* Due to time pressure this is not completely DRY - a lot of similarities with companyJobalertAction. Refactor later.
*/
#[Route(path: '/option_value/{id}', name: 'jobalert_optionvalue_jobalert')]
public function singleOptionValueJobalert(Request $request, int $id): RedirectResponse|JsonResponse|Response
{
$jobalert = new JobAlert();
$form = $this->createForm(CompanyJobAlertType::class, $jobalert, [
'action' => $this->generateUrl('jobalert_company_jobalert', ['id' => $id, 'redirect' => $request->query->get('redirect')]),
]);
$form->handleRequest($request);
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$optionValue = $serializer->deserialize(json_encode(['id' => $id]), OptionValue::class, 'json');
if ($form->isSubmitted() && $form->isValid()) {
$jobalert->setFrequency(JobAlert::FREQUENCY_WEEKLY);
if ($this->featureManager->isActive(FeatureFlagListener::FEATURE_CHILD_SITE)) {
$this->jobAlertService->postJobalert($jobalert, $request->getHost(), [$optionValue]);
} else {
$this->entityManager->persist($jobalert);
$this->entityManager->flush();
}
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'message' => $this->localisedSettingService->getLocalisedSetting('site_jobalert_success_message'),
]);
}
$this->addFlash('success', $this->localisedSettingService->getLocalisedSetting('site_jobalert_success_message'));
return new RedirectResponse($request->query->get('redirect'));
}
return $this->render('@default/pages/company_job_alert_form.html.twig', ['form' => $form->createView()]);
}
/**
* @throws \Exception
*/
#[Route(path: '/company/{id}', name: 'jobalert_company_jobalert')]
public function companyJobalertAction(Request $request, int $id): Response
{
if (!$company = $this->companyService->getCompanyFromRequest($request)) {
throw $this->createNotFoundException('Company is not available');
}
$jobalert = new JobAlert();
$form = $this->createForm(CompanyJobAlertType::class, $jobalert, [
'action' => $this->generateUrl('jobalert_company_jobalert', ['id' => $id, 'redirect' => $request->query->get('redirect')]),
]);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$jobalert->setCompany($company)
->setFrequency(JobAlert::FREQUENCY_WEEKLY)
;
if ($this->featureManager->isActive(FeatureFlagListener::FEATURE_CHILD_SITE)) {
$this->jobAlertService->postJobalert($jobalert, $request->getHost());
} else {
$this->entityManager->persist($jobalert);
$this->entityManager->flush();
}
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'message' => $this->localisedSettingService->getLocalisedSetting('site_jobalert_success_message'),
]);
}
$this->addFlash('success', $this->localisedSettingService->getLocalisedSetting('site_jobalert_success_message'));
return new RedirectResponse($request->query->get('redirect'));
}
$this->addFlash('danger', $this->translator->trans('Job alert could not be created'));
}
return $this->render('@default/pages/company_job_alert_form.html.twig', ['form' => $form->createView()]);
}
}