Skip to content
Snippets Groups Projects
Commit 762062e7 authored by Stefan Galinski's avatar Stefan Galinski :video_game:
Browse files

[TASK] First bunch of file upload changes (real implementation instead of the fake)

parent 037848b8
No related branches found
No related tags found
No related merge requests found
......@@ -27,16 +27,16 @@ namespace SGalinski\SgJobs\Controller;
***************************************************************/
use SGalinski\SgJobs\Domain\Model\JobApplication;
use SGalinski\SgJobs\Property\TypeConverter\UploadedFileReferenceConverter;
use SGalinski\SgJobs\Service\FrontendFilterService;
use SGalinski\SgMail\Service\MailTemplateService;
use TYPO3\CMS\Core\Log\LogLevel;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration;
/**
* The joblist plugin controller
......@@ -59,7 +59,6 @@ class JoblistController extends ActionController {
*
* @param array $filters
* @return void
* @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
* @throws \InvalidArgumentException
*/
public function indexAction(array $filters = []) {
......@@ -134,33 +133,47 @@ class JoblistController extends ActionController {
* Pre-apply action setup, configures model-property mapping and handles file upload
*
* @return void
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException
* @throws \Exception
*/
protected function initializeApplyAction() {
$propertyMappingConfiguration = $this->arguments->getArgument('applyData')->getPropertyMappingConfiguration();
$propertyMappingConfiguration->forProperty('coverLetter')->allowAllProperties();
$propertyMappingConfiguration->forProperty('cv')->allowAllProperties();
$propertyMappingConfiguration->forProperty('certificates')->allowAllProperties();
$propertyMappingConfiguration->allowAllProperties();
if ($this->request->hasArgument('folderName')) {
$uniqueFolderName = $this->request->getArgument('folderName');
} else {
$uniqueFolderName = uniqid('sgjobs-', TRUE);
}
try {
$this->handleFileUpload('coverLetter', $uniqueFolderName);
$this->handleFileUpload('cv', $uniqueFolderName);
$this->handleFileUpload('certificates', $uniqueFolderName);
} catch (\Exception $exception) {
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
}
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1);
$storage->createFolder('/Extension/temp/' . $uniqueFolderName . '/coverLetter');
$storage->createFolder('/Extension/temp/' . $uniqueFolderName . '/cv');
$storage->createFolder('/Extension/temp/' . $uniqueFolderName . '/certificates');
$uploadConfiguration = [
UploadedFileReferenceConverter::CONFIGURATION_ALLOWED_FILE_EXTENSIONS => $this->settings['allowedFileExtensions'],
UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER => '1:/' . $uniqueFolderName,
];
/** @var PropertyMappingConfiguration $propertyMappingConfiguration */
$propertyMappingConfiguration = $this->arguments['applyData']->getPropertyMappingConfiguration();
$propertyMappingConfiguration->forProperty('coverLetter')
->setTypeConverterOptions(UploadedFileReferenceConverter::class, $uploadConfiguration);
$propertyMappingConfiguration->forProperty('cv')
->setTypeConverterOptions(UploadedFileReferenceConverter::class, $uploadConfiguration);
$propertyMappingConfiguration->forProperty('certificates')
->setTypeConverterOptions(UploadedFileReferenceConverter::class, $uploadConfiguration);
// try {
// $this->handleFileUpload('coverLetter', $uniqueFolderName);
// $this->handleFileUpload('cv', $uniqueFolderName);
// $this->handleFileUpload('certificates', $uniqueFolderName);
// } catch (\Exception $exception) {
// $this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
// }
$uploadedFiles = $this->getExistingApplicationFiles($uniqueFolderName);
$this->request->setArgument('uploadedFiles', $uploadedFiles);
......@@ -276,9 +289,9 @@ class JoblistController extends ActionController {
* @throws \Exception
*/
private function getExistingApplicationFiles($folder): array {
$files['coverLetter'] = $this->getExistingFiles('temp/' . $folder . '/coverLetter');
$files['coverLetter'] = $this->getExistingFiles('temp/' . $folder . '/');
$files['cv'] = $this->getExistingFiles('temp/' . $folder . '/cv');
$files['certificates'] = $this->getExistingFiles('temp/' . $folder . '/certificates');
$files['certificates'] = $this->getExistingFiles('temp/' . $folder . '/');
return $files;
}
......@@ -289,6 +302,8 @@ class JoblistController extends ActionController {
* @param JobApplication $applicationData
* @param string $folderName
* @return void
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException
* @throws \TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException
* @throws \TYPO3\CMS\Core\Exception
......@@ -381,81 +396,4 @@ class JoblistController extends ActionController {
$this->redirect('applyForm', NULL, NULL, ['error' => $exception->getMessage()]);
}
}
/**
* Registers an uploaded file for TYPO3 native upload handling.
*
* @param array &$data
* @param string $namespace
* @param string $fieldName
* @param string $targetDirectory
* @return void
*/
private function registerUploadField(array &$data, $namespace, $fieldName, $targetDirectory = '1:/_temp_/') {
if (!\is_array($_FILES[$namespace])) {
return;
}
if (!isset($data['upload'])) {
$data['upload'] = [];
}
$counter = \count($data['upload']) + 1;
$keys = array_keys($_FILES[$namespace]);
foreach ($keys as $key) {
$_FILES['upload_' . $counter][$key] = $_FILES[$namespace][$key]['applyData'][$fieldName];
}
$data['upload'][$counter] = [
'data' => $counter,
'target' => $targetDirectory,
];
}
/**
* @param string $fieldName
* @param string $folderName
* @return array
* @throws \UnexpectedValueException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderWritePermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
* @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFolderException
* @throws \Exception
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Core\Resource\Exception
*/
private function handleFileUpload($fieldName, $folderName): array {
$data = [];
$namespace = key($_FILES);
$resourceFactory = $this->objectManager->get(ResourceFactory::class);
$storage = $resourceFactory->getStorageObject(1);
if (!$storage->hasFolder('/Extension/temp/' . $folderName . '/' . $fieldName)) {
$storage->createFolder('/Extension/temp/' . $folderName . '/' . $fieldName);
}
$targetFalDirectory = '1:/Extension/temp/' . $folderName . '/' . $fieldName;
// Register every upload field from the form:
$this->registerUploadField($data, $namespace, $fieldName, $targetFalDirectory);
$fileProcessor = $this->objectManager->get(ExtendedFileUtility::class);
$fileProcessor->setActionPermissions(['addFile' => TRUE]);
$fileProcessor->setFileExtensionPermissions($this->settings['allowedFileExtensions'], '');
// Actual upload
$fileProcessor->start($data);
// This was previously passed as empty string, why and from where? It breaks the upload if it's not set.
$fileProcessor->setExistingFilesConflictMode(DuplicationBehavior::REPLACE);
$result = $fileProcessor->processData();
$uploadedFiles = [];
foreach ((array) $result['upload'] as $files) {
/** @var array $files */
foreach ($files as $file) {
$uploadedFiles[] = $file;
}
}
return $uploadedFiles;
}
}
<?php
namespace SGalinski\SgJobs\Domain\Model;
/***************************************************************
* Copyright notice
*
* (c) 2014 Helmut Hummel
*
* 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!
***************************************************************/
/**
* Class FileReference
*/
class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference {
/**
* Uid of a sys_file
*
* @var int
*/
protected $originalFileIdentifier;
/**
* @param \TYPO3\CMS\Core\Resource\ResourceInterface $originalResource
*/
public function setOriginalResource(\TYPO3\CMS\Core\Resource\ResourceInterface $originalResource) {
$this->setFileReference($originalResource);
}
/**
* @param \TYPO3\CMS\Core\Resource\FileReference $originalResource
*/
private function setFileReference(\TYPO3\CMS\Core\Resource\FileReference $originalResource) {
$this->originalResource = $originalResource;
$this->originalFileIdentifier = (int) $originalResource->getOriginalFile()->getUid();
}
}
......@@ -33,9 +33,8 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
* The JobApplication model
*/
class JobApplication extends AbstractEntity {
/**
* this is a sharepoint id. nothing from the db
* An internal id for external purposes
*
* @var string $jobId
* @validate NotEmpty
......@@ -120,19 +119,19 @@ class JobApplication extends AbstractEntity {
protected $email = '';
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $coverLetter
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage $coverLetter
*
*/
protected $coverLetter;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $cv
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage $cv
*
*/
protected $cv;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $certificates
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage $certificates
*
*/
protected $certificates;
......@@ -142,6 +141,9 @@ class JobApplication extends AbstractEntity {
*/
protected $message = '';
/**
* JobApplication constructor.
*/
public function __construct() {
$this->coverLetter = new ObjectStorage();
$this->cv = new ObjectStorage();
......
<?php
namespace SGalinski\SgJobs\Property\TypeConverter;
/***************************************************************
* Copyright notice
*
* (c) 2014 Helmut Hummel
*
* 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\Resource\DuplicationBehavior;
use TYPO3\CMS\Core\Resource\File as FalFile;
use TYPO3\CMS\Core\Resource\FileReference as FalFileReference;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Error\Error;
use TYPO3\CMS\Extbase\Property\Exception\TypeConverterException;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;
/**
* Class UploadedFileReferenceConverter
*/
class UploadedFileReferenceConverter extends AbstractTypeConverter {
/**
* Folder where the file upload should go to (including storage).
*/
const CONFIGURATION_UPLOAD_FOLDER = 1;
/**
* How to handle a upload when the name of the uploaded file conflicts.
*/
const CONFIGURATION_UPLOAD_CONFLICT_MODE = 2;
/**
* Whether to replace an already present resource.
* Useful for "maxitems = 1" fields and properties
* with no ObjectStorage annotation.
*/
const CONFIGURATION_ALLOWED_FILE_EXTENSIONS = 4;
/**
* @var string
*/
protected $defaultUploadFolder = '1:/user_upload/';
/**
* @var array<string>
*/
protected $sourceTypes = ['array'];
/**
* @var string
*/
protected $targetType = FileReference::class;
/**
* Take precedence over the available FileReferenceConverter
*
* @var int
*/
protected $priority = 30;
/**
* @var \TYPO3\CMS\Core\Resource\ResourceFactory
* @inject
*/
protected $resourceFactory;
/**
* @var \TYPO3\CMS\Extbase\Security\Cryptography\HashService
* @inject
*/
protected $hashService;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager
* @inject
*/
protected $persistenceManager;
/**
* @var \TYPO3\CMS\Core\Resource\FileInterface[]
*/
protected $convertedResources = [];
/**
* Actually convert from $source to $targetType, taking into account the fully
* built $convertedChildProperties and $configuration.
*
* @param string|int $source
* @param string $targetType
* @param array $convertedChildProperties
* @param \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration
* @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidHashException
* @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForHashGenerationException
* @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
* @return \TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder
* @api
* @throws \TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException
*/
public function convertFrom(
$source, $targetType, array $convertedChildProperties = [],
PropertyMappingConfigurationInterface $configuration = NULL
) {
if (!isset($source['error']) || $source['error'] === \UPLOAD_ERR_NO_FILE) {
if (isset($source['submittedFile']['resourcePointer'])) {
try {
$resourcePointer = $this->hashService->validateAndStripHmac(
$source['submittedFile']['resourcePointer']
);
if (strpos($resourcePointer, 'file:') === 0) {
$fileUid = substr($resourcePointer, 5);
return $this->createFileReferenceFromFalFileObject(
$this->resourceFactory->getFileObject($fileUid)
);
}
return $this->createFileReferenceFromFalFileReferenceObject(
$this->resourceFactory->getFileReferenceObject($resourcePointer), $resourcePointer
);
} catch (\InvalidArgumentException $e) {
// Nothing to do. No file is uploaded and resource pointer is invalid. Discard!
}
}
return NULL;
}
if ($source['error'] !== \UPLOAD_ERR_OK) {
switch ($source['error']) {
case \UPLOAD_ERR_INI_SIZE:
case \UPLOAD_ERR_FORM_SIZE:
case \UPLOAD_ERR_PARTIAL:
return new Error('Error Code: ' . $source['error'], 1264440823);
default:
return new Error(
'An error occurred while uploading. Please try again or contact the administrator if the problem remains',
1340193849
);
}
}
if (isset($this->convertedResources[$source['tmp_name']])) {
return $this->convertedResources[$source['tmp_name']];
}
try {
$resource = $this->importUploadedResource($source, $configuration);
} catch (\Exception $e) {
return new Error($e->getMessage(), $e->getCode());
}
$this->convertedResources[$source['tmp_name']] = $resource;
return $resource;
}
/**
* Import a resource and respect configuration given for properties
*
* @param array $uploadInfo
* @param PropertyMappingConfigurationInterface $configuration
* @return \TYPO3\CMS\Extbase\Domain\Model\FileReference
* @throws TypeConverterException
* @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForHashGenerationException
* @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidHashException
*/
protected function importUploadedResource(array $uploadInfo, PropertyMappingConfigurationInterface $configuration) {
if (!GeneralUtility::verifyFilenameAgainstDenyPattern($uploadInfo['name'])) {
throw new TypeConverterException('Uploading files with PHP file extensions is not allowed!', 1399312430);
}
$allowedFileExtensions = $configuration->getConfigurationValue(
UploadedFileReferenceConverter::class, self::CONFIGURATION_ALLOWED_FILE_EXTENSIONS
);
if ($allowedFileExtensions !== NULL) {
$filePathInfo = PathUtility::pathinfo($uploadInfo['name']);
if (!GeneralUtility::inList($allowedFileExtensions, strtolower($filePathInfo['extension']))) {
throw new TypeConverterException('File extension is not allowed!', 1399312430);
}
}
debug($uploadInfo);
$uploadFolderId = $configuration->getConfigurationValue(
UploadedFileReferenceConverter::class, self::CONFIGURATION_UPLOAD_FOLDER
) ?: $this->defaultUploadFolder;
if (class_exists(DuplicationBehavior::class)) {
$defaultConflictMode = \TYPO3\CMS\Core\Resource\DuplicationBehavior::RENAME;
}
$conflictMode = $configuration->getConfigurationValue(
UploadedFileReferenceConverter::class, self::CONFIGURATION_UPLOAD_CONFLICT_MODE
) ?: $defaultConflictMode;
$uploadFolder = $this->resourceFactory->retrieveFileOrFolderObject($uploadFolderId);
$uploadedFile = $uploadFolder->addUploadedFile($uploadInfo, $conflictMode);
$resourcePointer = isset($uploadInfo['submittedFile']['resourcePointer']) &&
strpos($uploadInfo['submittedFile']['resourcePointer'], 'file:') === FALSE
? $this->hashService->validateAndStripHmac($uploadInfo['submittedFile']['resourcePointer'])
: NULL;
$fileReferenceModel = $this->createFileReferenceFromFalFileObject($uploadedFile, $resourcePointer);
return $fileReferenceModel;
}
/**
* @param FalFile $file
* @param int $resourcePointer
* @return \SGalinski\SgJobs\Domain\Model\FileReference
*/
protected function createFileReferenceFromFalFileObject(FalFile $file, $resourcePointer = NULL) {
$fileReference = $this->resourceFactory->createFileReferenceObject(
[
'uid_local' => $file->getUid(),
'uid_foreign' => uniqid('NEW_', TRUE),
'uid' => uniqid('NEW_', TRUE),
'crop' => NULL,
]
);
return $this->createFileReferenceFromFalFileReferenceObject($fileReference, $resourcePointer);
}
/**
* @param FalFileReference $falFileReference
* @param int $resourcePointer
* @return \SGalinski\SgJobs\Domain\Model\FileReference
*/
protected function createFileReferenceFromFalFileReferenceObject(
FalFileReference $falFileReference, $resourcePointer = NULL
) {
if ($resourcePointer === NULL) {
$fileReference = $this->objectManager->get(FileReference::class);
} else {
$fileReference = $this->persistenceManager->getObjectByIdentifier(
$resourcePointer, FileReference::class, FALSE
);
}
$fileReference->setOriginalResource($falFileReference);
return $fileReference;
}
}
<?php
namespace SGalinski\SgJobs\ViewHelpers\Form;
/***************************************************************
* Copyright notice
*
* (c) 2014 Helmut Hummel <helmut.hummel@typo3.org>
* 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 2 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.
* A copy is found in the text file GPL.txt and important notices to the license
* from the author is found in LICENSE.txt distributed with these scripts.
*
*
* 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\Extbase\Domain\Model\FileReference;
/**
* Class UploadViewHelper
*/
class UploadViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\UploadViewHelper {
/**
* @var \TYPO3\CMS\Extbase\Security\Cryptography\HashService
* @inject
*/
protected $hashService;
/**
* @var \TYPO3\CMS\Extbase\Property\PropertyMapper
* @inject
*/
protected $propertyMapper;
/**
* Render the upload field including possible resource pointer
*
* @return string
* @api
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Extbase\Property\Exception
*/
public function render(): string {
$output = '';
$resource = $this->getUploadedResource();
if ($resource !== NULL) {
$resourcePointerIdAttribute = '';
if ($this->hasArgument('id')) {
$resourcePointerIdAttribute = ' id="' . htmlspecialchars($this->arguments['id']) . '-file-reference"';
}
$resourcePointerValue = $resource->getUid();
if ($resourcePointerValue === NULL) {
// Newly created file reference which is not persisted yet.
// Use the file UID instead, but prefix it with "file:" to communicate this to the type converter
$resourcePointerValue = 'file:' . $resource->getOriginalResource()->getOriginalFile()->getUid();
}
$output .= '<input type="hidden" name="' . $this->getName() .
'[submittedFile][resourcePointer]" value="' .
htmlspecialchars(
$this->hashService->appendHmac((string) $resourcePointerValue)
) . '"' . $resourcePointerIdAttribute . ' />';
$this->templateVariableContainer->add('resource', $resource);
$output .= $this->renderChildren();
$this->templateVariableContainer->remove('resource');
}
$output .= parent::render();
return $output;
}
/**
* Return a previously uploaded resource.
* Return NULL if errors occurred during property mapping for this property.
*
* @return FileReference|NULL
* @throws \TYPO3\CMS\Extbase\Property\Exception
*/
protected function getUploadedResource() {
if ($this->getMappingResultsForProperty()->hasErrors()) {
return NULL;
}
if (\is_callable([$this, 'getValueAttribute'])) {
$resource = $this->getValueAttribute();
}
if ($resource instanceof FileReference) {
return $resource;
}
return $this->propertyMapper->convert($resource, FileReference::class);
}
}
{namespace h=SGalinski\SgJobs\ViewHelpers}
<f:layout name="Default" />
<f:section name="main">
......@@ -173,17 +175,37 @@
</p>
<p>
<label for="apply-cover-letter"><f:translate key="frontend.apply.cover_letter" /></label>
<label for="apply-cover-letter">
<f:translate key="frontend.apply.cover_letter" />
<f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}
</label>
<f:form.upload multiple="true" property="coverLetter" id="apply-cover-letter" additionalAttributes="{accept: '{allowedMimeTypes}'}" />
<h:form.upload property="coverLetter" id="apply-cover-letter" additionalAttributes="{accept: '{allowedMimeTypes}'}" />
<f:comment><h:form.upload property="coverLetter.0">test</h:form.upload></f:comment>
<f:for each="{uploadedFiles.coverLetter}" as="file">
<div class="sg-jobs-uploaded-file">
<span class="filename">{file.name}</span>
<a href="#" filetype="coverLetter" class="remove-file">(remove)</a>
</div>
</f:for>
<f:comment>
<h:form.upload property="image" >
<f:if condition="{resource}">
<f:image image="{resource}" alt="" width="50"/>
</f:if>
</h:form.upload><br />
<label for="image_collection">
<f:translate key="tx_uploadexample_domain_model_example.image_collection" />
</label><br />
<h:form.upload property="imageCollection.0">
<f:if condition="{resource}">
<f:image image="{resource}" alt="" width="50"/>
</f:if>
</h:form.upload>
</f:comment>
<f:form.validationResults for="applyData.coverLetter">
<f:for each="{validationResults.errors}" as="error">
<div class="sg-jobs-validation-error">
......@@ -194,10 +216,11 @@
</p>
<p>
<label for="apply-cv"><f:translate key="frontend.apply.cv" /></label>
<label for="apply-cover-letter">
<f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}</label>
<f:form.upload multiple="true" property="cv" id="apply-cv" additionalAttributes="{accept: '{allowedMimeTypes}'}" />
<label for="apply-cv">
<f:translate key="frontend.apply.cv" />
<f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}
</label>
<h:form.upload property="cv" id="apply-cv" additionalAttributes="{accept: '{allowedMimeTypes}'}" />
<f:for each="{uploadedFiles.cv}" as="file">
<div class="sg-jobs-uploaded-file">
<span class="filename">{file.name}</span>
......@@ -214,10 +237,11 @@
</p>
<p>
<label for="apply-certificates"><f:translate key="frontend.apply.certificates" /></label>
<label for="apply-cover-letter">
<f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}</label>
<f:form.upload multiple="true" property="certificates" id="apply-certificates" additionalAttributes="{accept: '{allowedMimeTypes}'}" />
<label for="apply-certificates">
<f:translate key="frontend.apply.certificates" />
<f:translate key="frontend.apply.allowed_file_extensions" />{allowedFileExtensions}
</label>
<h:form.upload multiple="true" property="certificates" id="apply-certificates" additionalAttributes="{accept: '{allowedMimeTypes}'}" />
<f:for each="{uploadedFiles.certificates}" as="file">
<div class="sg-jobs-uploaded-file">
<span class="filename">{file.name}</span>
......
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