<?php
namespace App\Controller;
use App\Entity\ApplicationEvent;
use App\Entity\Blacklisting;
use App\Entity\OccupationalField;
use App\Entity\PlatformSite;
use App\Entity\RecurrentJob;
use App\Entity\User;
use App\Event\RecurrentJobSharePageRequestedEvent;
use App\Event\RecurrentJobWillForwardToExternalUrlEvent;
use App\Event\UserTermsAndConditionsAcceptedEvent;
use App\Repository\ZipcodeCircumcirclesRepository;
use App\Service\AnonymousUserInfoService;
use App\Service\ApplicationEventService;
use App\Service\BlacklistingService;
use App\Service\CaptchaService;
use App\Service\ConversionEventService;
use App\Service\CriteoService;
use App\Service\ExtendedApplication\ExtendedApplicationBaseService;
use App\Service\ExtendedApplication\ExtendedApplicationCustomerService;
use App\Service\FeatureLimitationsService;
use App\Service\RecurrentJobContentDistributionValueService;
use App\Service\RecurrentJobService;
use App\Service\RecurrentJobsSearchService;
use App\Service\RecurrentJobsShareService;
use App\Service\RouterHelperService;
use App\Service\SessionService;
use App\Utility\GuidUtility;
use App\Value\MimeTypes;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use FOS\UserBundle\Form\Factory\FactoryInterface;
use GuzzleHttp\Exception\GuzzleException;
use JanusHercules\DatawarehouseIntegration\Domain\Entity\BusinessEvent;
use JanusHercules\DatawarehouseIntegration\Domain\Service\BusinessEventDomainService;
use JanusHercules\ExtendedApplicationQuestionnaire\Domain\Service\ExtendedApplicationQuestionsDomainService;
use Knp\Snappy\Pdf;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Throwable;
class RecurrentJobsShareController extends AbstractController
{
private RecurrentJobsShareService $recurrentJobsShareService;
private EntityManagerInterface $entityManager;
private RequestStack $requestStack;
private SessionService $sessionService;
private EventDispatcherInterface $eventDispatcher;
private LoggerInterface $logger;
private TranslatorInterface $translator;
private RouterHelperService $routerHelperService;
private FactoryInterface $formFactory;
private FeatureLimitationsService $featureLimitationsService;
private ExtendedApplicationBaseService $extendedApplicationBaseService;
private string $routerRequestContextHost;
private string $routerRequestContextScheme;
private string $routerRequestContextBaseUrl;
public function __construct(
RecurrentJobsShareService $recurrentJobsShareService,
EntityManagerInterface $entityManager,
RequestStack $requestStack,
SessionService $sessionService,
EventDispatcherInterface $eventDispatcher,
LoggerInterface $logger,
TranslatorInterface $translator,
RouterHelperService $routerHelperService,
FactoryInterface $formFactory,
FeatureLimitationsService $featureLimitationsService,
ExtendedApplicationBaseService $extendedApplicationBaseService,
string $routerRequestContextHost,
string $routerRequestContextScheme,
string $routerRequestContextBaseUrl
) {
$this->recurrentJobsShareService = $recurrentJobsShareService;
$this->entityManager = $entityManager;
$this->requestStack = $requestStack;
$this->sessionService = $sessionService;
$this->eventDispatcher = $eventDispatcher;
$this->logger = $logger;
$this->translator = $translator;
$this->routerHelperService = $routerHelperService;
$this->formFactory = $formFactory;
$this->featureLimitationsService = $featureLimitationsService;
$this->extendedApplicationBaseService = $extendedApplicationBaseService;
$this->routerRequestContextHost = $routerRequestContextHost;
$this->routerRequestContextScheme = $routerRequestContextScheme;
$this->routerRequestContextBaseUrl = $routerRequestContextBaseUrl;
}
/**
* @ParamConverter("recurrentJob", class="App\Entity\RecurrentJob", options={"id" = "recurrentJobId"})
*
* @throws Exception
*/
public function viewAction(
?RecurrentJob $recurrentJob,
FeatureLimitationsService $featureLimitationsService,
Request $request,
ZipcodeCircumcirclesRepository $zipcodeCircumcirclesRepository,
AnonymousUserInfoService $anonymousUserInfoService,
ConversionEventService $conversionEventService,
ExtendedApplicationBaseService $extendedApplicationBaseService,
RecurrentJobsSearchService $recurrentJobsSearchService,
ExtendedApplicationQuestionsDomainService $extendedApplicationQuestionsDomainService,
ExtendedApplicationCustomerService $extendedApplicationCustomerService
) {
/** @var User|null $user */
$user = $this->getUser();
if (!is_null($recurrentJob) && $recurrentJob->getJoboffererProfile()->getUser() === $user) {
return $this->render(
'recurrent_jobs/share/view.html.twig',
[
'recurrentJob' => $recurrentJob,
'recurrentJobBundesland' => $zipcodeCircumcirclesRepository->getBundeslandForRecurrentJob($recurrentJob),
'showAnonymous' => $featureLimitationsService->userMustSeeRecurrentJobAnonymized($user, $recurrentJob),
'newConversationMessageSubjectPrefillBase64' => null,
'newConversationMessageBodyPrefillBase64' => null,
'isPartOfASearchResultList' => false,
'highlightedOccupationalField' => $this->getHighlightedOccupationalField($request),
'additionalFiles' => $recurrentJob->getJoboffererProfile()->getAdditionalFiles(),
'jobseekerHasAlreadyAppliedViaExtendedApplication' => (
$user->isJobseeker()
&& $extendedApplicationBaseService->extendedApplicationFromJobseekerToRecurrentJobAlreadyExists(
$recurrentJob,
$user->getDefaultJobseekerProfile()
)
),
'fromSearch' => $request->get('fromSearch')
]
);
}
$this->eventDispatcher->dispatch(
new RecurrentJobSharePageRequestedEvent(
$recurrentJob,
$user,
$request,
(int)$request->get(ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_CAMPAIGN_ID, -1),
PlatformSite::PLATFORM_SITE_ID_JOBOO
),
RecurrentJobSharePageRequestedEvent::class
);
if (is_null($recurrentJob) || !$recurrentJob->isActive()) {
$recurrentJobsSearchService->syncRecurrentJobIdWithElasticSearch(
$request->get('recurrentJobId')
);
if (!is_null($recurrentJob)) {
$recurrentJob = $recurrentJobsSearchService->getSimilarActiveRecurrentJob($recurrentJob, $request);
if (is_null($recurrentJob)) {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
} else {
$this->addFlash(
'warning',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive_but_alternative')
);
return $this->redirectToRoute('recurrent_jobs.share', array_merge(['recurrentJobId' => $recurrentJob->getId()], $request->query->all()));
}
} else {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
}
}
if ($request->get('utm_source') === 'google_jobs_apply') {
return $this->redirect(
$this->generateUrl('recurrent_jobs.share',
['recurrentJobId' => $recurrentJob->getId()]
)
. '?'
. $conversionEventService->getQueryStringParameterForGoalReachedConversionTrackingInitiation(
ConversionEventService::CAMPAIGN_ID_GOOGLE_FOR_JOBS,
0,
$recurrentJob
)
);
}
if ($this
->featureLimitationsService
->recurrentJobAlwaysForwardsToExternalJobPostInsteadOfShowingSharePage($recurrentJob)
) {
return $this->redirectToRoute(
'recurrent_jobs.forward_to_external_job_post',
array_merge(['recurrentJobId' => $recurrentJob->getId(), 'directForwarding' => 'true'], $request->query->all())
);
}
$anonymousUserInfoService->setInfoIncomingExternalRecurrentJobsView($recurrentJob);
$ordinaryForm = $this->formFactory->createForm();
$this->sessionService->setRecurrentJobUriToOfferForReturn(
$this->requestStack->getSession(),
$this->routerHelperService->generate(
'recurrent_jobs.share',
[
'recurrentJobId' => $recurrentJob->getId(),
'seo_slug' => ''
],
UrlGeneratorInterface::ABSOLUTE_URL
)
);
if (!is_null($user)) {
if ($recurrentJob->getStatus() === RecurrentJob::STATUS_ACTIVE
|| (
($recurrentJob->getStatus() === RecurrentJob::STATUS_DRAFT || $recurrentJob->isInactive())
&& ($recurrentJob->getJoboffererProfile()->getUser()->getId() === $user->getId())
)
) {
$form = $this->getExtendedApplicationForm(
$recurrentJob,
$user,
$request,
$extendedApplicationQuestionsDomainService,
$extendedApplicationCustomerService
);
$form = !is_null($form) ? $form->createView() : null;
$conversationMessagePrefill = $this
->recurrentJobsShareService
->presetConversationMessage(
$recurrentJob,
$featureLimitationsService,
$user
);
return $this->render(
'recurrent_jobs/share/view.html.twig',
[
'recurrentJob' => $recurrentJob,
'recurrentJobBundesland' => $zipcodeCircumcirclesRepository->getBundeslandForRecurrentJob($recurrentJob),
'showAnonymous' => $featureLimitationsService->userMustSeeRecurrentJobAnonymized($user, $recurrentJob),
'newConversationMessageSubjectPrefillBase64' => base64_encode($conversationMessagePrefill['subject']),
'newConversationMessageBodyPrefillBase64' => base64_encode($conversationMessagePrefill['body']),
'isPartOfASearchResultList' => false,
'highlightedOccupationalField' => $this->getHighlightedOccupationalField($request),
'additionalFiles' => $recurrentJob->getJoboffererProfile()->getAdditionalFiles(),
'ordinaryRegistrationForm' => $ordinaryForm->createView(),
'form' => $form,
'jobseekerHasAlreadyAppliedViaExtendedApplication' => (
$user->isJobseeker()
&& $extendedApplicationBaseService->extendedApplicationFromJobseekerToRecurrentJobAlreadyExists(
$recurrentJob,
$user->getDefaultJobseekerProfile()
)
),
'fromSearch' => $request->get('fromSearch')
]
);
} else {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
if ($user->isJobseeker()) {
return $this->redirectToRoute('recurrent_jobs_search.form');
} else {
return $this->redirectToRoute('wanted_jobs_search.form');
}
}
} else {
if ($recurrentJob->getStatus() === RecurrentJob::STATUS_ACTIVE) {
$form = $this->getExtendedApplicationForm(
$recurrentJob,
$user,
$request,
$extendedApplicationQuestionsDomainService,
$extendedApplicationCustomerService
);
$form = !is_null($form) ? $form->createView() : null;
return $this->render(
'recurrent_jobs/share/view.html.twig',
[
'recurrentJob' => $recurrentJob,
'recurrentJobBundesland' => $zipcodeCircumcirclesRepository->getBundeslandForRecurrentJob($recurrentJob),
'showAnonymous' => $featureLimitationsService->userMustSeeRecurrentJobAnonymized($user, $recurrentJob),
'isPartOfASearchResultList' => false,
'highlightedOccupationalField' => $this->getHighlightedOccupationalField($request),
'additionalFiles' => $recurrentJob->getJoboffererProfile()->getAdditionalFiles(),
'form' => $form,
'ordinaryRegistrationForm' => $ordinaryForm->createView(),
'jobseekerHasAlreadyAppliedViaExtendedApplication' => false,
'anonymousJobSearch' => $request->get('anonymousJobSearch')
]
);
} else {
if (!is_null($recurrentJob = $recurrentJobsSearchService->getSimilarActiveRecurrentJob($recurrentJob, $request))) {
$this->addFlash(
'warning',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive_but_alternative')
);
return $this->redirectToRoute('recurrent_jobs.share', array_merge(['recurrentJobId' => $recurrentJob->getId()], $request->query->all()));
} else {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
}
}
}
}
/**
* @ParamConverter("recurrentJob", class="App\Entity\RecurrentJob", options={"id" = "recurrentJobId"})
*
* @throws Exception
*/
public function requestedFromSearchResultAction(
?RecurrentJob $recurrentJob,
Request $request,
RecurrentJobContentDistributionValueService $recurrentJobContentDistributionValueService
) {
if (is_null($recurrentJob)) {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
}
$customer = null;
if ($recurrentJob->isLinkedToExternalPartner() && !is_null($recurrentJob->getIntegratedExternalPartnerCustomer())) {
$customer = $recurrentJob->getIntegratedExternalPartnerCustomer();
}
if (
$this->featureLimitationsService->recurrentJobAlwaysForwardsToExternalJobPostInsteadOfShowingSharePage($recurrentJob)
|| (!is_null($customer)
&& $customer->hasClickBasedBilling()
&& $this->featureLimitationsService->recurrentJobMustLinkExternally($recurrentJob))
) {
return $this->redirectToRoute(
'recurrent_jobs.forward_to_external_job_post',
array_merge(['recurrentJobId' => $recurrentJob->getId(), 'directForwarding' => 'true'], $request->query->all())
);
} else {
return $this->redirectToRoute(
'recurrent_jobs.share',
array_merge(['recurrentJobId' => $recurrentJob->getId(), 'directForwarding' => 'true', 'fromSearch' => true], $request->query->all())
);
}
}
/**
* @ParamConverter("recurrentJob", class="App\Entity\RecurrentJob", options={"id" = "recurrentJobId"})
*
* @throws Exception
*/
public function viewOrForwardAction(
?RecurrentJob $recurrentJob,
Request $request,
FeatureLimitationsService $featureLimitationsService,
RouterInterface $router
): Response {
if (is_null($recurrentJob)) {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirect(
$this->routerRequestContextScheme . '://'
. $this->routerRequestContextHost
. $this->routerRequestContextBaseUrl
. $router->generate(
'recurrent_jobs_search.form'
)
);
}
$ctaTypeId = null;
if (!is_null($request->get('ctaTypeId'))) {
$ctaTypeId = (int)$request->get('ctaTypeId');
}
if ($recurrentJob->belongsToIntegratedExternalPartnerCustomer()
&& $featureLimitationsService->recurrentJobMustLinkExternally($recurrentJob)
&& $recurrentJob->getIntegratedExternalPartnerCustomer()->isDirectForwarded()
) {
/* This action is available under multiple routes, one for each of our platform sites:
* - joboo (recurrent_jobs.view_or_forward)
* - recruit (recruit_dl.recurrent_jobs.view_or_forward)
* - jobooOnline (joboo_online.recurrent_jobs.view_or_forward)
*
* Because each platform site is made available under its own top level domain,
* a problem arises if we redirect from, say recruit-dl.de to joboo.de:
*
* The initial visit is to recruit-dl.de, and the application starts a new PHP session
* for the visiting client. The session id is stored in a cookie, but the cookie is
* only valid for the recruit-dl.de domain.
*
* Under this session, certain tracking mechanisms take place, e.g. its stored
* that for a Conversion Tracking campaign, steps 0 and 1 have occured.
*
* This prepares the system to track the goal reached (step 2) conversion event.
*
* However, if we then redirect the client to joboo.de, the session cookie is not
* valid for this domain, and the client will start a new session.
*
* This new session will not have the tracking information from the previous session,
* and accordingly, the goal reached conversion event will not be tracked.
*
* Therefore, we need to identify the platform site that the client is currently on,
* and use the redirect route for that platform site, while avoiding a top-level domain change
* during redirection.
*/
$platformSiteId = PlatformSite::getPlatformSiteIdByRequest($request);
if ($platformSiteId === PlatformSite::PLATFORM_SITE_ID_RECRUIT_DL) {
$routename = 'recruit_dl.external_partners.forward_to_external_job_post';
} elseif ($platformSiteId === PlatformSite::PLATFORM_SITE_ID_JOBOO_ONLINE) {
$routename = 'joboo_online.external_partners.forward_to_external_job_post';
} else {
$routename = 'recurrent_jobs.forward_to_external_job_post';
}
return $this->redirect(
$router->generate(
$routename,
array_merge(
[
'recurrentJobId' => $recurrentJob->getId(),
'directForwarding' => 'true',
'ctaTypeId' => $ctaTypeId
],
$request->query->all()
)
)
);
}
return $this->redirect(
$this->routerRequestContextScheme . '://'
. $this->routerRequestContextHost
. $this->routerRequestContextBaseUrl
. $router->generate(
'recurrent_jobs.share',
array_merge(['recurrentJobId' => $recurrentJob->getId()], $request->query->all())
)
);
}
/**
* @ParamConverter("recurrentJob", class="App\Entity\RecurrentJob", options={"id" = "recurrentJobId"})
*
* @throws Exception
*/
public function viewOrForwardEbayAction(?RecurrentJob $recurrentJob, Request $request, ConversionEventService $conversionEventService)
{
if (is_null($recurrentJob)) {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
}
$ctaTypeId = null;
if (!is_null($request->get('ctaTypeId'))) {
$ctaTypeId = (int)$request->get('ctaTypeId');
}
if ($recurrentJob->belongsToIntegratedExternalPartnerCustomer() && $recurrentJob->getIntegratedExternalPartnerCustomer()->isDirectForwardedEbay()) {
return $this->redirectToRoute('recurrent_jobs.forward_to_external_job_post', array_merge(['recurrentJobId' => $recurrentJob->getId(), 'directForwarding' => 'true', 'ctyTypeId' => $ctaTypeId], $request->query->all()));
}
return $this->redirectToRoute('recurrent_jobs.share', array_merge(['recurrentJobId' => $recurrentJob->getId()], $request->query->all()));
}
/**
* @ParamConverter("recurrentJob", class="App\Entity\RecurrentJob", options={"id" = "recurrentJobId"})
*/
public function viewOrForwardKleinanzeigenAction(?RecurrentJob $recurrentJob, Request $request)
{
if (is_null($recurrentJob)) {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
}
return $this->redirectToRoute('recurrent_jobs.view_or_forward_ebay', array_merge(['recurrentJobId' => $recurrentJob->getId(), ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_CAMPAIGN_ID => ConversionEventService::CAMPAIGN_ID_EBAY, ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_SUBCAMPAIGN_ID => (int)$request->get('variante', 0)], $request->query->all()));
}
public function extendedApplicationThanksAction(Request $request, EntityManagerInterface $entityManager, CriteoService $criteoService)
{
$relatedRecurrentJobId = $criteoService->getLastSuccessfullCriteoConversionForUserid($request->get('userId', null));
$showTalentPixel = $request->get('showTalentPixel');
/** @var User $user */
$user = $entityManager->find(User::class, $request->get('userId'));
return $this->render(
'extended_application/thanks.html.twig',
[
'user' => $user,
'recurrentJobId' => $relatedRecurrentJobId,
'showTalentPixel' => $showTalentPixel,
'confirmationNecessary' => !(!is_null($user) && $user->isEnabled()),
]
);
}
/**
* @ParamConverter("recurrentJob", class="App\Entity\RecurrentJob", options={"id" = "recurrentJobId"})
*
* @throws Exception
*/
public function handleExtendedApplicationAction(
Request $request,
?RecurrentJob $recurrentJob,
CaptchaService $captchaService,
ZipcodeCircumcirclesRepository $zipcodeCircumcirclesRepository,
ExtendedApplicationBaseService $extendedApplicationBaseService,
ApplicationEventService $applicationEventService,
BlacklistingService $blacklistingService,
ExtendedApplicationQuestionsDomainService $extendedApplicationQuestionsDomainService,
ExtendedApplicationCustomerService $extendedApplicationCustomerService
): RedirectResponse|Response {
try {
if (is_null($recurrentJob)) {
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_job_inactive')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
}
/** @var ?User $user */
$user = $this->getUser();
$formOptions = [
'cvForExtendedApplicationsMandatory' => (!is_null($this->getUser())
&& !is_null($recurrentJob->getIntegratedExternalPartnerCustomer())
&& $recurrentJob->getIntegratedExternalPartnerCustomer()->cvForExtendedApplicationsMandatory()),
'phoneNumberForExtendedApplicationsMandatory' => $extendedApplicationBaseService->phoneNumberForExtendedApplicationsMandatory($recurrentJob),
'extendedApplicationQuestions' => $extendedApplicationQuestionsDomainService->getActiveExtendedApplicationQuestionsForRecurrentJob($recurrentJob),
'user' => $user,
'isJoboo' => true,
'showTertiaryCvFile' => $extendedApplicationCustomerService->extendedApplicationForRecurrentJobMustShowTertiaryCvFile($recurrentJob),
'tertiaryCvFileConfig' => $extendedApplicationCustomerService->getTertiaryCvFileUploadFieldConfigurationForRecurrentJob($recurrentJob)
];
$jobseekerProfile = !is_null($user) ? $user->getDefaultJobseekerProfile() : null;
if (!is_null($jobseekerProfile) && !empty($jobseekerProfile->getDocumentFileName())) {
$formOptions['defaultCVFileName'] = $jobseekerProfile->getDocumentFileName();
}
$form = $this->recurrentJobsShareService->getExtendedApplicationForm($formOptions)->handleRequest($request);
$ordinaryForm = $this->formFactory->createForm();
$renderParameters = [
'recurrentJob' => $recurrentJob,
'additionalFiles' => $recurrentJob->getJoboffererProfile()->getAdditionalFiles(),
'recurrentJobBundesland' => $zipcodeCircumcirclesRepository->getBundeslandForRecurrentJob($recurrentJob),
'showAnonymous' => true,
'isPartOfASearchResultList' => false,
'highlightedOccupationalField' => $this->getHighlightedOccupationalField($request),
'form' => $form->createView(),
'ordinaryRegistrationForm' => $ordinaryForm->createView()
];
if ($form->isSubmitted() && $form->isValid()) {
if (is_null($this->getUser()) && !$captchaService->requestContainsValidCaptchaSolution($request)) {
$renderParameters['errorMessage'] = $this->translator->trans('recurrent_jobs_search.alert_application_captcha_error');
$applicationEventService->writeNewEvent(
ApplicationEvent::EVENT_CATEGORY_ERROR,
ApplicationEvent::EVENT_TYPE_CAPTCHA_RETURNED_ERROR,
$this->getUser(),
null,
null,
json_encode(['url' => $request->getUri()])
);
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters
);
}
$useDefaultDocument = false;
if (isset($form['useDefaultDocument']) && !empty($form->get('useDefaultDocument')->getData())) {
$useDefaultDocument = $form->get('useDefaultDocument')->getData();
}
$usePrimaryUploadedFile = isset($form['useUploadedPrimaryFile'])
&& !empty($form->get('useUploadedPrimaryFile')->getData())
&& $form->get('useUploadedPrimaryFile')->getData();
$uploadedPrimaryCvFile = null;
if ($usePrimaryUploadedFile || $useDefaultDocument) {
$uploadedPrimaryCvFile = $this
->recurrentJobsShareService
->getUploadedFile(
$request,
'primaryCvFile',
$useDefaultDocument ? $jobseekerProfile->getDocumentFileName() : null
);
}
if (!is_null($uploadedPrimaryCvFile)) {
if (!in_array($uploadedPrimaryCvFile->getMimeType(), MimeTypes::ALLOWED_FOR_USER_UPLOAD_EXTENDED_APPLICATION)) {
$renderParameters['errorMessage'] = $this->translator->trans('recurrent_jobs_search.alert_application_mimetype_error', ['%mimetype' => $uploadedPrimaryCvFile->getMimeType()]);
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters,
new Response(null, Response::HTTP_BAD_REQUEST)
);
}
}
$useSecondaryUploadedFile = isset($form['useUploadedSecondaryFile'])
&& !empty($form->get('useUploadedSecondaryFile')->getData())
&& $form->get('useUploadedSecondaryFile')->getData();
$uploadedSecondaryCvFile = null;
if ($useSecondaryUploadedFile) {
$uploadedSecondaryCvFile = $this
->recurrentJobsShareService
->getUploadedFile($request, 'secondaryCvFile');
}
if (!is_null($uploadedSecondaryCvFile)) {
if (!in_array($uploadedSecondaryCvFile->getMimeType(), MimeTypes::ALLOWED_FOR_USER_UPLOAD_ALL)) {
$renderParameters['errorMessage'] = $this->translator->trans('recurrent_jobs_search.alert_application_mimetype_error', ['%mimetype' => $uploadedSecondaryCvFile->getMimeType()]);
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters,
new Response(null, Response::HTTP_BAD_REQUEST)
);
}
}
$useTertiaryUploadedFile = isset($form['useUploadedTertiaryFile'])
&& !empty($form->get('useUploadedTertiaryFile')->getData())
&& $form->get('useUploadedTertiaryFile')->getData();
$uploadedTertiaryCvFile = null;
if ($useTertiaryUploadedFile) {
$uploadedTertiaryCvFile = $this
->recurrentJobsShareService
->getUploadedFile($request, 'tertiaryCvFile');
}
if (!is_null($uploadedTertiaryCvFile)) {
if (!in_array($uploadedTertiaryCvFile->getMimeType(), MimeTypes::ALLOWED_FOR_USER_UPLOAD_ALL)) {
$renderParameters['errorMessage'] = $this->translator->trans('recurrent_jobs_search.alert_application_mimetype_error', ['%mimetype' => $uploadedTertiaryCvFile->getMimeType()]);
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters,
new Response(null, Response::HTTP_BAD_REQUEST)
);
}
}
if ($blacklistingService->isEmailBlacklistedForType(
trim(
mb_strtolower($form->getData()->getEmail())
),
Blacklisting::BLACKLISTING_TYPE_REGISTRATION
)) {
$renderParameters['errorMessage'] = 'Leider kannst du dich nicht über JOBOO!® bewerben. Kontaktiere uns gerne, falls hier ein Fehler vorliegt unter info@joboo.de';
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters
);
}
if (!is_null($user = $this->entityManager
->getRepository(User::class)
->findOneBy(['email' => trim(mb_strtolower($form->getData()->getEmail()))]))
&& $this->extendedApplicationBaseService->extendedApplicationFromJobseekerToRecurrentJobAlreadyExists(
$recurrentJob,
$user->getDefaultJobseekerProfile()
)
) {
$renderParameters['errorMessage'] = 'Du hast dich auf diesen Job bereits beworben. Es gibt noch viele andere interessante Jobs auf JOBOO!®';
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters
);
}
if (is_null($form->getData()->getFirstname())
|| is_null($form->getData()->getLastname())
|| is_null($form->getData()->getEmail())
|| (is_null($form->getData()->getPhone())
&& $extendedApplicationBaseService->phoneNumberForExtendedApplicationsMandatory($recurrentJob)
)
) {
$renderParameters['errorMessage'] = 'Bitte fülle alle Pflichtfelder der Bewerbung aus.';
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters,
new Response(null, Response::HTTP_BAD_REQUEST)
);
}
if (is_null($request->get(ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_CAMPAIGN_ID))
|| !in_array(
(int)$request->get(ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_CAMPAIGN_ID),
ConversionEventService::AVAILABLE_CAMPAIGN_IDS_FOR_INCOMING_TRAFFIC
)
) {
$campaignId = null;
} else {
$campaignId = (int)$request->get(ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_CAMPAIGN_ID);
}
$extendedApplication = $extendedApplicationBaseService->handleNewExtendedApplication(
$form->getData(),
$recurrentJob,
$uploadedPrimaryCvFile,
$uploadedSecondaryCvFile,
$uploadedTertiaryCvFile,
$this->getUser(),
$request,
$campaignId,
User::CREATED_VIA_JOBOO_RECURRENT_JOB_LANDINGPAGE,
PlatformSite::PLATFORM_SITE_ID_JOBOO,
$form
);
if (is_null($user)) {
$user = $extendedApplication->getJobseekerProfile()?->getUser();
}
if ($form->has('termsAndConditionsAccepted') && !is_null($user) && $form->get('termsAndConditionsAccepted')->getData()) {
$this->eventDispatcher->dispatch(
new UserTermsAndConditionsAcceptedEvent(
$user,
$recurrentJob
),
UserTermsAndConditionsAcceptedEvent::class
);
}
if (!is_null($this->getUser())) {
$this->addFlash('success', 'Deine Bewerbung wurde erfolgreich abgeschickt');
return $this->redirectToRoute(
'recurrent_jobs.share',
array_merge(
['recurrentJobId' => $recurrentJob->getId()],
$request->query->all()
),
Response::HTTP_SEE_OTHER
);
} else {
return $this->redirectToRoute(
'recurrent_jobs.share.extended_application.thanks',
[
'userId' => $extendedApplication->getJobseekerProfile()->getUser()->getId(),
'showTalentPixel' => ((int)$request->get(ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_CAMPAIGN_ID) === ConversionEventService::CAMPAIGN_ID_TALENTCOM)
],
Response::HTTP_SEE_OTHER
);
}
} else {
$renderParameters['errorMessage'] = $this->translator->trans('recurrent_jobs_search.alert_application_unknown_error');
return $this->render(
'recurrent_jobs/share/view.html.twig',
$renderParameters
);
}
} catch (Throwable $t) {
$this->logger->error($t->getMessage());
$this->addFlash(
'danger',
$this->translator->trans('recurrent_jobs_search.alert_application_unknown_error')
);
return $this->redirectToRoute('recurrent_jobs_search.form');
}
}
public function removeTrailingSlashAction(Request $request)
{
return $this->redirect(
$this->recurrentJobsShareService->removeTrailingSlash($request),
Response::HTTP_MOVED_PERMANENTLY
);
}
/** @throws Exception */
public function generatePrintTemplateFromRecurrentJobAction(string $recurrentJobId, Pdf $pdf, ConversionEventService $conversionEventService): Response
{
/** @var RecurrentJob $recurrentJob */
$recurrentJob = $this->entityManager->find(RecurrentJob::class, $recurrentJobId);
if (is_null($recurrentJob)) {
throw new Exception('No recurrent job found for id ' . $recurrentJobId . '.');
}
$html = $this->renderView('recurrent_jobs/print_template.html.twig', [
'recurrentJob' => $recurrentJob
]);
$pdf->setOption('enable-local-file-access', true);
$pdf->setOption('lowquality', false);
$pdf->setOption('encoding', 'UTF-8');
$pdf->setOption('margin-top', 5);
$pdf->setOption('margin-right', 5);
$pdf->setOption('margin-bottom', 5);
$pdf->setOption('margin-left', 5);
$content = $pdf->getOutputFromHtml($html);
$response = new Response();
$response->headers->set('Content-Type', 'application/pdf');
$response->headers->set(
'Content-Disposition',
'attachment;filename="'
. mb_substr(
urlencode(
$recurrentJob->getBusinessName()
. '-'
. $recurrentJob->getOccupationalFieldSearchterm()
. '-'
. $recurrentJob->getZipcode()
. '-'
. $recurrentJob->getCity()
),
0,
251
)
. '.pdf"'
);
$response->setContent($content);
$conversionEventService->handleConversionGoalReached(ConversionEventService::CAMPAIGN_ID_RECURRENT_JOBS_TO_PRINT_INFO_MAIL);
return $response;
}
/**
* @throws Exception
*/
private function getExtendedApplicationForm(
RecurrentJob $recurrentJob,
?User $user,
?Request $request,
ExtendedApplicationQuestionsDomainService $extendedApplicationQuestionsDomainService,
ExtendedApplicationCustomerService $extendedApplicationCustomerService
): ?FormInterface {
$extendedApplication = $this->extendedApplicationBaseService->prefillForm($user);
$jobseekerProfile = $extendedApplication->getJobseekerProfile();
if ($this->featureLimitationsService->recurrentJobMustDisplayExtendedApplicationForm($recurrentJob, $user)) {
$formOptions = [
'method' => Request::METHOD_POST,
'action' => $this->generateUrl(
'recurrent_jobs.share.extended_application.handle',
array_merge(
$request->query->all(),
[
'recurrentJobId' => $recurrentJob->getId(),
]
)
),
'cvForExtendedApplicationsMandatory' => (!is_null($this->getUser()) && !is_null($recurrentJob->getIntegratedExternalPartnerCustomer()) && $recurrentJob->getIntegratedExternalPartnerCustomer()->cvForExtendedApplicationsMandatory()),
'phoneNumberForExtendedApplicationsMandatory' => $this->extendedApplicationBaseService->phoneNumberForExtendedApplicationsMandatory($recurrentJob),
'extendedApplicationQuestions' => $extendedApplicationQuestionsDomainService->getActiveExtendedApplicationQuestionsForRecurrentJob($recurrentJob),
'isJoboo' => true,
'user' => $user,
'showTertiaryCvFile' => $extendedApplicationCustomerService->extendedApplicationForRecurrentJobMustShowTertiaryCvFile($recurrentJob),
'tertiaryCvFileConfig' => $extendedApplicationCustomerService->getTertiaryCvFileUploadFieldConfigurationForRecurrentJob($recurrentJob)
];
if (!is_null($jobseekerProfile) && !empty($jobseekerProfile->getDocumentFileName())) {
$formOptions['defaultCVFileName'] = $jobseekerProfile->getDocumentFileName();
}
return $this->recurrentJobsShareService->getExtendedApplicationForm($formOptions, $extendedApplication);
}
return null;
}
private function getHighlightedOccupationalField(Request $request): ?string
{
return !is_null($request->get('highlightedOccupationalFieldId', null))
? $this->entityManager->find(OccupationalField::class, (int)$request->get('highlightedOccupationalFieldId', null))
: null;
}
/** @throws Exception */
public function forwardToJobPostThatIsRecurrentJobAction(
Request $request,
string $recurrentJobId,
EntityManagerInterface $entityManager,
RecurrentJobService $recurrentJobService,
EventDispatcherInterface $eventDispatcher,
RouterHelperService $routerHelperService,
TranslatorInterface $translator,
ConversionEventService $conversionEventService,
BusinessEventDomainService $businessEventDomainService,
FeatureLimitationsService $featureLimitationsService
): Response {
if ($request->get('isMobileAppRequest') === true) {
$user = $entityManager->getRepository(User::class)->find($request->get('userId'));
} else {
/** @var ?User $user */
$user = $this->getUser();
}
GuidUtility::validOrThrow($recurrentJobId);
/** @var RecurrentJob $recurrentJob * */
$recurrentJob = $entityManager->getRepository(RecurrentJob::class)->find($recurrentJobId);
$disableForwardingPage = $request->get('disableDirectForwardingPage', false);
if (is_null($recurrentJob)) {
$this->logger->info(
"Tried to forward to job post that is recurrent job with id '$recurrentJobId', but the recurrent job not exist."
);
return new Response(null, Response::HTTP_NOT_FOUND);
}
if (!$recurrentJob->isActive()) {
return $this->redirect($routerHelperService->generate(
'recurrent_jobs.share',
['recurrentJobId' => $recurrentJob->getId()]
));
}
if (!is_null($request->get(ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_CAMPAIGN_ID))
&& !is_null($request->get(ConversionEventService::QUERY_STRING_PARAM_NAME_CONVERSION_SUBCAMPAIGN_ID))
&& !is_null($request->get('initiateConversionTracking'))
&& $request->get('initiateConversionTracking')
) {
$conversionEventService->initiateGoalReachedConversionTrackingBasedOnRequest($request);
}
$conversionEventService->handleRequest($request);
$conversionEventService->handleConversionGoalReached(ConversionEventService::CAMPAIGN_ID_INTEGRATED_EXTERNAL_PARTNER_CUSTOMER_PREMIUM_RADAR, 0, $request, $user, $recurrentJob);
$context = null;
if (!is_null($premiumRadarContext = $request->get('premiumRadarContext'))) {
$businessEventDomainService->writeNewEvent(BusinessEvent::EVENT_TYPE_INTEGRATED_EXTERNAL_PARTNER_CUSTOMER_PREMIUM_RADAR_LINK_CLICKED, $user, $recurrentJob, null, json_encode(['premiumRadarContext' => $premiumRadarContext, 'externalPartnerForwarding' => 'false', 'relatedWantedJobId' => $request->get('relatedWantedJobId')]));
$context = 'premiumRadar';
}
if (is_null($context)) {
$context = $request->get('request');
}
$conversionCampaignId = null;
if (!is_null($request->get('__ggctci'))) {
$conversionCampaignId = (int)$request->get('__ggctci');
}
$platformSiteId = PlatformSite::PLATFORM_SITE_ID_JOBOO;
if (!is_null($request->get('platformSite'))) {
if (in_array((int)$request->get('platformSite'), PlatformSite::AVAILABLE_PLATFORM_IDS)) {
$platformSiteId = (int)$request->get('platformSite');
}
}
$ctaTypeId = null;
if (!is_null($request->get('ctaTypeId'))) {
$ctaTypeId = (int)$request->get('ctaTypeId');
}
if ($recurrentJobService->recurrentJobMustLinkToSharePage(
$recurrentJob,
$conversionCampaignId,
$platformSiteId,
$ctaTypeId)) {
if ($this
->featureLimitationsService
->recurrentJobAlwaysForwardsToExternalJobPostInsteadOfShowingSharePage($recurrentJob)
) {
throw new Exception("Impossible situation: recurrent job '{$recurrentJob->getId()}' must link to share page AND always forwards to external job post instead of showing share page.");
}
return $this->redirect($routerHelperService->generate(
'recurrent_jobs.share',
array_merge(['recurrentJobId' => $recurrentJob->getId()], $request->query->all())
));
}
$redirectUrl = $recurrentJobService->getExternalRedirectUrlToBeForwardedTo($recurrentJob, $user, $conversionCampaignId, $platformSiteId, $ctaTypeId);
if (is_null($redirectUrl) || $redirectUrl === '') {
$this->addFlash('danger', $translator->trans('external_partners.forwarding_impossible'));
return $this->redirect($routerHelperService->generate(
'recurrent_jobs.share',
array_merge(['recurrentJobId' => $recurrentJob->getId()], $request->query->all())
));
} else {
if (!is_null($request->get('conversionCampaignId'))) {
if (in_array((int)$request->get('conversionCampaignId'), ConversionEventService::AVAILABLE_CAMPAIGN_IDS_FOR_INCOMING_TRAFFIC)) {
$conversionCampaignId = (int)$request->get('conversionCampaignId');
}
}
try {
if ($featureLimitationsService->userNeedsToSeeCaptchaBeforeForwardingToExternalJoboffer(
$request,
$conversionCampaignId
)) {
$businessEventDomainService->writeNewEvent(
BusinessEvent::EVENT_TYPE_USER_SEES_CAPTCHA_PAGE_BEFORE_FORWARDING,
$user,
$recurrentJob
);
return $this->render(
'recurrent_jobs/forwarding_page_captcha.html.twig',
[
'urlToForwardTo' => $this->routerHelperService->generate(
'recurrent_jobs.forward_to_external_job_post',
array_merge(
$request->query->all(),
[
'recurrentJobId' => $recurrentJobId
]
)
)
]
);
}
} catch (GuzzleException|ClientExceptionInterface $e) {
return $this->redirect($routerHelperService->generate(
'recurrent_jobs.share',
array_merge(['recurrentJobId' => $recurrentJob->getId()], $request->query->all())
));
}
$eventDispatcher->dispatch(
new RecurrentJobWillForwardToExternalUrlEvent(
$recurrentJob,
$user,
$context,
$request,
$conversionCampaignId,
$platformSiteId
),
RecurrentJobWillForwardToExternalUrlEvent::class
);
$redirectUrl = mb_ereg_replace('utm_source=j2w', 'utm_source=DEJoboo', $redirectUrl);
if (!$this->featureLimitationsService->recurrentJobMustAttachJobooUtmParameterToExternalForwardingUrl($recurrentJob)) {
$redirectUrl = mb_ereg_replace('\?utm_source=joboo&', '?', $redirectUrl);
$redirectUrl = mb_ereg_replace('\?utm_source=joboo', '', $redirectUrl);
$redirectUrl = mb_ereg_replace('&utm_source=joboo', '', $redirectUrl);
}
if ($disableForwardingPage) {
return $this->redirect($redirectUrl);
} else {
return $this->render(
'recurrent_jobs/forwarding_page.html.twig',
[
'urlToForwardTo' => $redirectUrl
]
);
}
}
}
/**
* @throws \Doctrine\DBAL\Exception
*/
public function showRecurrentJobsBelongingToJobooGmbhAction(RecurrentJobService $recurrentJobService): Response
{
$recurrentJobIds = $recurrentJobService->findAllRecurrentJobsBelongingToJobooGmbh();
$recurrentJobsToDisplay = [];
foreach ($recurrentJobIds as $recurrentJobId) {
/** @var RecurrentJob $recurrentJob */
$recurrentJob = $this->entityManager->find(RecurrentJob::class, $recurrentJobId);
if (!is_null($recurrentJob) && $recurrentJobService->recurrentJobBelongingToJobooGmbHCanGetDisplayed($recurrentJob)) {
$recurrentJobsToDisplay[] = $recurrentJob;
}
}
return $this->render(
'/recurrent_jobs/recurrent_jobs_belonging_to_joboo_gmbh.html.twig',
[
'recurrentJobs' => $recurrentJobsToDisplay
]
);
}
}