* merge master - allow to upload twig invoice templates via UI
* support adding existing teams with same name
* permissions cannot be set right after role was created - fixes #3777
* allow to deactivate unique customer number validation - fixes #3762 
* invalid message when trying to edit locked or exported timesheets in calendar - fixes #3766
* updated icons and manifest - fixes #3761
This commit is contained in:
Kevin Papst
2023-01-21 14:49:55 +01:00
committed by GitHub
parent b62253e1f3
commit a230be77dd
79 changed files with 428 additions and 358 deletions

View File

@@ -9,6 +9,7 @@
namespace App\Form;
use App\Configuration\SystemConfiguration;
use App\Repository\InvoiceDocumentRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
@@ -21,28 +22,45 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
final class InvoiceDocumentUploadForm extends AbstractType
{
public function __construct(private InvoiceDocumentRepository $repository)
public const EXTENSIONS = ['.html.twig', '.pdf.twig', '.docx', '.xlsx', '.ods'];
public const EXTENSIONS_NO_TWIG = ['.docx', '.xlsx', '.ods'];
public const FILENAME_RULE = 'Any-Latin; Latin-ASCII; [^A-Za-z0-9_\-] remove; Lower()';
/** @var array<string> */
private array $extensions = [];
public function __construct(private InvoiceDocumentRepository $repository, private SystemConfiguration $systemConfiguration)
{
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$this->extensions = self::EXTENSIONS_NO_TWIG;
$extensions = 'DOCX, ODS, XLSX';
$mimetypes = [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.oasis.opendocument.spreadsheet',
];
if ((bool) $this->systemConfiguration->find('invoice.upload_twig') === true) {
$this->extensions = self::EXTENSIONS;
$extensions = 'DOCX, ODS, XLSX, TWIG (PDF & HTML)';
$mimetypes = array_merge($mimetypes, [
'application/octet-stream', // needed for twig templates
'text/html', // needed for twig templates
'text/plain', // needed for twig templates
]);
}
$builder
->add('document', FileType::class, [
'label' => 'invoice_renderer',
'translation_domain' => 'invoice-renderer',
'help' => 'help.upload',
'help_translation_parameters' => ['%extensions%' => $extensions],
'mapped' => false,
'required' => true,
'attr' => [
'accept' => implode(',', $mimetypes)
],
'constraints' => [
new File([
'mimeTypes' => $mimetypes,
@@ -54,7 +72,7 @@ final class InvoiceDocumentUploadForm extends AbstractType
;
}
public function validateDocument($value, ExecutionContextInterface $context)
public function validateDocument($value, ExecutionContextInterface $context): void
{
if (!($value instanceof UploadedFile)) {
return;
@@ -71,6 +89,48 @@ final class InvoiceDocumentUploadForm extends AbstractType
->setTranslationDomain('validators')
->setCode('kimai-invoice-document-upload-01')
->addViolation();
return;
}
$extension = null;
$nameWithoutExtension = null;
foreach ($this->extensions as $ext) {
$len = \strlen($ext);
if (substr_compare($name, $ext, -$len) === 0) {
$extension = $ext;
$nameWithoutExtension = str_replace($ext, '', $name);
break;
}
}
if ($extension === null || $nameWithoutExtension === null) {
$context->buildViolation('This invoice document cannot be used, allowed file extensions are: %extensions%')
->setParameters(['%extensions%' => implode(', ', $this->extensions)])
->setTranslationDomain('validators')
->setCode('kimai-invoice-document-upload-02')
->addViolation();
return;
}
$safeFilename = transliterator_transliterate(self::FILENAME_RULE, $nameWithoutExtension);
if ($safeFilename !== $nameWithoutExtension) {
$context->buildViolation('This invoice document cannot be used, filename may only contain the following ascii character: %character%')
->setParameters(['%character%' => 'A-Z a-z 0-9 _ -'])
->setTranslationDomain('validators')
->setCode('kimai-invoice-document-upload-03')
->addViolation();
}
if (mb_strlen($nameWithoutExtension) > 20) {
$context->buildViolation('This invoice document cannot be used, allowed filename length without extension is %character% character.')
->setParameters(['%character%' => 20])
->setTranslationDomain('validators')
->setCode('kimai-invoice-document-upload-04')
->addViolation();
}
}