Skip to content
Snippets Groups Projects
Commit beb8fa84 authored by Matthias Adrowski's avatar Matthias Adrowski
Browse files

[TASK] Uploading works, but very wonky, lots of errors

parent 120a5f8c
No related branches found
No related tags found
1 merge request!37Feature new uploadhandling
......@@ -36,7 +36,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*/
class UploadController extends AbstractAjaxController {
public const TYPO3_TMP_FOLDER = 'typo3temp/';
public const TYPO3_TMP_FOLDER = '/JobApplication/temp/';
/**
* Returns the calculated max file size.
......@@ -86,7 +86,11 @@ class UploadController extends AbstractAjaxController {
$this->handleAnyDropZoneUpload();
}
/**
* since all files are handled the same way, we can use a single function!
*
* @return void
*/
private function handleAnyDropZoneUpload(){
$success = FALSE;
$filePath = '';
......@@ -102,7 +106,7 @@ class UploadController extends AbstractAjaxController {
)
);
$filePath = Environment::getPublicPath() . '/' . self::TYPO3_TMP_FOLDER . $fileName;
$filePath = Environment::getPublicPath() . '/fileadmin/' . self::TYPO3_TMP_FOLDER . $fileName;
$tempFilePath = $firstFile['tmp_name'];
$success = GeneralUtility::upload_copy_move($tempFilePath, $filePath);
}
......
......@@ -28,6 +28,7 @@ namespace SGalinski\SgJobs\Controller;
use Psr\Http\Message\ResponseInterface;
use SGalinski\ProjectBase\Domain\Repository\CountryRepository;
use SGalinski\SgComments\Domain\Model\Comment;
use SGalinski\SgJobs\Domain\Model\Company;
use SGalinski\SgJobs\Domain\Model\Job;
use SGalinski\SgJobs\Domain\Model\JobApplication;
......@@ -37,6 +38,7 @@ use SGalinski\SgJobs\Domain\Repository\ExperienceLevelRepository;
use SGalinski\SgJobs\Domain\Repository\JobApplicationRepository;
use SGalinski\SgJobs\Domain\Repository\JobRepository;
use SGalinski\SgJobs\Property\TypeConverter\UploadedFileReferenceConverter;
use SGalinski\SgJobs\Service\FileAndFolderService;
use SGalinski\SgMail\Service\MailTemplateService;
use SGalinski\SgSeo\Service\HeadTagService;
use TYPO3\CMS\Core\Context\Context;
......@@ -46,11 +48,14 @@ 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\Core\Utility\VersionNumberUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException;
use TYPO3\CMS\Extbase\Object\ObjectManager;
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;
......@@ -64,6 +69,12 @@ 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',
];
/**
* @var CompanyRepository
*/
......@@ -89,6 +100,11 @@ class JoblistController extends ActionController {
*/
protected $experienceLevelRepository;
/**
* @var FileAndFolderService
*/
protected $fileAndFolderService;
/**
* Inject the CompanyRepository
*
......@@ -98,6 +114,15 @@ class JoblistController extends ActionController {
$this->companyRepository = $companyRepository;
}
/**
* Inject the CompanyRepository
*
* @param CompanyRepository $companyRepository
*/
public function injectFileAndFolderService(FileAndFolderService $fileAndFolderService): void {
$this->fileAndFolderService = $fileAndFolderService;
}
/**
* Inject the DepartmentRepository
*
......@@ -198,7 +223,6 @@ class JoblistController extends ActionController {
);
$headTagService->execute();
$jobs = [$job];
$numberOfPages = 1;
} else {
......@@ -414,15 +438,15 @@ class JoblistController extends ActionController {
$propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration();
$propertyMappingConfiguration->forProperty('job')->allowAllProperties();
foreach (['coverLetter', 'cv', 'certificate'] as $property) {
$typeConverter = $this->objectManager->get(UploadedFileReferenceConverter::class);
$typeConverter->setAllowedFileExtensions(
$this->settings['allowedFileExtensions'] ?? $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
);
$typeConverter->setUploadFolder('1:/JobApplication/temp/' . $uniqueFolderName);
$typeConverter->setTargetUploadFileName($property);
$propertyMappingConfiguration->forProperty($property)->setTypeConverter($typeConverter);
}
// foreach (['coverLetter', 'cv', 'certificate'] as $property) {
// $typeConverter = $this->objectManager->get(UploadedFileReferenceConverter::class);
// $typeConverter->setAllowedFileExtensions(
// $this->settings['allowedFileExtensions'] ?? $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
// );
// $typeConverter->setUploadFolder('1:/JobApplication/temp/' . $uniqueFolderName);
// $typeConverter->setTargetUploadFileName($property);
// $propertyMappingConfiguration->forProperty($property)->setTypeConverter($typeConverter);
// }
// remove the job validator
/** @var ConjunctionValidator $validator */
......@@ -469,7 +493,7 @@ class JoblistController extends ActionController {
$this->jobApplicationRepository->update($applyData);
}
$this->moveTmpFolder($folderName);
$this->moveTmpFolder($folderName, $applyData);
$this->submitApplicationFiles($applyData, $folderName);
$mailService = $this->objectManager->get(
......@@ -550,20 +574,6 @@ class JoblistController extends ActionController {
}
}
/**
* Debug Action for us to check for all Data from form
*
*
*/
public function emptyAction(): ?\Psr\Http\Message\ResponseInterface {
$request = $this->request;
$arguments = $this->request->getArguments();
$parsedBody = $this->request->getParsedBody();
$uploadedFiles = $this->request->getUploadedFiles();
$basicBody = $this->request->getBody()->getContents();
return $this->htmlResponse('');
}
/**
* Assign filter values
*
......@@ -688,8 +698,11 @@ class JoblistController extends ActionController {
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException
*/
protected function moveTmpFolder(string $folderName): void {
// Move uploaded files & csv fo real folder and delete the tmp folder
protected function moveTmpFolder(string $folderName, JobApplication $applicationData): void {
$filePathInfo = [];
$namesToMove = [];
$allowedFileExtensions = $this->getAllowedFileExtensions();
/** @var ResourceFactory $resourceFactory */
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1);
......@@ -699,13 +712,57 @@ class JoblistController extends ActionController {
} else {
$newFolder = $storage->getFolder('/JobApplication/' . $folderName);
}
$tempFolder = $storage->getFolder('/JobApplication/temp/' . $folderName);
$filesToMove = $storage->getFilesInFolder($tempFolder);
foreach ($filesToMove as $fileToMove) {
$storage->moveFile($fileToMove, $newFolder);
$tempFolder = $storage->getFolder('/JobApplication/temp/');
// 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']);
$namesToMove[] = $filePathInfo['basename'];
if (!GeneralUtility::inList($allowedFileExtensions, strtolower($filePathInfo['extension']))) {
throw new TypeConverterException('File extension is not allowed!', 1399312430);
}
if(!$newFolder->hasFile($filePathInfo['basename'])) {
$singleFileToMove = $storage->getFileInFolder($filePathInfo['basename'], $tempFolder);
// when we reload etc this image might already be moved.
$usableFile = $storage->moveFile($singleFileToMove, $newFolder);
}
else {
$usableFile = $newFolder->getFile($filePathInfo['basename']);
}
$fileReference = $this->fileAndFolderService->createFileReferenceFromFalFileObject($usableFile);
if ($fileReference) {
// @todo: make this more dynamic
if ($singleFilePostKey === 'coverLetter') {
$applicationData->setCoverLetter($fileReference);
}
if ($singleFilePostKey === 'cv') {
$applicationData->setCV($fileReference);
}
if ($singleFilePostKey === 'certificate') {
$applicationData->setCertificate($fileReference);
}
}
continue;
}
} else {
throw new TypeConverterException('Missing file ' . $singleFilePostKey, 1399312430);
}
}
}
/**
* 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
*
......
......@@ -137,19 +137,16 @@ class JobApplication extends AbstractEntity {
/**
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference $coverLetter
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
*/
protected $coverLetter;
/**
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference $cv
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
*/
protected $cv;
/**
* @var \TYPO3\CMS\Extbase\Domain\Model\FileReference $certificate
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
*/
protected $certificate;
......
<?php
namespace SGalinski\SgJobs\Service;
/***************************************************************
* 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 TYPO3\CMS\Core\Charset\CharsetConverter;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Resource\File as FalFile;
use TYPO3\CMS\Core\Resource\FileReference as FalFileReference;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\ProcessedFile;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Resource\ResourceStorage;
use TYPO3\CMS\Core\Resource\StorageRepository;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\File\BasicFileUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
/**
* Service for diverse file operations
*/
class FileAndFolderService implements SingletonInterface {
/**
*
* @var ObjectManagerInterface
*/
protected $objectManager;
/**
* Inject the ObjectManager
*
* @param ObjectManagerInterface $objectManager
*/
public function injectObjectManager(ObjectManagerInterface $objectManager) {
$this->objectManager = $objectManager;
}
/**
*
* @var BasicFileUtility
*/
protected $fileUtility;
/**
* Inject the FileUtility
*
* @param BasicFileUtility $fileUtility
*/
public function injectFileUtility(BasicFileUtility $fileUtility) {
$this->fileUtility = $fileUtility;
}
/**
* @var ResourceFactory
*
*/
protected $resourceFactory;
/**
* Inject the ResourceFactory
*
* @param ResourceFactory $resourceFactory
*/
public function injectResourceFactory(ResourceFactory $resourceFactory) {
$this->resourceFactory = $resourceFactory;
}
/**
*
* @var StorageRepository
*/
protected $storageRepository;
/**
* Inject the StorageRepository
*
* @param StorageRepository $storageRepository
*/
public function injectStorageRepository(StorageRepository $storageRepository) {
$this->storageRepository = $storageRepository;
}
/**
*
* @var CharsetConverter
*/
protected $characterSetConverter;
/**
* Inject the CharacterSetConverter
*
* @param CharsetConverter $characterSetConverter
*/
public function injectCharacterSetConverter(CharsetConverter $characterSetConverter) {
$this->characterSetConverter = $characterSetConverter;
}
/**
* @var PersistenceManager
*
*/
protected $persistenceManager;
/**
* Inject the PersistenceManager
*
* @param PersistenceManager $persistenceManager
*/
public function injectPersistenceManager(PersistenceManager $persistenceManager) {
$this->persistenceManager = $persistenceManager;
}
/**
* @var array
*/
protected $allowedFileExtensionCache = [];
/**
* @var array
*/
protected $settings = [];
/**
* Method for uploading a file.
*
* @param string $temporaryFileName
* @param int $size
* @return string
*/
public function uploadFile($temporaryFileName, $size): string {
if ($size <= 0) {
return '';
}
$newFile = GeneralUtility::upload_to_tempfile($temporaryFileName);
GeneralUtility::fixPermissions($newFile);
return \basename($newFile);
}
/**
* Method for clean typo3temp from unused temporary files.
*
* @param string $name
* @return boolean
*/
public function removeTemporaryFile($name): bool {
$fileRemoved = FALSE;
if (\trim($name) !== '') {
$name = GeneralUtility::getFileAbsFileName('typo3temp/' . $name);
$fileRemoved = (bool) GeneralUtility::unlink_tempfile($name);
}
return $fileRemoved;
}
/**
* This method creates the fal folder.
*
* @param string $folderIdentifier
* @param int $storageUid
* @return Folder
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException
* @throws \Exception
*/
protected function createFolder($folderIdentifier, $storageUid): Folder {
/** @var ResourceStorage $storage */
$storage = $this->getStorage($storageUid);
return $storage->createFolder($folderIdentifier);
}
/**
* Returns a storage instance.
*
* @param int $storageUid
* @return ResourceStorage
*/
public function getStorage($storageUid = 1): ResourceStorage {
/** @var ResourceStorage $storage */
$storage = $this->storageRepository->findByUid($storageUid);
if (Environment::isCli() && $storage !== NULL) {
// if not set, the storage cannot access any folder in CLI mode (TYPO3 bug?)
$storage->setEvaluatePermissions(FALSE);
}
return $storage;
}
/**
* Returns an array with allowed file extensions.
*
* The types array can contain e.g. image or document and will be configured at
* plugin.tx_rsevents.settings.uploader in the typoscript.
*
* @param array $types
* @return array
*/
public function getAllowedFileExtensions(array $types = []): array {
$fileTypes = '';
$key = \md5(\implode('_', $types));
if (!isset($this->allowedFileExtensionCache[$key])) {
foreach ($types as $type) {
$type = \lcfirst($type . 'FileExtensions');
if (!\array_key_exists($type, $this->settings['rsUploader'])) {
continue;
}
if ($fileTypes !== '' && \substr($fileTypes, -1) !== ',') {
$fileTypes .= ',';
}
$fileTypes .= $this->settings['uploader'][$type];
}
$this->allowedFileExtensionCache[$key] = GeneralUtility::trimExplode(',', $fileTypes, TRUE);
}
return $this->allowedFileExtensionCache[$key];
}
/**
* Method create FAL records from the temporary files of the new impression. The new fileReferences will
* be attached to the new impression.
*
* @param array $fileInfo
* @param Folder $folder
* @return FalFile
*/
public function createFileRecords(array $fileInfo, Folder $folder): FalFile {
return $folder->addUploadedFile($fileInfo);
}
/**
* Returns the folder for the given folder identifier.
*
* @param string $folderIdentifier
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException
* @throws \InvalidArgumentException
* @throws \Exception
* @return Folder
* @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException
*/
public function getFolder($folderIdentifier): Folder {
/** @var ResourceStorage $storage */
$storage = $this->getStorage();
if ($storage->hasFolder($folderIdentifier)) {
return $storage->getFolder($folderIdentifier);
}
/** @var Folder $folder */
$folder = $storage->getFolder('sg_comments');
$this->createHtaccessFile($folder);
return $storage->createFolder($folderIdentifier);
}
/**
* Write a htaccess file to the folder with the appropriate settings
*
* @param Folder $folder
*/
private function createHtaccessFile($folder) {
$path = $folder->getPublicUrl();
$file = $path . '.htaccess';
$absolutePublicPath = Environment::getPublicPath();
$file = $absolutePublicPath.$file;
if (!\file_exists($file)) {
$current = '';
$allowedImageFileExtensions = 'png|gif|bmp|ico|jpeg|jpg|ps|psd|svg|tif|tiff|dds|pspimage|tga|';
$allowedVideoFileExtensions = '3g2|3gp|avi|flv|h264|m4v|mkv|mov|mp4|mpg|mpeg|rm|swf|vob|wmv|';
$allowedAudioFileExtensions = 'aif|cda|mid|midi|mp3|mpa|ogg|wav|wma|wpl';
$current .= <<<EOT
order allow,deny
<Files ~ "\.($allowedImageFileExtensions$allowedVideoFileExtensions$allowedAudioFileExtensions)$">
allow from all
</Files>
EOT;
\file_put_contents($file, $current);
}
}
/**
* Method the returns the given subfolder. The FAL core method throws an exception if the folder does not exists.
* And this method just create the folder.
*
* @param Folder $folder
* @param string $subfolderName
* @return Folder
* @throws \InvalidArgumentException
*/
public function getSubfolder(Folder $folder, $subfolderName): Folder {
if ($folder->hasFolder($subfolderName)) {
return $folder->getSubfolder($subfolderName);
}
return $folder->createFolder($subfolderName);
}
/**
* This creates a fal file reference object.
*
* @param FalFile $file
* @param int $resourcePointer
* @return FileReference
*/
public function createFileReferenceFromFalFileObject(FalFile $file, $resourcePointer = NULL): FileReference {
$fileReference = $this->resourceFactory->createFileReferenceObject(
[
'uid_local' => $file->getUid(),
'uid_foreign' => \uniqid('NEW_', TRUE),
'uid' => \uniqid('NEW_', TRUE),
]
);
return $this->createFileReferenceFromFalFileReferenceObject($fileReference, $resourcePointer);
}
/**
* This creates a file reference extbase object from a given fal file reference object.
*
* @param FalFileReference $falFileReference
* @param int $resourcePointer
* @return FileReference
*/
protected function createFileReferenceFromFalFileReferenceObject(
FalFileReference $falFileReference,
$resourcePointer = NULL
): FileReference {
if ($resourcePointer === NULL) {
/** @var FileReference $fileReference */
$fileReference = $this->objectManager->get(FileReference::class);
} else {
$fileReference = $this->persistenceManager->getObjectByIdentifier(
$resourcePointer,
FileReference::class,
FALSE
);
}
$fileReference->setOriginalResource($falFileReference);
return $fileReference;
}
/**
* Generate thumbnail image for the given file. This function creates a sub folder for the thumbnails if this is
* needed and attaches the processed new thumbnail file to this folder.
*
* @param FalFile $file
* @param Folder $folder
* @param array $uploadSettings
* @return FalFile
* @throws \InvalidArgumentException
*/
public function generateFileUploadThumbnail(FalFile $file, Folder $folder, array $uploadSettings): FalFile {
$thumbnailSettings = $uploadSettings['thumbnail'];
$thumbnailFolder = $this->getThumbnailFolder($folder, $thumbnailSettings);
$thumbnailFileName = $this->getThumbnailFileName($file, $thumbnailSettings);
$thumbnailConfig = [
'width' => $thumbnailSettings['resizeSettings']['width'],
'height' => $thumbnailSettings['resizeSettings']['height'],
'additionalParameters' => '-quality ' . $thumbnailSettings['resizeSettings']['quality']
];
return $thumbnailFolder->addFile(
$file->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $thumbnailConfig)->getPublicUrl(),
$thumbnailFileName,
'replace'
);
}
/**
* Returns name of a generated thumbnail.
*
* @param FalFile $file
* @param array $thumbnailSettings
* @return string
*/
public function getThumbnailFileName(FalFile $file, array $thumbnailSettings): string {
$thumbnailFileName = $file->getNameWithoutExtension() . '_' . $thumbnailSettings['prefix'];
$thumbnailFileName .= '.' . $file->getExtension();
return $thumbnailFileName;
}
/**
* Returns the thumbnail sub folder and creates the folder if no folder exists.
*
* @param Folder $folder
* @param array $thumbnailSettings
* @return Folder
* @throws \InvalidArgumentException
*/
public function getThumbnailFolder(Folder $folder, array $thumbnailSettings): Folder {
return $this->getSubfolder($folder, $thumbnailSettings['prefix']);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment