Newer
Older
<?php
/***************************************************************
* Copyright notice
*
* (c) sgalinski Internet Services (https://www.sgalinski.de)
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
namespace SGalinski\SgJobs\Controller;
Stefan Galinski
committed
use Psr\Http\Message\ResponseInterface;
use SGalinski\SgJobs\Controller\Ajax\UploadController;
Stefan Galinski
committed
use SGalinski\SgJobs\Domain\Model\Company;
use SGalinski\SgJobs\Domain\Model\Job;
use SGalinski\SgJobs\Domain\Model\JobApplication;
use SGalinski\SgJobs\Domain\Repository\CompanyRepository;
use SGalinski\SgJobs\Domain\Repository\DepartmentRepository;
use SGalinski\SgJobs\Domain\Repository\ExperienceLevelRepository;
use SGalinski\SgJobs\Domain\Repository\JobApplicationRepository;
use SGalinski\SgJobs\Domain\Repository\JobRepository;
use SGalinski\SgJobs\Service\FileAndFolderService;
use SGalinski\SgMail\Service\MailTemplateService;
use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationExtensionNotConfiguredException;
use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationPathDoesNotExistException;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Context\Context;
Stefan Galinski
committed
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Core\Environment;
Stefan Galinski
committed
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
Stefan Galinski
committed
use TYPO3\CMS\Core\Http\ImmediateResponseException;
Kevin Ditscheid
committed
use TYPO3\CMS\Core\Page\PageRenderer;
Stefan Galinski
committed
use TYPO3\CMS\Core\Resource\Exception\AbstractFileOperationException;
Stefan Galinski
committed
use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException;
use TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderReadPermissionsException;
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException;
Kevin von Spiczak
committed
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException;
use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException;
use TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException;
use TYPO3\CMS\Extbase\Property\Exception\TypeConverterException;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
Stefan Galinski
committed
use TYPO3\CMS\Frontend\Controller\ErrorController;
use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
/**
* The joblist plugin controller
*/
class JoblistController extends ActionController {
// the array key for the error message in the post-array
Stefan Galinski
committed
public const ERROR_KEY_IN_POST = 'error';
private const UPLOADED_FILES = [
'coverLetter',
'cv',
'certificate',
];
* @var CompanyRepository
Stefan Galinski
committed
* @var JobRepository
*/
/**
Stefan Galinski
committed
* @var JobApplicationRepository
Stefan Galinski
committed
* @var DepartmentRepository
*/
Stefan Galinski
committed
/**
* @var ExperienceLevelRepository
*/
/**
* @var FileAndFolderService
*/
Stefan Galinski
committed
public $jobFolderPath = 'JobApplication';
Stefan Galinski
committed
/**
* Inject the CompanyRepository
*
Stefan Galinski
committed
* @param CompanyRepository $companyRepository
*/
Stefan Galinski
committed
public function injectCompanyRepository(CompanyRepository $companyRepository): void {
$this->companyRepository = $companyRepository;
}
/**
* Inject the CompanyRepository
*
Stefan Galinski
committed
* @param FileAndFolderService $fileAndFolderService
*/
public function injectFileAndFolderService(FileAndFolderService $fileAndFolderService): void {
$this->fileAndFolderService = $fileAndFolderService;
}
/**
Stefan Galinski
committed
* Inject the DepartmentRepository
*
Stefan Galinski
committed
* @param DepartmentRepository $departmentRepository
Stefan Galinski
committed
public function injectDepartmentRepository(DepartmentRepository $departmentRepository): void {
$this->departmentRepository = $departmentRepository;
}
/**
* Inject the ExperienceLevelRepository
*
* @param ExperienceLevelRepository $experienceLevelRepository
*/
public function injectExperienceLevelRepository(ExperienceLevelRepository $experienceLevelRepository): void {
$this->experienceLevelRepository = $experienceLevelRepository;
}
* Inject the JobApplicationRepository
*
* @param JobApplicationRepository $jobApplicationRepository
*/
Stefan Galinski
committed
public function injectJobApplicationRepository(JobApplicationRepository $jobApplicationRepository): void {
$this->jobApplicationRepository = $jobApplicationRepository;
}
/**
Stefan Galinski
committed
* Inject the JobRepository
*
Stefan Galinski
committed
* @param JobRepository $jobRepository
*/
Stefan Galinski
committed
public function injectJobRepository(JobRepository $jobRepository): void {
$this->jobRepository = $jobRepository;
}
Stefan Galinski
committed
/**
* Initializes the class
*/
public function __construct() {
$extensionConfiguration = $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sg_jobs'] ?? [];
if (isset($extensionConfiguration['jobFolderPath']) && $extensionConfiguration['jobFolderPath'] !== '') {
$this->jobFolderPath = $extensionConfiguration['jobFolderPath'];
} else {
$this->jobFolderPath = 'JobApplication';
}
}
/**
* Make sure the upload folder & upload temp folder exists
*
* @return void
* @throws ExistingTargetFolderException
* @throws InsufficientFolderAccessPermissionsException
* @throws InsufficientFolderWritePermissionsException
*/
public function initializeAction(): void {
$storage = $this->fileAndFolderService->getStorage();
if (!$storage->hasFolder($this->jobFolderPath)) {
$storage->createFolder($this->jobFolderPath);
}
$tempFolderPath = $this->jobFolderPath . DIRECTORY_SEPARATOR . UploadController::JOB_APPLICATION_TEMP_FOLDER;
if (!$storage->hasFolder($tempFolderPath)) {
$storage->createFolder($tempFolderPath);
}
}
Kevin von Spiczak
committed
Stefan Galinski
committed
/**
* Initialize the indexAction to set the currentPageBrowserPage parameter
*/
Stefan Galinski
committed
public function initializeIndexAction(): void {
$currentPageBrowserPage = 0;
$parameters = $this->request->getQueryParams()['tx_sgjobs_pagebrowser'] ?? 0;
if (is_array($parameters)) {
$currentPageBrowserPage = (int) $parameters['currentPage'] ?: 0;
}
Stefan Galinski
committed
if ($currentPageBrowserPage > 0) {
$this->request = $this->request->withArgument('currentPageBrowserPage', $currentPageBrowserPage);
Stefan Galinski
committed
}
}
/**
* Show all job offers and options to manage them
*
Stefan Galinski
committed
* @param int|null $jobId
Stefan Galinski
committed
* @param int $currentPageBrowserPage
Stefan Galinski
committed
* @throws ImmediateResponseException
Stefan Galinski
committed
* @throws AspectNotFoundException
* @throws PageNotFoundException
public function indexAction(
array $filters = [],
int $jobId = NULL,
int $currentPageBrowserPage = 0
$this->view->assign('selectedCountry', $filters['filterCountry'] ?? '');
$this->view->assign('selectedCompany', $filters['filterCompany'] ?? '');
$this->view->assign('selectedLocation', $filters['filterLocation'] ?? '');
$this->view->assign('selectedDepartment', $filters['filterDepartment'] ?? '');
$this->view->assign('selectedExperienceLevel', $filters['filterExperienceLevel'] ?? '');
$this->view->assign('selectedFunction', $filters['filterFunction'] ?? '');
$this->view->assign('selectedRemote', $filters['filterRemote'] ?? '');
$filters['filterByDepartment'] = $this->settings['filterByDepartment'] ?? '';
$filters['filterByExperienceLevel'] = $this->settings['filterByExperienceLevel'] ?? '';
$filters['filterByLocation'] = $this->settings['filterByLocation'] ?? '';
foreach ($filters as $name => &$filter) {
if ($name === 'filterByLocation' || $name === 'filterByExperienceLevel' || $name === 'filterByDepartment') {
$filter = $filter ? GeneralUtility::trimExplode(',', $filter) : NULL;
if (!$filter) {
continue;
}
foreach ($filter as &$value) {
$value = (int) $value;
}
$storagePids = GeneralUtility::trimExplode(
',',
$this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
)['persistence']['storagePid']
);

Torsten Oppermann
committed
Kevin Ditscheid
committed
if ($currentPageBrowserPage > 0 && ExtensionManagementUtility::isLoaded('sg_seo')) {
$headTagService = GeneralUtility::makeInstance(
HeadTagService::class,
FALSE,
'',
'',
'&tx_sgjobs_pagebrowser[currentPage]=' . $currentPageBrowserPage
);
$headTagService->execute();
}
$this->assignFilterValues($storagePids, $filters);
$this->view->assign('recordPageIds', $storagePids);
$jobLimit = (int) $this->settings['jobLimit'];
/** @var Job $job */
$job = $this->jobRepository->findByUid($jobId);
if (!$job) {
throw new \InvalidArgumentException('Given Job Id is invalid!');
}
if (ExtensionManagementUtility::isLoaded('sg_seo')) {
$headTagService = GeneralUtility::makeInstance(
TRUE,
$job->getTitle(),
$job->getDescription(),
'&tx_sgjobs_jobapplication[jobId]=' . $jobId
);
$headTagService->execute();
}
$jobs = [$job];
$numberOfPages = 1;
} else {
// pagination logic
$offset = 0;
if ($currentPageBrowserPage && $jobLimit) {
$offset = $currentPageBrowserPage * $jobLimit;
}
Stefan Galinski
committed
$frontendPluginSettings = $this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
);
$frontendPluginSettings = $frontendPluginSettings['settings'];
Stefan Galinski
committed
$ordering = (int) $frontendPluginSettings['orderBy'];
Stefan Galinski
committed
$jobs = $this->jobRepository->findJobsByFilter($filters, $jobLimit, $offset, $ordering)->toArray();
$allJobsCount = $this->jobRepository->findJobsByFilter($filters)->count();
$numberOfPages = (int) ($jobLimit <= 0 ? 0 : \ceil($allJobsCount / $jobLimit));
if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) {
Kevin Ditscheid
committed
/** @var PageRenderer $pageRenderer */
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
// the PageRenderer contains the content of the current request, the result of the following sub-request will
// be appended to it and we get 2 pages, the current one and the 404 page in one. We flush the PageRenderer
// content here, so it will contain only the 404 page content
$pageRenderer->setBodyContent('');
Stefan Galinski
committed
/** @var ErrorController $errorController */
$errorController = GeneralUtility::makeInstance(ErrorController::class);
$response = $errorController->pageNotFoundAction(
$GLOBALS['TYPO3_REQUEST'],
'The requested page does not exist',
['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
);
throw new ImmediateResponseException($response);
}
$this->view->assign('jobs', $jobs);
$this->view->assign('limit', $jobLimit);
$this->view->assign('numberOfPages', $numberOfPages);
$this->view->assign('data', $this->request->getAttribute('currentContentObject')->data);
Stefan Galinski
committed
return $this->htmlResponse();
* Renders the application form with an optional job
Stefan Galinski
committed
* @param JobApplication|null $applyData
* @param string $error
Stefan Galinski
committed
* @param int|null $jobId
Stefan Galinski
committed
* @throws AspectNotFoundException
* @throws SiteNotFoundException
* @throws InvalidArgumentNameException
public function applyFormAction(
JobApplication $applyData = NULL,
string $error = '',
int $jobId = NULL
Stefan Galinski
committed
if ($error !== '') {
$this->view->assign('internalError', $error);
$this->request = $this->request->withArgument('error', NULL);
Sergiu-Lucian Petrica
committed
}
if ($jobId === NULL && $this->settings['disallowUnsolicitedApplication']) {
$uriBuilder = $this->uriBuilder;
$uri = $uriBuilder
->setTargetPageUid($this->settings['offersPage'])
->build();
$this->redirectToUri($uri, 0, 301);
}
$folderName = NULL;
try {
$folderName = $this->request->getArgument('folderName');
} catch (\Exception $exception) {
// this happens for the initial call, but works for any follow-up call as the form validation
// throws you back to this one if something has failed
if ($folderName === NULL) {
$folderName = \md5(\uniqid('sgjobs-', TRUE));
$this->request = $this->request->withArgument('folderName', $folderName);
}
$this->view->assign('folderName', $folderName);
$job = NULL;
/** @var Job $job */
Stefan Galinski
committed
$job = $this->jobRepository->findByUid($jobId);
if ($job) {
if (ExtensionManagementUtility::isLoaded('sg_seo')) {
$headTagService = GeneralUtility::makeInstance(
FALSE,
$job->getTitle(),
$job->getDescription(),
'&tx_sgjobs_jobapplication[jobId]=' . $jobId
);
$headTagService->execute();
}
$enableAutomaticRelatedJobs = (bool) $this->settings['enableAutomaticRelatedJobs'];
if ($enableAutomaticRelatedJobs) {
$automaticRelatedJobsLimit = (int) $this->settings['automaticRelatedJobsLimit'];
$relatedJobs = $this->jobRepository->findRelated($job, $automaticRelatedJobsLimit);
$this->view->assign('relatedJobs', $relatedJobs);
}
}
$this->view->assign('job', $job);
$storagePids = GeneralUtility::trimExplode(
',',
$this->configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
)['persistence']['storagePid']
);
$this->view->assign('companies', $this->companyRepository->getAllCompanies($storagePids));
// display country options
$context = GeneralUtility::makeInstance(Context::class);
$sysLanguageUid = $context->getPropertyFromAspect('language', 'id');
$site = GeneralUtility::makeInstance(SiteFinder::class)
->getSiteByPageId($GLOBALS['TSFE']->id)
->getLanguageById($sysLanguageUid);
$countries = [];
if (ExtensionManagementUtility::isLoaded('project_base')) {
$countryProvider = GeneralUtility::makeInstance(CountryProvider::class);
$countries = $countryProvider->getAll();
}
$this->view->assign('countries', $countries);
$this->view->assign('sysLanguageUid', $sysLanguageUid);
$allowedMimeTypes = $this->settings['allowedMimeTypes'];
$this->view->assign('allowedMimeTypes', $allowedMimeTypes);
$allowedFileExtensions = $this->settings['allowedFileExtensions'];
$this->view->assign('allowedFileExtensions', $allowedFileExtensions);
if ($applyData === NULL) {
/** @var JobApplication $applyData */
$applyData = GeneralUtility::makeInstance(JobApplication::class);
if ($job) {
$applyData->setJobId($job->getJobId());
}
}
$this->view->assign('isProjectBaseLoaded', ExtensionManagementUtility::isLoaded('project_base'));
$this->view->assign('applyData', $applyData);
$this->view->assign('maxFileSize', $this->settings['allowedMaxFileSize']);
$this->view->assign('maxFileSizeMb', ((int) $this->settings['allowedMaxFileSize'] / 1000) . ' MByte');
$this->view->assign(
'maxFileSizeMessage',
LocalizationUtility::translate('error.maxFileSizeMessage', 'sg_jobs')
// This fixes a bug in the form ViewHelper that wants to serialize a Model with closures in it
$arguments = $this->request->getArguments();
if (isset($arguments['applyData']) && $arguments['applyData']) {
$arguments['applyData'] = (string) $arguments['applyData'];
$this->request = $this->request->withArguments($arguments);
Stefan Galinski
committed
return $this->htmlResponse();
Stefan Galinski
committed
/**
Stefan Galinski
committed
*
* @param JobApplication $applicationData
* @param string $folderName
* @return void
*/
Stefan Galinski
committed
protected function createCsvSummary(JobApplication $applicationData, string $folderName): void {
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
Stefan Galinski
committed
$newName = \date('Ymd-His') . '_' . $applicationData->getJobId() . '-' . $applicationData->getFirstName()
. '-' . $applicationData->getLastName();
$storage = $resourceFactory->getStorageObject(1);
$applicationFilePath = Environment::getPublicPath() . '/' .
$storage->getConfiguration()['basePath'] . 'JobApplication/' . $folderName . '/' . $newName . '.csv';
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
$coverLetter = '';
$coverLetterObject = $applicationData->getCoverLetter();
if ($coverLetterObject) {
$coverLetterObject = $coverLetterObject->getOriginalResource();
if ($coverLetterObject) {
$coverLetter = $coverLetterObject->getPublicUrl();
}
}
$cv = '';
$cvObject = $applicationData->getCv();
if ($cvObject) {
$cvObject = $cvObject->getOriginalResource();
if ($cvObject) {
$cv = $cvObject->getPublicUrl();
}
}
$certificate = '';
$certificateObject = $applicationData->getCertificate();
if ($certificateObject) {
$certificateObject = $certificateObject->getOriginalResource();
if ($certificateObject) {
$certificate = $certificateObject->getPublicUrl();
}
}
$dataToInsertArr = [
$applicationData->getJobId(),
$applicationData->getFirstName(),
$applicationData->getLastName(),
$applicationData->getGender(),
$applicationData->getCountry(),
$applicationData->getBirthDate(),
$applicationData->getEducation(),
$applicationData->getStreet(),
$applicationData->getZip(),
$applicationData->getCity(),
$applicationData->getNationality(),
$applicationData->getPhone(),
$applicationData->getEmail(),
$coverLetter,
$cv,
$certificate,
$applicationData->getMessage()
];
try {
GeneralUtility::mkdir_deep(\dirname($applicationFilePath));
$file = \fopen($applicationFilePath, 'wb+');
\fputcsv($file, $dataToInsertArr);
\fclose($file);
} catch (\RuntimeException $exception) {
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
}
Stefan Galinski
committed
}
/**
* Pre-apply action setup, configures model-property mapping and handles file upload
*
* @throws NoSuchArgumentException
Stefan Galinski
committed
protected function initializeApplyAction(): void {
* Saves the application send by the applyFormAction
*
* @param JobApplication $applyData
* @throws ExtensionConfigurationExtensionNotConfiguredException
* @throws ExtensionConfigurationPathDoesNotExistException
public function applyAction(JobApplication $applyData): ResponseInterface {
$folderName = $this->request->getArgument('folderName');
$enableApplicantMail = (bool) GeneralUtility::makeInstance(ExtensionConfiguration::class)
->get('sg_jobs', 'enableApplicantMail');
Stefan Galinski
committed
if ($job) {
$applyData->setJobId($job->getJobId());
Kevin Ditscheid
committed
foreach ($job->getCompany() as $company) {
Stefan Galinski
committed
/** @var Company $company */
$applyData->setCompany($company);
}
Kevin Ditscheid
committed
} elseif (!$applyData->getFirstCompany()) {
/** @var Company $company */
$company = $this->companyRepository->findByUid(
(int) $_POST['tx_sgjobs_jobapplication']['applyData']['company']
);
if ($company) {
$applyData->setCompany($company);
}
Stefan Galinski
committed
}
// look for a configured default job, in case of unsolicited application
$applyData->setPid($GLOBALS['TSFE']->id);
Kevin Ditscheid
committed
if ((!$job || !$applyData->getJobId()) && $applyData->getFirstCompany()) {
$applyData->setJobId($applyData->getFirstCompany()->getJobId());
if ($applyData->_isNew()) {
$this->jobApplicationRepository->add($applyData);
} else {
$this->jobApplicationRepository->update($applyData);
}
$this->moveTmpFolder($folderName, $applyData);
Stefan Galinski
committed
$this->createCsvSummary($applyData, $folderName);
/** @var MailTemplateService $mailService */
$mailService = GeneralUtility::makeInstance(
MailTemplateService::class,
'application_mail',
'sg_jobs',
$this->getApplicationMailMarkers($applyData)
// set the pageId of the root page, otherwise the templates could be duplicated
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($GLOBALS['TSFE']->id);
$mailService->setPid($site->getRootPageId());

Torsten Oppermann
committed
/** @var MailTemplateService $applicantMailService */
$applicantMailService = GeneralUtility::makeInstance(
MailTemplateService::class,
'applicant_mail',
'sg_jobs',
$this->getApplicationMailMarkers($applyData)
);
$applicantMailService->setPid($site->getRootPageId());
}

Torsten Oppermann
committed
// get email from the job contact, fallback is TS settings

Torsten Oppermann
committed
if ($job !== NULL) {
$contact = $job->getContact();
}
if ($contact !== NULL) {
$mailService->setToAddresses($contact->getEmail());
} else {
Kevin Ditscheid
committed
$company = $applyData->getFirstCompany();
if (($company !== NULL) && $company->getContact() !== NULL) {
$mailService->setToAddresses($company->getContact()->getEmail());

Torsten Oppermann
committed
}
$mailService->setMarkers(
[
'application' => $applyData,
]
);
$mailService->setIgnoreMailQueue(TRUE);
$applicantMailService->setToAddresses($applyData->getEmail());
$applicantMailService->setIgnoreMailQueue(TRUE);
$applicantMailService->setMarkers(
[
'application' => $applyData,
]
);
}
// add attachments for each file
$coverLetter = $applyData->getCoverLetter();
if ($coverLetter) {
$mailService->addFileResourceAttachment($coverLetter);
$cv = $applyData->getCv();
if ($cv) {
$mailService->addFileResourceAttachment($cv);
$certificate = $applyData->getCertificate();
if ($certificate) {
$mailService->addFileResourceAttachment($certificate);
if ($enableApplicantMail) {
$applicantMailService->sendEmail();
}

Torsten Oppermann
committed
$redirectPageUid = (int) $this->settings['redirectPage'];
if ($redirectPageUid) {
$contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
Stefan Galinski
committed
if ($contentObject) {
$url = $contentObject->typoLink_URL(['params' => $redirectPageUid]);
Stefan Galinski
committed
$this->redirectToUri($url);
}
}

Torsten Oppermann
committed
$this->redirect('applyForm');
} catch (\Exception $exception) {

Torsten Oppermann
committed
$this->deleteTmpFolder($folderName);
$job = $applyData->getJob();
Kevin von Spiczak
committed
// remove application, since there was an exception (e.g. upload filetype mismatch @see: moveTmpFolder())
$this->jobApplicationRepository->remove($applyData);
$this->request = $this->request->withArgument('folderName', $folderName);
return (new ForwardResponse('applyForm'))->withArguments(
Kevin Ditscheid
committed
['applyData' => $applyData, 'error' => $exception->getMessage(), 'jobId' => $jobId]
Stefan Galinski
committed
return $this->htmlResponse();
Sergiu-Lucian Petrica
committed
}

Torsten Oppermann
committed
/**
* @param array $rootPageIds
Stefan Galinski
committed
* @throws AspectNotFoundException

Torsten Oppermann
committed
*/
protected function assignFilterValues(array $rootPageIds, array $filters = []): void {
$countries = $this->companyRepository->getAllCountries($rootPageIds, $filters['filterByLocation'] ?? []);

Torsten Oppermann
committed
$this->view->assign('countries', $countries);
$cities = $this->companyRepository->getAllCities($rootPageIds, $filters['filterByLocation'] ?? []);

Torsten Oppermann
committed
$this->view->assign('cities', $cities);
$companies = $this->companyRepository->getAllCompanyNames($rootPageIds, $filters['filterByLocation'] ?? []);

Torsten Oppermann
committed
$this->view->assign('companies', $companies);
$departments = $this->departmentRepository->findAllByFilter($filters['filterByDepartment'] ?? []);
$this->view->assign('departments', $departments);
$experienceLevels = $this->experienceLevelRepository->findAllByFilter(
$filters['filterByExperienceLevel'] ?? []
);
$this->view->assign('experienceLevels', $experienceLevels);

Torsten Oppermann
committed
}
* Returns the application mail markers
*
* @param JobApplication $applyData
Stefan Galinski
committed
protected function getApplicationMailMarkers(JobApplication $applyData): array {
$location = '';
Kevin Ditscheid
committed
if ($applyData->getFirstCompany() !== NULL) {
$location = $applyData->getFirstCompany()->getCity();
}
'salutation' => $applyData->getGender(),
'location' => $location,
'firstname' => $applyData->getFirstName(),
'lastname' => $applyData->getLastName(),
'street' => $applyData->getStreet(),
'city' => $applyData->getCity(),
'country' => $applyData->getCountry(),
'phone' => $applyData->getPhone(),
'mobile' => $applyData->getMobile(),
'email' => $applyData->getEmail(),
Kevin von Spiczak
committed
'message' => $applyData->getFirstName(),
'freetextField1' => $applyData->getFreetextField1(),
'freetextField2' => $applyData->getFreetextField2(),
'freetextField3' => $applyData->getFreetextField3(),
'freetextField4' => $applyData->getFreetextField4(),
'freetextField5' => $applyData->getFreetextField5()
/**
* Move the temp folder to its proper location
*
* @param string $folderName
Stefan Galinski
committed
* @param JobApplication $applicationData
* @throws ExistingTargetFileNameException
* @throws ExistingTargetFolderException
* @throws InsufficientFolderAccessPermissionsException
* @throws InsufficientFolderReadPermissionsException
* @throws InsufficientFolderWritePermissionsException
Stefan Galinski
committed
* @throws TypeConverterException
* @throws AbstractFileOperationException
protected function moveTmpFolder(string $folderName, JobApplication $applicationData): void {
$allowedFileExtensions = $this->getAllowedFileExtensions();
/** @var ResourceFactory $resourceFactory */
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1); // fileadmin
$newFolder = $tempFolder = NULL;
Stefan Galinski
committed
$folder = $storage->getFolder($this->jobFolderPath);
if ($folder) {
$tempFolder = $storage->getFolderInFolder(UploadController::JOB_APPLICATION_TEMP_FOLDER, $folder);
if (!$storage->hasFolderInFolder($folderName, $folder)) {
$newFolder = $storage->createFolder($folderName, $folder);
} else {
Stefan Galinski
committed
$newFolder = $storage->getFolder($this->jobFolderPath . $folderName);
}
}
if (!$newFolder || !$tempFolder) {
throw new \RuntimeException('Upload folder can\'t be created (write permissions?)!');
// Move uploaded files & csv fo real folder and delete the tmp folder
Stefan Galinski
committed
$uploadedFiles = [];
foreach (self::UPLOADED_FILES as $singleFilePostKey) {
if (!array_key_exists($singleFilePostKey, $_POST)) {
Stefan Galinski
committed
throw new TypeConverterException(
LocalizationUtility::translate(
'error.TypeConverterException.missing.' . $singleFilePostKey,
'sg_jobs'
),
1399312430
Stefan Galinski
committed
);
// get the first uploaded document, should be prevented in the frontend to upload more than one
$singleUploadedFile = current($_POST[$singleFilePostKey])['path'];
$filePathInfo = PathUtility::pathinfo($singleUploadedFile);
if (!GeneralUtility::inList($allowedFileExtensions, strtolower($filePathInfo['extension']))) {
throw new TypeConverterException(
LocalizationUtility::translate('error.TypeConverterException.type', 'sg_jobs'),
1399312430
);
}
$basename = $filePathInfo['basename'];
Stefan Galinski
committed
$newFilename = strtolower($singleFilePostKey) . '.' . strtolower($filePathInfo['extension']);
if (array_key_exists($singleUploadedFile, $uploadedFiles)) {
// the same file was uploaded for different sources
Kevin von Spiczak
committed
$usableFile = $this->getFileInFolder(
$uploadedFiles[$singleUploadedFile] . '.' . strtolower($filePathInfo['extension']),
$newFolder
Stefan Galinski
committed
);
if (!$usableFile) {
throw new \RuntimeException('File not found (' . $singleFilePostKey . ')!');
}
Stefan Galinski
committed
$usableFile = $storage->copyFile($usableFile, $newFolder, $newFilename);
} elseif (!$newFolder->hasFile($newFilename)) {
// when we reload, etc. this image might already be moved.
Stefan Galinski
committed
/** @noinspection PhpUnreachableStatementInspection */
$singleFileToMove = $storage->getFileInFolder($basename, $tempFolder);
$usableFile = $storage->moveFile($singleFileToMove, $newFolder, $newFilename);
} else {
/** @noinspection PhpUnreachableStatementInspection */
Kevin von Spiczak
committed
$usableFile = $this->getFileInFolder($newFilename, $newFolder);
$fileReference = $this->fileAndFolderService->createFileReferenceFromFalFileObject($usableFile);
if ($singleFilePostKey === 'coverLetter') {
$applicationData->setCoverLetter($fileReference);
}
if ($singleFilePostKey === 'cv') {
$applicationData->setCV($fileReference);
}
if ($singleFilePostKey === 'certificate') {
$applicationData->setCertificate($fileReference);
}
Stefan Galinski
committed
$uploadedFiles[$singleUploadedFile] = strtolower($singleFilePostKey);
Kevin von Spiczak
committed
/**
* Gets a file in a folder.
Kevin von Spiczak
committed
* @param string $fileName
* @param Folder $folder
Kevin von Spiczak
committed
*/
protected function getFileInFolder(string $fileName, Folder $folder): ?File {
Kevin von Spiczak
committed
}
*
* @return mixed
*/
protected function getAllowedFileExtensions() {
return $this->settings['allowedFileExtensions'] ?? $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
}

Torsten Oppermann
committed
/**
* Delete uploaded files in tmp folder
*
* @param string $folderName
*/
Stefan Galinski
committed
protected function deleteTmpFolder(string $folderName): void {

Torsten Oppermann
committed
/** @var ResourceFactory $resourceFactory */
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);

Torsten Oppermann
committed
$storage = $resourceFactory->getStorageObject(1);
try {
Stefan Galinski
committed
$tempFolder = $storage->getFolder('/JobApplication/' . $folderName);

Torsten Oppermann
committed
$storage->deleteFolder($tempFolder, TRUE);
// the folder is already deleted for some reason

Torsten Oppermann
committed
}
}
/**
* If for any reason something goes wrong, delete the tmp upload folder
*
Stefan Galinski
committed
* @return ResponseInterface

Torsten Oppermann
committed
*/
public function errorAction(): ResponseInterface {

Torsten Oppermann
committed
if ($this->request->hasArgument('folderName')) {
$folderName = $this->request->getArgument('folderName');
$this->deleteTmpFolder($folderName);
}

Torsten Oppermann
committed
}