Skip to content
Snippets Groups Projects
JoblistController.php 26.7 KiB
Newer Older
<?php

namespace SGalinski\SgJobs\Controller;

/***************************************************************
 *  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!
 ***************************************************************/

use SGalinski\ProjectBase\Domain\Repository\CountryRepository;
use SGalinski\SgJobs\Controller\Ajax\UploadController;
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 SGalinski\SgSeo\Service\HeadTagService;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\Http\ImmediateResponseException;
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;
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\NoSuchArgumentException;
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
use TYPO3\CMS\Extbase\Property\Exception\TypeConverterException;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator;
use TYPO3\CMS\Extbase\Validation\Validator\GenericObjectValidator;
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
	public const ERROR_KEY_IN_POST = 'error';
	private const UPLOADED_FILES = [
		'coverLetter',
		'cv',
		'certificate',
	];

Stefan Galinski's avatar
Stefan Galinski committed
	protected $companyRepository;
Stefan Galinski's avatar
Stefan Galinski committed
	protected $jobRepository;
Stefan Galinski's avatar
Stefan Galinski committed
	protected $jobApplicationRepository;
Stefan Galinski's avatar
Stefan Galinski committed
	protected $departmentRepository;
	/**
	 * @var ExperienceLevelRepository
	 */
Stefan Galinski's avatar
Stefan Galinski committed
	protected $experienceLevelRepository;
Stefan Galinski's avatar
Stefan Galinski committed
	protected $fileAndFolderService;
	 * @param CompanyRepository $companyRepository
	public function injectCompanyRepository(CompanyRepository $companyRepository): void {
		$this->companyRepository = $companyRepository;
	/**
	 * Inject the CompanyRepository
	 *
	 * @param FileAndFolderService $fileAndFolderService
	 */
	public function injectFileAndFolderService(FileAndFolderService $fileAndFolderService): void {
		$this->fileAndFolderService = $fileAndFolderService;
	}

	 * @param DepartmentRepository $departmentRepository
	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
	 */
	public function injectJobApplicationRepository(JobApplicationRepository $jobApplicationRepository): void {
		$this->jobApplicationRepository = $jobApplicationRepository;
	}

	/**
	public function injectJobRepository(JobRepository $jobRepository): void {
		$this->jobRepository = $jobRepository;
	/**
	 * Initialize the indexAction to set the currentPageBrowserPage parameter
	 */
	public function initializeIndexAction(): void {
		$currentPageBrowserPage = GeneralUtility::_GP('tx_sgjobs_pagebrowser') ?
			(int) GeneralUtility::_GP('tx_sgjobs_pagebrowser')['currentPage'] : 0;
		if ($currentPageBrowserPage > 0) {
			$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
		}
	}

	/**
	 * Show all job offers and options to manage them
	 *
	 * @param array $filters
	 * @throws AspectNotFoundException
	 * @throws PageNotFoundException
Matthias Adrowski's avatar
Matthias Adrowski committed
	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;
				}
			}
		}

		$storagePid = (int) $this->configurationManager->getConfiguration(
			ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
		)['persistence']['storagePid'];
		$this->assignFilterValues($storagePid, $filters);
		$this->view->assign('recordPageId', $storagePid);
		$jobLimit = (int) $this->settings['jobLimit'];

		if ($jobId) {
			/** @var Job $job */
			$job = $this->jobRepository->findByUid($jobId);
			if (!$job) {
				throw new \InvalidArgumentException('Given Job Id is invalid!');
			}

			$headTagService = GeneralUtility::makeInstance(
				HeadTagService::class,
				TRUE,
				$job->getTitle(),
				$job->getDescription(),
				'&tx_sgjobs_jobapplication[jobId]=' . $jobId
			);
			$headTagService->execute();

			$numberOfPages = 1;
		} else {
			// pagination logic
			$offset = 0;
			if ($currentPageBrowserPage && $jobLimit) {
				$offset = $currentPageBrowserPage * $jobLimit;
			}

			$frontendPluginSettings = $this->configurationManager->getConfiguration(
				ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
			);
			$frontendPluginSettings = $frontendPluginSettings['settings'];

			// get all jobs for the current page
			$ordering = (int) $frontendPluginSettings['orderBy'];
			$jobs = $this->jobRepository->findJobsByFilter($filters, $jobLimit, $offset, $ordering)->toArray();

			// get all jobs for the current page
			$allJobs = $this->jobRepository->findJobsByFilter($filters)->toArray();
			$numberOfPages = (int) ($jobLimit <= 0 ? 0 : \ceil(\count($allJobs) / $jobLimit));
			if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) {
				/** @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('jobs2', 'just a job');
		$this->view->assign('limit', $jobLimit);
		$this->view->assign('numberOfPages', $numberOfPages);

		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
			return NULL;
		}
	 * Renders the application form with an optional job
	 * @param int|null $jobId
	 * @return ResponseInterface|null
	 * @throws AspectNotFoundException
	 * @throws StopActionException
	 * @throws SiteNotFoundException
Matthias Adrowski's avatar
Matthias Adrowski committed
	public function applyFormAction(
		JobApplication $applyData = NULL,
		string $error = '',
		int $jobId = NULL
			$this->view->assign('internalError', $error);
			$this->request->setArgument('error', NULL);
		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
			$folderName = \md5(\uniqid('sgjobs-', TRUE));
			$this->request->setArgument('folderName', $folderName);
		}
		$this->view->assign('folderName', $folderName);

		if ($jobId !== NULL) {
			$job = $this->jobRepository->findByUid($jobId);
				$headTagService = GeneralUtility::makeInstance(
					HeadTagService::class,
					FALSE,
					$job->getTitle(),
					$job->getDescription(),
					'&tx_sgjobs_jobapplication[jobId]=' . $jobId
				);
				$headTagService->execute();
			$enableAutomaticRelatedJobs = (bool) $this->settings['enableAutomaticRelatedJobs'];
			$automaticRelatedJobsLimit = (int) $this->settings['automaticRelatedJobsLimit'];
			if ($enableAutomaticRelatedJobs) {
				$relatedJobs = $this->jobRepository->findRelated($job, $automaticRelatedJobsLimit);
				$this->view->assign('relatedJobs', $relatedJobs);
			}
		} else {
			$storagePid = (int) $this->configurationManager->getConfiguration(
				ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
			)['persistence']['storagePid'];
			$this->view->assign('companies', $this->companyRepository->getAllCompanies($storagePid));
		// 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')) {
			$countryRepository = $this->objectManager->get(CountryRepository::class);
			$countries = $countryRepository->findAllOrderedByLanguage($site->getTwoLetterIsoCode());
		}
		$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) {
			/** @noinspection CallableParameterUseCaseInTypeContextInspection */
			$applyData = $this->objectManager->get(JobApplication::class);
			if ($job) {
				$applyData->setJobId($job->getJobId());
		$this->view->assign('applyData', $applyData);
		$this->view->assign('maxFileSize', $this->settings['allowedMaxFileSize']);
		$this->view->assign('maxFileSizeMb', ((int) $this->settings['allowedMaxFileSize'] / 1000) . ' MByte');
Matthias Adrowski's avatar
Matthias Adrowski committed
			'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->setArguments($arguments);
		}

		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
			return NULL;
		}
	/**
	 * Moves the application files from temporary to permanent storage
	 *
	 * @param JobApplication $applicationData
	 * @param string $folderName
	 * @return void
	protected function submitApplicationFiles(JobApplication $applicationData, string $folderName): void {
		$resourceFactory = $this->objectManager->get(ResourceFactory::class);
		$newName = \date('Ymd-His') . '_' . $applicationData->getJobId() . '-' . $applicationData->getFirstName()
			. '-' . $applicationData->getLastName();
		$storage = $resourceFactory->getStorageObject(1);
		$applicationFilePath = Environment::getPublicPath() . '/' . $storage->getConfiguration(
		)['basePath'] . 'JobApplication/' . $folderName .
			'/' . $newName . '.csv';
		$this->writeApplicationFile($applicationData, $applicationFilePath);
	}

Stefan Galinski's avatar
Stefan Galinski committed
	/**
	 * Pre-apply action setup, configures model-property mapping and handles file upload
	 *
	 * @throws NoSuchArgumentException
Stefan Galinski's avatar
Stefan Galinski committed
	 */
	protected function initializeApplyAction(): void {
Stefan Galinski's avatar
Stefan Galinski committed
		$propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration();
		$propertyMappingConfiguration->forProperty('job')->allowAllProperties();
		// remove the job validator
		/** @var ConjunctionValidator $validator */
		$validator = $this->arguments->getArgument('applyData')->getValidator();
		foreach ($validator->getValidators() as $subValidator) {
			/** @var GenericObjectValidator $subValidatorSub */
			foreach ($subValidator->getValidators() as $subValidatorSub) {
				$subValidatorSub->getPropertyValidators('job')->removeAll(
					$subValidatorSub->getPropertyValidators('job')
				);
			}
		}
	 * Saves the application send by the applyFormAction
	 *
	 * @param JobApplication $applyData
Stefan Galinski's avatar
Stefan Galinski committed
	 * @throws NoSuchArgumentException
	public function applyAction(JobApplication $applyData): ?ResponseInterface {
		$folderName = $this->request->getArgument('folderName');

			$job = $applyData->getJob();
			if ($job) {
				foreach ($job->getCompanies() as $company) {
					/** @var Company $company */
					$applyData->setCompany($company);
				}
			} elseif (!$applyData->getCompany()) {
				$company = $this->companyRepository->findByUid(
					(int) $_POST['tx_sgjobs_jobapplication']['applyData']['company']
				);
				if ($company) {
					$applyData->setCompany($company);
				}
			// look for a configured default job, in case of unsolicited application
			if ((!$job || $applyData->getJobId() === NULL) && $applyData->getCompany() !== NULL) {
				$applyData->setJobId($applyData->getCompany()->getJobId());
			if ($applyData->_isNew()) {
				$this->jobApplicationRepository->add($applyData);
			} else {
				$this->jobApplicationRepository->update($applyData);
			}

			$this->moveTmpFolder($folderName, $applyData);
			$this->submitApplicationFiles($applyData, $folderName);
			$mailService = $this->objectManager->get(
Matthias Adrowski's avatar
Matthias Adrowski committed
				MailTemplateService::class,
				'application_mail',
				'sg_jobs',
				$this->getApplicationMailMarkers($applyData)

			// set the pageId of the rootpage, otherwise the templates could be duplicated
			$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($GLOBALS['TSFE']->id);
			$mailService->setPid($site->getRootPageId());

			// get email from the job contact, fallback is TS settings
			$contact = NULL;
			if ($job !== NULL) {
				$contact = $job->getContact();
			}

			if ($contact !== NULL) {
				$mailService->setToAddresses($contact->getEmail());
				$company = $applyData->getCompany();
Stefan Galinski's avatar
Stefan Galinski committed
				if (($company !== NULL) && $company->getContact() !== NULL) {
					$mailService->setToAddresses($company->getContact()->getEmail());
Stefan Galinski's avatar
Stefan Galinski committed
			$mailService->setMarkers(
				[
					'application' => $applyData,
				]
			);
			$mailService->setIgnoreMailQueue(TRUE);

			// 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);
Stefan Galinski's avatar
Stefan Galinski committed

			$mailService->sendEmail();
			$redirectPageUid = (int) $this->settings['redirectPage'];
			if ($redirectPageUid) {
				$contentObject = $this->configurationManager->getContentObject();
				if ($contentObject) {
					$url = $contentObject->getTypoLink_URL($redirectPageUid);
					$this->redirectToUri($url);
				}
		} catch (\Exception $exception) {
			if ($exception instanceof StopActionException) {
			$job = $applyData->getJob();
			$jobId = $job !== NULL ? $job->getUid() : NULL;
			$this->request->setArgument('folderName', $folderName);
			$this->forward(
Matthias Adrowski's avatar
Matthias Adrowski committed
				'applyForm',
				NULL,
				NULL,
				['applyData' => $applyData, 'error' => $exception->getMessage(), 'jobId' => $jobId]

		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
			return NULL;
		}
	 * Assign filter values
	 *
	protected function assignFilterValues(int $rootPageId, array $filters = []): void {
		$countries = $this->companyRepository->getAllCountries($rootPageId, $filters['filterByLocation'] ?? []);
		$this->view->assign('countries', $countries);

		$cities = $this->companyRepository->getAllCities($rootPageId, $filters['filterByLocation'] ?? []);
		$companies = $this->companyRepository->getAllCompanyNames($rootPageId, $filters['filterByLocation'] ?? []);
		$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);
	 * Returns the application mail markers
	 *
	 * @param JobApplication $applyData
	 * @return array
	 */
	protected function getApplicationMailMarkers(JobApplication $applyData): array {
		$location = '';
		if ($applyData->getCompany() !== NULL) {
			$location = $applyData->getCompany()->getCity();
		}

		return [
			'salutation' => $applyData->getGender(),
			'firstname' => $applyData->getFirstName(),
			'lastname' => $applyData->getLastName(),
			'street' => $applyData->getStreet(),
			'city' => $applyData->getCity(),
			'country' => $applyData->getCountry(),
			'phone' => $applyData->getPhone(),
			'mobile' => $applyData->getMobile(),
			'email' => $applyData->getEmail(),
			'message' => $applyData->getFirstName()
	 * Writes the application files
	 *
	 * @param JobApplication $data
	 * @param string $filePath
	protected function writeApplicationFile(JobApplication $data, string $filePath): void {
		$coverLetter = '';
		$coverLetterObject = $data->getCoverLetter();
		if ($coverLetterObject) {
			$coverLetterObject = $coverLetterObject->getOriginalResource();
			if ($coverLetterObject) {
				$coverLetter = $coverLetterObject->getPublicUrl();
			}
		}

		$cv = '';
		$cvObject = $data->getCv();
		if ($cvObject) {
			$cvObject = $cvObject->getOriginalResource();
			if ($cvObject) {
				$cv = $cvObject->getPublicUrl();
			}
		}

		$certificate = '';
		$certificateObject = $data->getCertificate();
		if ($certificateObject) {
			$certificateObject = $certificateObject->getOriginalResource();
			if ($certificateObject) {
				$certificate = $certificateObject->getPublicUrl();
			}
		}

			$data->getFirstName(),
			$data->getLastName(),
			$data->getGender(),
			$data->getCountry(),
			$data->getBirthDate(),
			$data->getEducation(),
			$data->getStreet(),
			$data->getZip(),
			$data->getCity(),
			$data->getNationality(),
			$data->getPhone(),
			$data->getEmail(),
			$data->getMessage()
			GeneralUtility::mkdir_deep(\dirname($filePath));
			$file = \fopen($filePath, 'wb+');
			\fputcsv($file, $dataToInsertArr);
			\fclose($file);
		} catch (\RuntimeException $exception) {
			$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
	/**
	 * Move the temp folder to its proper location
	 *
	 * @param string $folderName
	 * @param JobApplication $applicationData
	 * @throws TypeConverterException
	 * @throws ExistingTargetFileNameException
	 * @throws ExistingTargetFolderException
	 * @throws InsufficientFolderAccessPermissionsException
	 * @throws InsufficientFolderReadPermissionsException
	 * @throws InsufficientFolderWritePermissionsException
	protected function moveTmpFolder(string $folderName, JobApplication $applicationData): void {
		$allowedFileExtensions = $this->getAllowedFileExtensions();

		/** @var ResourceFactory $resourceFactory */
		$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
		$storage = $resourceFactory->getStorageObject(1);
		$folder = $storage->getFolder(UploadController::JOB_APPLICATION_FOLDER);
		$tempFolder = $storage->getFolderInFolder(UploadController::JOB_APPLICATION_TEMP_FOLDER, $folder);
Stefan Galinski's avatar
Stefan Galinski committed
		if (!$storage->hasFolderInFolder($folderName, $folder)) {
			$newFolder = $storage->createFolder($folderName, $folder);
			$newFolder = $storage->getFolder(UploadController::JOB_APPLICATION_FOLDER . $folderName);

		// Move uploaded files & csv fo real folder and delete the tmp folder
		foreach (self::UPLOADED_FILES as $singleFilePostKey) {
			if (array_key_exists($singleFilePostKey, $_POST)) {
				foreach ($_POST[$singleFilePostKey] as $singleUploadedArr) {
					$filePathInfo = PathUtility::pathinfo($singleUploadedArr['path']);
					if (!GeneralUtility::inList($allowedFileExtensions, strtolower($filePathInfo['extension']))) {
							LocalizationUtility::translate('error.TypeConverterException.type', 'sg_jobs'),
							1399312430
					if (!$newFolder->hasFile($filePathInfo['basename'])) {
						/** @noinspection PhpUnreachableStatementInspection */
						$singleFileToMove = $storage->getFileInFolder($filePathInfo['basename'], $tempFolder);
						// when we reload etc. this image might already be moved.
						$usableFile = $storage->moveFile($singleFileToMove, $newFolder);
						/** @noinspection PhpUnreachableStatementInspection */
						$usableFile = $newFolder->getFile($filePathInfo['basename']);
					}

					$fileReference = $this->fileAndFolderService->createFileReferenceFromFalFileObject($usableFile);
					if ($singleFilePostKey === 'coverLetter') {
						$applicationData->setCoverLetter($fileReference);
					}
					if ($singleFilePostKey === 'cv') {
						$applicationData->setCV($fileReference);
					}
					if ($singleFilePostKey === 'certificate') {
						$applicationData->setCertificate($fileReference);
				throw new TypeConverterException(
					LocalizationUtility::translate(
						'error.TypeConverterException.missing.' . $singleFilePostKey,
						'sg_jobs'
					),
					1399312430
Stefan Galinski's avatar
Stefan Galinski committed

	/**
	 * returns currently set allowedFiles
	 *
	 * @return mixed
	 */
	protected function getAllowedFileExtensions() {
		return $this->settings['allowedFileExtensions'] ?? $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
	}

	/**
	 * Delete uploaded files in tmp folder
	 *
	 * @param string $folderName
	 */
	protected function deleteTmpFolder(string $folderName): void {
		/** @var ResourceFactory $resourceFactory */
		$resourceFactory = $this->objectManager->get(ResourceFactory::class);
		$storage = $resourceFactory->getStorageObject(1);
		try {
			$tempFolder = $storage->getFolder('/JobApplication/temp/' . $folderName);
			$storage->deleteFolder($tempFolder, TRUE);
Stefan Galinski's avatar
Stefan Galinski committed
		} catch (\Exception $exception) {
			// folder is already deleted for some reason
		}
	}

	/**
	 * If for any reason something goes wrong, delete the tmp upload folder
	 *
Stefan Galinski's avatar
Stefan Galinski committed
	 * @throws NoSuchArgumentException
	 */
	public function errorAction() {
		if ($this->request->hasArgument('folderName')) {
			$folderName = $this->request->getArgument('folderName');
			$this->deleteTmpFolder($folderName);
		}

		return parent::errorAction();
	 * @param string|NULL $html
	protected function htmlResponse(string $html = NULL): ResponseInterface {
		return $this->responseFactory->createResponse()
			->withHeader('Content-Type', 'text/html; charset=utf-8')
			->withBody($this->streamFactory->createStream($html ?? $this->view->render()));
	}