mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 01:25:55 +02:00
Applied symplify rules to codebase.
This commit is contained in:
parent
2f20d90041
commit
388e847b17
136 changed files with 1370 additions and 789 deletions
8
ecs.yaml
8
ecs.yaml
|
@ -6,5 +6,9 @@ parameters:
|
||||||
- "clean-code"
|
- "clean-code"
|
||||||
- "common"
|
- "common"
|
||||||
# very nice to have ↓
|
# very nice to have ↓
|
||||||
#- "symplify"
|
- "symplify"
|
||||||
- "symfony"
|
- "symfony"
|
||||||
|
|
||||||
|
skip:
|
||||||
|
Symplify\CodingStandard\Fixer\Naming\PropertyNameMatchingTypeFixer: ~
|
||||||
|
Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer: ~
|
|
@ -27,6 +27,9 @@ namespace App\Command;
|
||||||
use App\Services\Attachments\AttachmentManager;
|
use App\Services\Attachments\AttachmentManager;
|
||||||
use App\Services\Attachments\AttachmentPathResolver;
|
use App\Services\Attachments\AttachmentPathResolver;
|
||||||
use App\Services\Attachments\AttachmentReverseSearch;
|
use App\Services\Attachments\AttachmentReverseSearch;
|
||||||
|
use function count;
|
||||||
|
use const DIRECTORY_SEPARATOR;
|
||||||
|
use IntlDateFormatter;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Helper\Table;
|
use Symfony\Component\Console\Helper\Table;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
@ -83,11 +86,11 @@ class CleanAttachmentsCommand extends Command
|
||||||
|
|
||||||
$table = new Table($output);
|
$table = new Table($output);
|
||||||
$table->setHeaders(['Filename', 'MIME Type', 'Last modified date']);
|
$table->setHeaders(['Filename', 'MIME Type', 'Last modified date']);
|
||||||
$dateformatter = \IntlDateFormatter::create(null, \IntlDateFormatter::SHORT, \IntlDateFormatter::SHORT);
|
$dateformatter = IntlDateFormatter::create(null, IntlDateFormatter::SHORT, IntlDateFormatter::SHORT);
|
||||||
|
|
||||||
foreach ($finder as $file) {
|
foreach ($finder as $file) {
|
||||||
//If not attachment object uses this file, print it
|
//If not attachment object uses this file, print it
|
||||||
if (0 === \count($this->reverseSearch->findAttachmentsByFile($file))) {
|
if (0 === count($this->reverseSearch->findAttachmentsByFile($file))) {
|
||||||
$file_list[] = $file;
|
$file_list[] = $file;
|
||||||
$table->addRow([
|
$table->addRow([
|
||||||
$fs->makePathRelative($file->getPathname(), $mediaPath),
|
$fs->makePathRelative($file->getPathname(), $mediaPath),
|
||||||
|
@ -97,10 +100,10 @@ class CleanAttachmentsCommand extends Command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\count($file_list) > 0) {
|
if (count($file_list) > 0) {
|
||||||
$table->render();
|
$table->render();
|
||||||
|
|
||||||
$continue = $io->confirm(sprintf('Found %d abandoned files. Do you want to delete them? This can not be undone!', \count($file_list)), false);
|
$continue = $io->confirm(sprintf('Found %d abandoned files. Do you want to delete them? This can not be undone!', count($file_list)), false);
|
||||||
|
|
||||||
if (! $continue) {
|
if (! $continue) {
|
||||||
//We are finished here, when no files should be deleted
|
//We are finished here, when no files should be deleted
|
||||||
|
@ -128,7 +131,7 @@ class CleanAttachmentsCommand extends Command
|
||||||
protected function removeEmptySubFolders($path)
|
protected function removeEmptySubFolders($path)
|
||||||
{
|
{
|
||||||
$empty = true;
|
$empty = true;
|
||||||
foreach (glob($path.\DIRECTORY_SEPARATOR.'*') as $file) {
|
foreach (glob($path.DIRECTORY_SEPARATOR.'*') as $file) {
|
||||||
$empty &= is_dir($file) && $this->removeEmptySubFolders($file);
|
$empty &= is_dir($file) && $this->removeEmptySubFolders($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ use App\Entity\Parts\Supplier;
|
||||||
use App\Entity\PriceInformations\Currency;
|
use App\Entity\PriceInformations\Currency;
|
||||||
use App\Entity\UserSystem\Group;
|
use App\Entity\UserSystem\Group;
|
||||||
use App\Helpers\BBCodeToMarkdownConverter;
|
use App\Helpers\BBCodeToMarkdownConverter;
|
||||||
|
use function count;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
@ -49,9 +50,13 @@ use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||||
*/
|
*/
|
||||||
class ConvertBBCodeCommand extends Command
|
class ConvertBBCodeCommand extends Command
|
||||||
{
|
{
|
||||||
/** @var string The LIKE criteria used to detect on SQL server if a entry contains BBCode */
|
/**
|
||||||
|
* @var string The LIKE criteria used to detect on SQL server if a entry contains BBCode
|
||||||
|
*/
|
||||||
protected const BBCODE_CRITERIA = '%[%]%[/%]%';
|
protected const BBCODE_CRITERIA = '%[%]%[/%]%';
|
||||||
/** @var string The regex (performed in PHP) used to check if a property really contains BBCODE */
|
/**
|
||||||
|
* @var string The regex (performed in PHP) used to check if a property really contains BBCODE
|
||||||
|
*/
|
||||||
protected const BBCODE_REGEX = '/\\[.+\\].*\\[\\/.+\\]/';
|
protected const BBCODE_REGEX = '/\\[.+\\].*\\[\\/.+\\]/';
|
||||||
|
|
||||||
protected static $defaultName = 'app:convert-bbcode';
|
protected static $defaultName = 'app:convert-bbcode';
|
||||||
|
@ -125,7 +130,7 @@ class ConvertBBCodeCommand extends Command
|
||||||
|
|
||||||
//Fetch resulting classes
|
//Fetch resulting classes
|
||||||
$results = $qb->getQuery()->getResult();
|
$results = $qb->getQuery()->getResult();
|
||||||
$io->note(sprintf('Found %d entities, that need to be converted!', \count($results)));
|
$io->note(sprintf('Found %d entities, that need to be converted!', count($results)));
|
||||||
|
|
||||||
//In verbose mode print the names of the entities
|
//In verbose mode print the names of the entities
|
||||||
foreach ($results as $result) {
|
foreach ($results as $result) {
|
||||||
|
|
|
@ -25,7 +25,10 @@ declare(strict_types=1);
|
||||||
namespace App\Command;
|
namespace App\Command;
|
||||||
|
|
||||||
use App\Entity\PriceInformations\Currency;
|
use App\Entity\PriceInformations\Currency;
|
||||||
|
use function count;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Exchanger\Exception\Exception;
|
||||||
|
use function strlen;
|
||||||
use Swap\Builder;
|
use Swap\Builder;
|
||||||
use Swap\Swap;
|
use Swap\Swap;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
@ -70,7 +73,7 @@ class UpdateExchangeRatesCommand extends Command
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
//Check for valid base current
|
//Check for valid base current
|
||||||
if (3 !== \strlen($this->base_current)) {
|
if (3 !== strlen($this->base_current)) {
|
||||||
$io->error('Choosen Base current is not valid. Check your settings!');
|
$io->error('Choosen Base current is not valid. Check your settings!');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -108,15 +111,15 @@ class UpdateExchangeRatesCommand extends Command
|
||||||
$this->em->persist($currency);
|
$this->em->persist($currency);
|
||||||
|
|
||||||
++$success_counter;
|
++$success_counter;
|
||||||
} catch (\Exchanger\Exception\Exception $ex) {
|
} catch (Exception $exception) {
|
||||||
$io->warning(sprintf('Error updating %s:', $currency->getIsoCode()));
|
$io->warning(sprintf('Error updating %s:', $currency->getIsoCode()));
|
||||||
$io->warning($ex->getMessage());
|
$io->warning($exception->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save to database
|
//Save to database
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
|
|
||||||
$io->success(sprintf('%d (of %d) currency exchange rates were updated.', $success_counter, \count($candidates)));
|
$io->success(sprintf('%d (of %d) currency exchange rates were updated.', $success_counter, count($candidates)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,12 @@ namespace App\Configuration;
|
||||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||||
|
|
||||||
class PermissionsConfiguration implements ConfigurationInterface
|
final class PermissionsConfiguration implements ConfigurationInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Generates the configuration tree builder.
|
* Generates the configuration tree builder.
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
|
* @return TreeBuilder The tree builder
|
||||||
*/
|
*/
|
||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
@ -49,7 +50,7 @@ class AttachmentTypeController extends BaseAdminController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}", name="attachment_type_delete", methods={"DELETE"})
|
* @Route("/{id}", name="attachment_type_delete", methods={"DELETE"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function delete(Request $request, AttachmentType $entity, StructuralElementRecursionHelper $recursionHelper)
|
public function delete(Request $request, AttachmentType $entity, StructuralElementRecursionHelper $recursionHelper)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,6 +36,7 @@ use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use InvalidArgumentException;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
@ -61,11 +62,11 @@ abstract class BaseAdminController extends AbstractController
|
||||||
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler)
|
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler)
|
||||||
{
|
{
|
||||||
if ('' === $this->entity_class || '' === $this->form_class || '' === $this->twig_template || '' === $this->route_base) {
|
if ('' === $this->entity_class || '' === $this->form_class || '' === $this->twig_template || '' === $this->route_base) {
|
||||||
throw new \InvalidArgumentException('You have to override the $entity_class, $form_class, $route_base and $twig_template value in your subclasss!');
|
throw new InvalidArgumentException('You have to override the $entity_class, $form_class, $route_base and $twig_template value in your subclasss!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('' === $this->attachment_class) {
|
if ('' === $this->attachment_class) {
|
||||||
throw new \InvalidArgumentException('You have to override the $attachment_class value in your subclass!');
|
throw new InvalidArgumentException('You have to override the $attachment_class value in your subclass!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
|
@ -101,10 +102,10 @@ abstract class BaseAdminController extends AbstractController
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
$this->attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
||||||
} catch (AttachmentDownloadException $ex) {
|
} catch (AttachmentDownloadException $attachmentDownloadException) {
|
||||||
$this->addFlash(
|
$this->addFlash(
|
||||||
'error',
|
'error',
|
||||||
$this->translator->trans('attachment.download_failed').' '.$ex->getMessage()
|
$this->translator->trans('attachment.download_failed').' '.$attachmentDownloadException->getMessage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,10 +159,10 @@ abstract class BaseAdminController extends AbstractController
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
$this->attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
||||||
} catch (AttachmentDownloadException $ex) {
|
} catch (AttachmentDownloadException $attachmentDownloadException) {
|
||||||
$this->addFlash(
|
$this->addFlash(
|
||||||
'error',
|
'error',
|
||||||
$this->translator->trans('attachment.download_failed').' '.$ex->getMessage()
|
$this->translator->trans('attachment.download_failed').' '.$attachmentDownloadException->getMessage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,8 +187,12 @@ abstract class BaseAdminController extends AbstractController
|
||||||
$file = $import_form['file']->getData();
|
$file = $import_form['file']->getData();
|
||||||
$data = $import_form->getData();
|
$data = $import_form->getData();
|
||||||
|
|
||||||
$options = ['parent' => $data['parent'], 'preserve_children' => $data['preserve_children'],
|
$options = [
|
||||||
'format' => $data['format'], 'csv_separator' => $data['csv_separator'], ];
|
'parent' => $data['parent'],
|
||||||
|
'preserve_children' => $data['preserve_children'],
|
||||||
|
'format' => $data['format'],
|
||||||
|
'csv_separator' => $data['csv_separator'],
|
||||||
|
];
|
||||||
|
|
||||||
$errors = $importer->fileToDBEntities($file, $this->entity_class, $options);
|
$errors = $importer->fileToDBEntities($file, $this->entity_class, $options);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
@ -49,7 +50,7 @@ class CategoryController extends BaseAdminController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}", name="category_delete", methods={"DELETE"})
|
* @Route("/{id}", name="category_delete", methods={"DELETE"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function delete(Request $request, Category $entity, StructuralElementRecursionHelper $recursionHelper)
|
public function delete(Request $request, Category $entity, StructuralElementRecursionHelper $recursionHelper)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
@ -51,7 +52,7 @@ class CurrencyController extends BaseAdminController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}", name="currency_delete", methods={"DELETE"})
|
* @Route("/{id}", name="currency_delete", methods={"DELETE"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function delete(Request $request, Currency $entity, StructuralElementRecursionHelper $recursionHelper)
|
public function delete(Request $request, Currency $entity, StructuralElementRecursionHelper $recursionHelper)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
@ -49,7 +50,7 @@ class DeviceController extends BaseAdminController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}", name="device_delete", methods={"DELETE"})
|
* @Route("/{id}", name="device_delete", methods={"DELETE"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function delete(Request $request, Device $entity, StructuralElementRecursionHelper $recursionHelper)
|
public function delete(Request $request, Device $entity, StructuralElementRecursionHelper $recursionHelper)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,10 +28,14 @@ use App\DataTables\AttachmentDataTable;
|
||||||
use App\Entity\Attachments\Attachment;
|
use App\Entity\Attachments\Attachment;
|
||||||
use App\Entity\Attachments\PartAttachment;
|
use App\Entity\Attachments\PartAttachment;
|
||||||
use App\Services\Attachments\AttachmentManager;
|
use App\Services\Attachments\AttachmentManager;
|
||||||
|
use Exception;
|
||||||
use Omines\DataTablesBundle\DataTableFactory;
|
use Omines\DataTablesBundle\DataTableFactory;
|
||||||
|
use RuntimeException;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
@ -49,11 +53,11 @@ class AttachmentFileController extends AbstractController
|
||||||
$this->denyAccessUnlessGranted('read', $attachment);
|
$this->denyAccessUnlessGranted('read', $attachment);
|
||||||
|
|
||||||
if ($attachment->isExternal()) {
|
if ($attachment->isExternal()) {
|
||||||
throw new \RuntimeException('You can not download external attachments!');
|
throw new RuntimeException('You can not download external attachments!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $helper->isFileExisting($attachment)) {
|
if (! $helper->isFileExisting($attachment)) {
|
||||||
throw new \RuntimeException('The file associated with the attachment is not existing!');
|
throw new RuntimeException('The file associated with the attachment is not existing!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$file_path = $helper->toAbsoluteFilePath($attachment);
|
$file_path = $helper->toAbsoluteFilePath($attachment);
|
||||||
|
@ -72,18 +76,18 @@ class AttachmentFileController extends AbstractController
|
||||||
*
|
*
|
||||||
* @return BinaryFileResponse
|
* @return BinaryFileResponse
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function view(Attachment $attachment, AttachmentManager $helper)
|
public function view(Attachment $attachment, AttachmentManager $helper)
|
||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted('read', $attachment);
|
$this->denyAccessUnlessGranted('read', $attachment);
|
||||||
|
|
||||||
if ($attachment->isExternal()) {
|
if ($attachment->isExternal()) {
|
||||||
throw new \RuntimeException('You can not download external attachments!');
|
throw new RuntimeException('You can not download external attachments!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $helper->isFileExisting($attachment)) {
|
if (! $helper->isFileExisting($attachment)) {
|
||||||
throw new \RuntimeException('The file associated with the attachment is not existing!');
|
throw new RuntimeException('The file associated with the attachment is not existing!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$file_path = $helper->toAbsoluteFilePath($attachment);
|
$file_path = $helper->toAbsoluteFilePath($attachment);
|
||||||
|
@ -98,7 +102,7 @@ class AttachmentFileController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/attachment/list", name="attachment_list")
|
* @Route("/attachment/list", name="attachment_list")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function attachmentsTable(DataTableFactory $dataTable, Request $request)
|
public function attachmentsTable(DataTableFactory $dataTable, Request $request)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,7 @@ use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
@ -72,7 +73,7 @@ class GroupController extends BaseAdminController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}", name="group_delete", methods={"DELETE"})
|
* @Route("/{id}", name="group_delete", methods={"DELETE"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function delete(Request $request, Group $entity, StructuralElementRecursionHelper $recursionHelper)
|
public function delete(Request $request, Group $entity, StructuralElementRecursionHelper $recursionHelper)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use App\Services\GitVersionInfo;
|
use App\Services\GitVersionInfo;
|
||||||
|
use const DIRECTORY_SEPARATOR;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
@ -46,7 +47,7 @@ class HomepageController extends AbstractController
|
||||||
$banner = $this->getParameter('banner');
|
$banner = $this->getParameter('banner');
|
||||||
if (empty($banner)) {
|
if (empty($banner)) {
|
||||||
$banner_path = $this->kernel->getProjectDir()
|
$banner_path = $this->kernel->getProjectDir()
|
||||||
.\DIRECTORY_SEPARATOR.'config'.\DIRECTORY_SEPARATOR.'banner.md';
|
.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'banner.md';
|
||||||
|
|
||||||
return file_get_contents($banner_path);
|
return file_get_contents($banner_path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,9 @@ use App\Services\PricedetailHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
@ -48,7 +50,7 @@ class PartController extends AbstractController
|
||||||
* @Route("/{id}/info", name="part_info")
|
* @Route("/{id}/info", name="part_info")
|
||||||
* @Route("/{id}", requirements={"id"="\d+"})
|
* @Route("/{id}", requirements={"id"="\d+"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function show(Part $part, AttachmentManager $attachmentHelper, PricedetailHelper $pricedetailHelper, PartPreviewGenerator $previewGenerator)
|
public function show(Part $part, AttachmentManager $attachmentHelper, PricedetailHelper $pricedetailHelper, PartPreviewGenerator $previewGenerator)
|
||||||
{
|
{
|
||||||
|
@ -68,7 +70,7 @@ class PartController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}/edit", name="part_edit")
|
* @Route("/{id}/edit", name="part_edit")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function edit(Part $part, Request $request, EntityManagerInterface $em, TranslatorInterface $translator,
|
public function edit(Part $part, Request $request, EntityManagerInterface $em, TranslatorInterface $translator,
|
||||||
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler)
|
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler)
|
||||||
|
@ -90,10 +92,10 @@ class PartController extends AbstractController
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
$attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
||||||
} catch (AttachmentDownloadException $ex) {
|
} catch (AttachmentDownloadException $attachmentDownloadException) {
|
||||||
$this->addFlash(
|
$this->addFlash(
|
||||||
'error',
|
'error',
|
||||||
$translator->trans('attachment.download_failed').' '.$ex->getMessage()
|
$translator->trans('attachment.download_failed').' '.$attachmentDownloadException->getMessage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +120,7 @@ class PartController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}/delete", name="part_delete", methods={"DELETE"})
|
* @Route("/{id}/delete", name="part_delete", methods={"DELETE"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function delete(Request $request, Part $part)
|
public function delete(Request $request, Part $part)
|
||||||
{
|
{
|
||||||
|
@ -142,7 +144,7 @@ class PartController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/new", name="part_new")
|
* @Route("/new", name="part_new")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function new(Request $request, EntityManagerInterface $em, TranslatorInterface $translator,
|
public function new(Request $request, EntityManagerInterface $em, TranslatorInterface $translator,
|
||||||
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler)
|
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler)
|
||||||
|
@ -174,10 +176,10 @@ class PartController extends AbstractController
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
$attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options);
|
||||||
} catch (AttachmentDownloadException $ex) {
|
} catch (AttachmentDownloadException $attachmentDownloadException) {
|
||||||
$this->addFlash(
|
$this->addFlash(
|
||||||
'error',
|
'error',
|
||||||
$translator->trans('attachment.download_failed').' '.$ex->getMessage()
|
$translator->trans('attachment.download_failed').' '.$attachmentDownloadException->getMessage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +206,7 @@ class PartController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/{id}/clone", name="part_clone")
|
* @Route("/{id}/clone", name="part_clone")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
|
* @return RedirectResponse|Response
|
||||||
*/
|
*/
|
||||||
public function clone(Part $part, Request $request, EntityManagerInterface $em, TranslatorInterface $translator)
|
public function clone(Part $part, Request $request, EntityManagerInterface $em, TranslatorInterface $translator)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,7 +32,9 @@ use App\Entity\Parts\Storelocation;
|
||||||
use App\Entity\Parts\Supplier;
|
use App\Entity\Parts\Supplier;
|
||||||
use Omines\DataTablesBundle\DataTableFactory;
|
use Omines\DataTablesBundle\DataTableFactory;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
class PartListsController extends AbstractController
|
class PartListsController extends AbstractController
|
||||||
|
@ -40,7 +42,7 @@ class PartListsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/category/{id}/parts", name="part_list_category")
|
* @Route("/category/{id}/parts", name="part_list_category")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function showCategory(Category $category, Request $request, DataTableFactory $dataTable)
|
public function showCategory(Category $category, Request $request, DataTableFactory $dataTable)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +62,7 @@ class PartListsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/footprint/{id}/parts", name="part_list_footprint")
|
* @Route("/footprint/{id}/parts", name="part_list_footprint")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function showFootprint(Footprint $footprint, Request $request, DataTableFactory $dataTable)
|
public function showFootprint(Footprint $footprint, Request $request, DataTableFactory $dataTable)
|
||||||
{
|
{
|
||||||
|
@ -80,7 +82,7 @@ class PartListsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/manufacturer/{id}/parts", name="part_list_manufacturer")
|
* @Route("/manufacturer/{id}/parts", name="part_list_manufacturer")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function showManufacturer(Manufacturer $manufacturer, Request $request, DataTableFactory $dataTable)
|
public function showManufacturer(Manufacturer $manufacturer, Request $request, DataTableFactory $dataTable)
|
||||||
{
|
{
|
||||||
|
@ -100,7 +102,7 @@ class PartListsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/store_location/{id}/parts", name="part_list_store_location")
|
* @Route("/store_location/{id}/parts", name="part_list_store_location")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function showStorelocation(Storelocation $storelocation, Request $request, DataTableFactory $dataTable)
|
public function showStorelocation(Storelocation $storelocation, Request $request, DataTableFactory $dataTable)
|
||||||
{
|
{
|
||||||
|
@ -120,7 +122,7 @@ class PartListsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/supplier/{id}/parts", name="part_list_supplier")
|
* @Route("/supplier/{id}/parts", name="part_list_supplier")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function showSupplier(Supplier $supplier, Request $request, DataTableFactory $dataTable)
|
public function showSupplier(Supplier $supplier, Request $request, DataTableFactory $dataTable)
|
||||||
{
|
{
|
||||||
|
@ -140,7 +142,7 @@ class PartListsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/parts/by_tag/{tag}", name="part_list_tags")
|
* @Route("/parts/by_tag/{tag}", name="part_list_tags")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function showTag(string $tag, Request $request, DataTableFactory $dataTable)
|
public function showTag(string $tag, Request $request, DataTableFactory $dataTable)
|
||||||
{
|
{
|
||||||
|
@ -180,7 +182,7 @@ class PartListsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/parts", name="parts_show_all")
|
* @Route("/parts", name="parts_show_all")
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
|
* @return JsonResponse|Response
|
||||||
*/
|
*/
|
||||||
public function showAll(Request $request, DataTableFactory $dataTable)
|
public function showAll(Request $request, DataTableFactory $dataTable)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,7 +25,10 @@ declare(strict_types=1);
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
use App\Entity\UserSystem\User;
|
use App\Entity\UserSystem\User;
|
||||||
|
use function function_exists;
|
||||||
|
use function in_array;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
@ -49,7 +52,7 @@ class RedirectController extends AbstractController
|
||||||
* This function is called whenever a route was not matching the localized routes.
|
* This function is called whenever a route was not matching the localized routes.
|
||||||
* The purpose is to redirect the user to the localized version of the page.
|
* The purpose is to redirect the user to the localized version of the page.
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function addLocalePart(Request $request)
|
public function addLocalePart(Request $request)
|
||||||
{
|
{
|
||||||
|
@ -84,13 +87,13 @@ class RedirectController extends AbstractController
|
||||||
*/
|
*/
|
||||||
public function checkIfModRewriteAvailable()
|
public function checkIfModRewriteAvailable()
|
||||||
{
|
{
|
||||||
if (! \function_exists('apache_get_modules')) {
|
if (! function_exists('apache_get_modules')) {
|
||||||
//If we can not check for apache modules, we just hope for the best and assume url rewriting is available
|
//If we can not check for apache modules, we just hope for the best and assume url rewriting is available
|
||||||
//If you want to enforce index.php versions of the url, you can override this via ENV vars.
|
//If you want to enforce index.php versions of the url, you can override this via ENV vars.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if the mod_rewrite module is loaded
|
//Check if the mod_rewrite module is loaded
|
||||||
return \in_array('mod_rewrite', apache_get_modules(), false);
|
return in_array('mod_rewrite', apache_get_modules(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace App\Controller;
|
||||||
|
|
||||||
use App\Services\PasswordResetManager;
|
use App\Services\PasswordResetManager;
|
||||||
use Gregwar\CaptchaBundle\Type\CaptchaType;
|
use Gregwar\CaptchaBundle\Type\CaptchaType;
|
||||||
|
use RuntimeException;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||||
|
@ -122,7 +123,10 @@ class SecurityController extends AbstractController
|
||||||
throw new AccessDeniedHttpException('You are already logged in, so you can not reset your password!');
|
throw new AccessDeniedHttpException('You are already logged in, so you can not reset your password!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = ['username' => $user, 'token' => $token];
|
$data = [
|
||||||
|
'username' => $user,
|
||||||
|
'token' => $token,
|
||||||
|
];
|
||||||
$builder = $this->createFormBuilder($data);
|
$builder = $this->createFormBuilder($data);
|
||||||
$builder->add('username', TextType::class, [
|
$builder->add('username', TextType::class, [
|
||||||
'label' => $this->translator->trans('pw_reset.username'),
|
'label' => $this->translator->trans('pw_reset.username'),
|
||||||
|
@ -132,8 +136,12 @@ class SecurityController extends AbstractController
|
||||||
]);
|
]);
|
||||||
$builder->add('new_password', RepeatedType::class, [
|
$builder->add('new_password', RepeatedType::class, [
|
||||||
'type' => PasswordType::class,
|
'type' => PasswordType::class,
|
||||||
'first_options' => ['label' => 'user.settings.pw_new.label'],
|
'first_options' => [
|
||||||
'second_options' => ['label' => 'user.settings.pw_confirm.label'],
|
'label' => 'user.settings.pw_new.label',
|
||||||
|
],
|
||||||
|
'second_options' => [
|
||||||
|
'label' => 'user.settings.pw_confirm.label',
|
||||||
|
],
|
||||||
'invalid_message' => 'password_must_match',
|
'invalid_message' => 'password_must_match',
|
||||||
'constraints' => [new Length([
|
'constraints' => [new Length([
|
||||||
'min' => 6,
|
'min' => 6,
|
||||||
|
@ -171,6 +179,6 @@ class SecurityController extends AbstractController
|
||||||
*/
|
*/
|
||||||
public function logout(): void
|
public function logout(): void
|
||||||
{
|
{
|
||||||
throw new \RuntimeException('Will be intercepted before getting here');
|
throw new RuntimeException('Will be intercepted before getting here');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use InvalidArgumentException;
|
||||||
use Symfony\Component\Asset\Packages;
|
use Symfony\Component\Asset\Packages;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
@ -99,7 +100,7 @@ class UserController extends AdminPages\BaseAdminController
|
||||||
public function delete(Request $request, User $entity, StructuralElementRecursionHelper $recursionHelper)
|
public function delete(Request $request, User $entity, StructuralElementRecursionHelper $recursionHelper)
|
||||||
{
|
{
|
||||||
if (User::ID_ANONYMOUS === $entity->getID()) {
|
if (User::ID_ANONYMOUS === $entity->getID()) {
|
||||||
throw new \InvalidArgumentException('You can not delete the anonymous user! It is needed for permission checking without a logged in user');
|
throw new InvalidArgumentException('You can not delete the anonymous user! It is needed for permission checking without a logged in user');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->_delete($request, $entity, $recursionHelper);
|
return $this->_delete($request, $entity, $recursionHelper);
|
||||||
|
|
|
@ -30,12 +30,14 @@ use App\Form\TFAGoogleSettingsType;
|
||||||
use App\Form\UserSettingsType;
|
use App\Form\UserSettingsType;
|
||||||
use App\Services\TFA\BackupCodeManager;
|
use App\Services\TFA\BackupCodeManager;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use RuntimeException;
|
||||||
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticator;
|
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticator;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||||
|
@ -65,13 +67,13 @@ class UserSettingsController extends AbstractController
|
||||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
||||||
|
|
||||||
if (! $user instanceof User) {
|
if (! $user instanceof User) {
|
||||||
return new \RuntimeException('This controller only works only for Part-DB User objects!');
|
return new RuntimeException('This controller only works only for Part-DB User objects!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($user->getBackupCodes())) {
|
if (empty($user->getBackupCodes())) {
|
||||||
$this->addFlash('error', 'tfa_backup.no_codes_enabled');
|
$this->addFlash('error', 'tfa_backup.no_codes_enabled');
|
||||||
|
|
||||||
throw new \RuntimeException('You do not have any backup codes enabled, therefore you can not view them!');
|
throw new RuntimeException('You do not have any backup codes enabled, therefore you can not view them!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('Users/backup_codes.html.twig', [
|
return $this->render('Users/backup_codes.html.twig', [
|
||||||
|
@ -82,12 +84,12 @@ class UserSettingsController extends AbstractController
|
||||||
/**
|
/**
|
||||||
* @Route("/u2f_delete", name="u2f_delete", methods={"DELETE"})
|
* @Route("/u2f_delete", name="u2f_delete", methods={"DELETE"})
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function removeU2FToken(Request $request, EntityManagerInterface $entityManager, BackupCodeManager $backupCodeManager)
|
public function removeU2FToken(Request $request, EntityManagerInterface $entityManager, BackupCodeManager $backupCodeManager)
|
||||||
{
|
{
|
||||||
if ($this->demo_mode) {
|
if ($this->demo_mode) {
|
||||||
throw new \RuntimeException('You can not do 2FA things in demo mode');
|
throw new RuntimeException('You can not do 2FA things in demo mode');
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
|
@ -96,7 +98,7 @@ class UserSettingsController extends AbstractController
|
||||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
||||||
|
|
||||||
if (! $user instanceof User) {
|
if (! $user instanceof User) {
|
||||||
throw new \RuntimeException('This controller only works only for Part-DB User objects!');
|
throw new RuntimeException('This controller only works only for Part-DB User objects!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isCsrfTokenValid('delete'.$user->getId(), $request->request->get('_token'))) {
|
if ($this->isCsrfTokenValid('delete'.$user->getId(), $request->request->get('_token'))) {
|
||||||
|
@ -108,14 +110,14 @@ class UserSettingsController extends AbstractController
|
||||||
if (null === $u2f) {
|
if (null === $u2f) {
|
||||||
$this->addFlash('danger', 'tfa_u2f.u2f_delete.not_existing');
|
$this->addFlash('danger', 'tfa_u2f.u2f_delete.not_existing');
|
||||||
|
|
||||||
throw new \RuntimeException('Key not existing!');
|
throw new RuntimeException('Key not existing!');
|
||||||
}
|
}
|
||||||
|
|
||||||
//User can only delete its own U2F keys
|
//User can only delete its own U2F keys
|
||||||
if ($u2f->getUser() !== $user) {
|
if ($u2f->getUser() !== $user) {
|
||||||
$this->addFlash('danger', 'tfa_u2f.u2f_delete.access_denied');
|
$this->addFlash('danger', 'tfa_u2f.u2f_delete.access_denied');
|
||||||
|
|
||||||
throw new \RuntimeException('You can only delete your own U2F keys!');
|
throw new RuntimeException('You can only delete your own U2F keys!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$backupCodeManager->disableBackupCodesIfUnused($user);
|
$backupCodeManager->disableBackupCodesIfUnused($user);
|
||||||
|
@ -136,7 +138,7 @@ class UserSettingsController extends AbstractController
|
||||||
public function resetTrustedDevices(Request $request, EntityManagerInterface $entityManager)
|
public function resetTrustedDevices(Request $request, EntityManagerInterface $entityManager)
|
||||||
{
|
{
|
||||||
if ($this->demo_mode) {
|
if ($this->demo_mode) {
|
||||||
throw new \RuntimeException('You can not do 2FA things in demo mode');
|
throw new RuntimeException('You can not do 2FA things in demo mode');
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
|
@ -145,7 +147,7 @@ class UserSettingsController extends AbstractController
|
||||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
||||||
|
|
||||||
if (! $user instanceof User) {
|
if (! $user instanceof User) {
|
||||||
return new \RuntimeException('This controller only works only for Part-DB User objects!');
|
return new RuntimeException('This controller only works only for Part-DB User objects!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isCsrfTokenValid('devices_reset'.$user->getId(), $request->request->get('_token'))) {
|
if ($this->isCsrfTokenValid('devices_reset'.$user->getId(), $request->request->get('_token'))) {
|
||||||
|
@ -173,7 +175,7 @@ class UserSettingsController extends AbstractController
|
||||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
|
||||||
|
|
||||||
if (! $user instanceof User) {
|
if (! $user instanceof User) {
|
||||||
throw new \RuntimeException('This controller only works only for Part-DB User objects!');
|
throw new RuntimeException('This controller only works only for Part-DB User objects!');
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
|
@ -202,23 +204,36 @@ class UserSettingsController extends AbstractController
|
||||||
//Username field for autocomplete
|
//Username field for autocomplete
|
||||||
->add('username', TextType::class, [
|
->add('username', TextType::class, [
|
||||||
'data' => $user->getName(),
|
'data' => $user->getName(),
|
||||||
'attr' => ['autocomplete' => 'username'],
|
'attr' => [
|
||||||
|
'autocomplete' => 'username',
|
||||||
|
],
|
||||||
'disabled' => true,
|
'disabled' => true,
|
||||||
'row_attr' => ['class' => 'd-none'],
|
'row_attr' => [
|
||||||
|
'class' => 'd-none',
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->add('old_password', PasswordType::class, [
|
->add('old_password', PasswordType::class, [
|
||||||
'label' => 'user.settings.pw_old.label',
|
'label' => 'user.settings.pw_old.label',
|
||||||
'disabled' => $this->demo_mode,
|
'disabled' => $this->demo_mode,
|
||||||
'attr' => ['autocomplete' => 'current-password'],
|
'attr' => [
|
||||||
'constraints' => [new UserPassword()], ]) //This constraint checks, if the current user pw was inputted.
|
'autocomplete' => 'current-password',
|
||||||
|
],
|
||||||
|
'constraints' => [new UserPassword()],
|
||||||
|
]) //This constraint checks, if the current user pw was inputted.
|
||||||
->add('new_password', RepeatedType::class, [
|
->add('new_password', RepeatedType::class, [
|
||||||
'disabled' => $this->demo_mode,
|
'disabled' => $this->demo_mode,
|
||||||
'type' => PasswordType::class,
|
'type' => PasswordType::class,
|
||||||
'first_options' => ['label' => 'user.settings.pw_new.label'],
|
'first_options' => [
|
||||||
'second_options' => ['label' => 'user.settings.pw_confirm.label'],
|
'label' => 'user.settings.pw_new.label',
|
||||||
|
],
|
||||||
|
'second_options' => [
|
||||||
|
'label' => 'user.settings.pw_confirm.label',
|
||||||
|
],
|
||||||
'invalid_message' => 'password_must_match',
|
'invalid_message' => 'password_must_match',
|
||||||
'options' => [
|
'options' => [
|
||||||
'attr' => ['autocomplete' => 'new-password'],
|
'attr' => [
|
||||||
|
'autocomplete' => 'new-password',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'constraints' => [new Length([
|
'constraints' => [new Length([
|
||||||
'min' => 6,
|
'min' => 6,
|
||||||
|
@ -276,7 +291,9 @@ class UserSettingsController extends AbstractController
|
||||||
|
|
||||||
$backup_form = $this->get('form.factory')->createNamedBuilder('backup_codes')->add('reset_codes', SubmitType::class, [
|
$backup_form = $this->get('form.factory')->createNamedBuilder('backup_codes')->add('reset_codes', SubmitType::class, [
|
||||||
'label' => 'tfa_backup.regenerate_codes',
|
'label' => 'tfa_backup.regenerate_codes',
|
||||||
'attr' => ['class' => 'btn-danger'],
|
'attr' => [
|
||||||
|
'class' => 'btn-danger',
|
||||||
|
],
|
||||||
'disabled' => empty($user->getBackupCodes()),
|
'disabled' => empty($user->getBackupCodes()),
|
||||||
])->getForm();
|
])->getForm();
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ use App\Entity\Parts\Supplier;
|
||||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||||
use Doctrine\Common\Persistence\ObjectManager;
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
class DataStructureFixtures extends Fixture
|
class DataStructureFixtures extends Fixture
|
||||||
{
|
{
|
||||||
|
@ -71,7 +72,7 @@ class DataStructureFixtures extends Fixture
|
||||||
public function createNodesForClass(string $class, ObjectManager $manager): void
|
public function createNodesForClass(string $class, ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
if (! new $class() instanceof StructuralDBElement) {
|
if (! new $class() instanceof StructuralDBElement) {
|
||||||
throw new \InvalidArgumentException('$class must be a StructuralDBElement!');
|
throw new InvalidArgumentException('$class must be a StructuralDBElement!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$table_name = $this->em->getClassMetadata($class)->getTableName();
|
$table_name = $this->em->getClassMetadata($class)->getTableName();
|
||||||
|
|
|
@ -40,14 +40,41 @@ class GroupFixtures extends Fixture
|
||||||
$admins->setName('admins');
|
$admins->setName('admins');
|
||||||
//Perm values taken from Version 1
|
//Perm values taken from Version 1
|
||||||
$admins->getPermissions()->setRawPermissionValues([
|
$admins->getPermissions()->setRawPermissionValues([
|
||||||
'system' => 21, 'groups' => 1365, 'users' => 87381, 'self' => 85, 'config' => 85,
|
'system' => 21,
|
||||||
'database' => 21, 'parts' => 1431655765, 'parts_name' => 5, 'parts_description' => 5,
|
'groups' => 1365,
|
||||||
'parts_footprint' => 5, 'parts_manufacturer' => 5, 'parts_comment' => 5, 'parts_order' => 5,
|
'users' => 87381,
|
||||||
'parts_orderdetails' => 341, 'parts_prices' => 341, 'parts_attachments' => 341, 'devices' => 5461,
|
'self' => 85,
|
||||||
'devices_parts' => 325, 'storelocations' => 5461, 'footprints' => 5461, 'categories' => 5461,
|
'config' => 85,
|
||||||
'suppliers' => 5461, 'manufacturers' => 5461, 'attachment_types' => 1365, 'tools' => 1365,
|
'database' => 21,
|
||||||
'labels' => 21, 'parts_category' => 5, 'parts_minamount' => 5, 'parts_lots' => 85, 'parts_tags' => 5,
|
'parts' => 1431655765,
|
||||||
'parts_unit' => 5, 'parts_mass' => 5, 'parts_status' => 5, 'parts_mpn' => 5, 'currencies' => 5461,
|
'parts_name' => 5,
|
||||||
|
'parts_description' => 5,
|
||||||
|
'parts_footprint' => 5,
|
||||||
|
'parts_manufacturer' => 5,
|
||||||
|
'parts_comment' => 5,
|
||||||
|
'parts_order' => 5,
|
||||||
|
'parts_orderdetails' => 341,
|
||||||
|
'parts_prices' => 341,
|
||||||
|
'parts_attachments' => 341,
|
||||||
|
'devices' => 5461,
|
||||||
|
'devices_parts' => 325,
|
||||||
|
'storelocations' => 5461,
|
||||||
|
'footprints' => 5461,
|
||||||
|
'categories' => 5461,
|
||||||
|
'suppliers' => 5461,
|
||||||
|
'manufacturers' => 5461,
|
||||||
|
'attachment_types' => 1365,
|
||||||
|
'tools' => 1365,
|
||||||
|
'labels' => 21,
|
||||||
|
'parts_category' => 5,
|
||||||
|
'parts_minamount' => 5,
|
||||||
|
'parts_lots' => 85,
|
||||||
|
'parts_tags' => 5,
|
||||||
|
'parts_unit' => 5,
|
||||||
|
'parts_mass' => 5,
|
||||||
|
'parts_status' => 5,
|
||||||
|
'parts_mpn' => 5,
|
||||||
|
'currencies' => 5461,
|
||||||
'measurement_units' => 5461,
|
'measurement_units' => 5461,
|
||||||
]);
|
]);
|
||||||
$this->setReference(self::ADMINS, $admins);
|
$this->setReference(self::ADMINS, $admins);
|
||||||
|
@ -56,14 +83,41 @@ class GroupFixtures extends Fixture
|
||||||
$readonly = new Group();
|
$readonly = new Group();
|
||||||
$readonly->setName('readonly');
|
$readonly->setName('readonly');
|
||||||
$readonly->getPermissions()->setRawPermissionValues([
|
$readonly->getPermissions()->setRawPermissionValues([
|
||||||
'system' => 2, 'groups' => 2730, 'users' => 43690, 'self' => 25, 'config' => 170,
|
'system' => 2,
|
||||||
'database' => 42, 'parts' => 2778027689, 'parts_name' => 9, 'parts_description' => 9,
|
'groups' => 2730,
|
||||||
'parts_footprint' => 9, 'parts_manufacturer' => 9, 'parts_comment' => 9, 'parts_order' => 9,
|
'users' => 43690,
|
||||||
'parts_orderdetails' => 681, 'parts_prices' => 681, 'parts_attachments' => 681, 'devices' => 1705,
|
'self' => 25,
|
||||||
'devices_parts' => 649, 'storelocations' => 1705, 'footprints' => 1705, 'categories' => 1705,
|
'config' => 170,
|
||||||
'suppliers' => 1705, 'manufacturers' => 1705, 'attachment_types' => 681, 'tools' => 1366,
|
'database' => 42,
|
||||||
'labels' => 165, 'parts_category' => 9, 'parts_minamount' => 9, 'parts_lots' => 169, 'parts_tags' => 9,
|
'parts' => 2778027689,
|
||||||
'parts_unit' => 9, 'parts_mass' => 9, 'parts_status' => 9, 'parts_mpn' => 9, 'currencies' => 9897,
|
'parts_name' => 9,
|
||||||
|
'parts_description' => 9,
|
||||||
|
'parts_footprint' => 9,
|
||||||
|
'parts_manufacturer' => 9,
|
||||||
|
'parts_comment' => 9,
|
||||||
|
'parts_order' => 9,
|
||||||
|
'parts_orderdetails' => 681,
|
||||||
|
'parts_prices' => 681,
|
||||||
|
'parts_attachments' => 681,
|
||||||
|
'devices' => 1705,
|
||||||
|
'devices_parts' => 649,
|
||||||
|
'storelocations' => 1705,
|
||||||
|
'footprints' => 1705,
|
||||||
|
'categories' => 1705,
|
||||||
|
'suppliers' => 1705,
|
||||||
|
'manufacturers' => 1705,
|
||||||
|
'attachment_types' => 681,
|
||||||
|
'tools' => 1366,
|
||||||
|
'labels' => 165,
|
||||||
|
'parts_category' => 9,
|
||||||
|
'parts_minamount' => 9,
|
||||||
|
'parts_lots' => 169,
|
||||||
|
'parts_tags' => 9,
|
||||||
|
'parts_unit' => 9,
|
||||||
|
'parts_mass' => 9,
|
||||||
|
'parts_status' => 9,
|
||||||
|
'parts_mpn' => 9,
|
||||||
|
'currencies' => 9897,
|
||||||
'measurement_units' => 9897,
|
'measurement_units' => 9897,
|
||||||
]);
|
]);
|
||||||
$this->setReference(self::READONLY, $readonly);
|
$this->setReference(self::READONLY, $readonly);
|
||||||
|
@ -72,14 +126,41 @@ class GroupFixtures extends Fixture
|
||||||
$users = new Group();
|
$users = new Group();
|
||||||
$users->setName('users');
|
$users->setName('users');
|
||||||
$users->getPermissions()->setRawPermissionValues([
|
$users->getPermissions()->setRawPermissionValues([
|
||||||
'system' => 42, 'groups' => 2730, 'users' => 43690, 'self' => 89, 'config' => 105,
|
'system' => 42,
|
||||||
'database' => 41, 'parts' => 1431655765, 'parts_name' => 5, 'parts_description' => 5,
|
'groups' => 2730,
|
||||||
'parts_footprint' => 5, 'parts_manufacturer' => 5, 'parts_comment' => 5, 'parts_order' => 5,
|
'users' => 43690,
|
||||||
'parts_orderdetails' => 341, 'parts_prices' => 341, 'parts_attachments' => 341, 'devices' => 5461,
|
'self' => 89,
|
||||||
'devices_parts' => 325, 'storelocations' => 5461, 'footprints' => 5461, 'categories' => 5461,
|
'config' => 105,
|
||||||
'suppliers' => 5461, 'manufacturers' => 5461, 'attachment_types' => 1365, 'tools' => 1365,
|
'database' => 41,
|
||||||
'labels' => 85, 'parts_category' => 5, 'parts_minamount' => 5, 'parts_lots' => 85, 'parts_tags' => 5,
|
'parts' => 1431655765,
|
||||||
'parts_unit' => 5, 'parts_mass' => 5, 'parts_status' => 5, 'parts_mpn' => 5, 'currencies' => 5461,
|
'parts_name' => 5,
|
||||||
|
'parts_description' => 5,
|
||||||
|
'parts_footprint' => 5,
|
||||||
|
'parts_manufacturer' => 5,
|
||||||
|
'parts_comment' => 5,
|
||||||
|
'parts_order' => 5,
|
||||||
|
'parts_orderdetails' => 341,
|
||||||
|
'parts_prices' => 341,
|
||||||
|
'parts_attachments' => 341,
|
||||||
|
'devices' => 5461,
|
||||||
|
'devices_parts' => 325,
|
||||||
|
'storelocations' => 5461,
|
||||||
|
'footprints' => 5461,
|
||||||
|
'categories' => 5461,
|
||||||
|
'suppliers' => 5461,
|
||||||
|
'manufacturers' => 5461,
|
||||||
|
'attachment_types' => 1365,
|
||||||
|
'tools' => 1365,
|
||||||
|
'labels' => 85,
|
||||||
|
'parts_category' => 5,
|
||||||
|
'parts_minamount' => 5,
|
||||||
|
'parts_lots' => 85,
|
||||||
|
'parts_tags' => 5,
|
||||||
|
'parts_unit' => 5,
|
||||||
|
'parts_mass' => 5,
|
||||||
|
'parts_status' => 5,
|
||||||
|
'parts_mpn' => 5,
|
||||||
|
'currencies' => 5461,
|
||||||
'measurement_units' => 5461,
|
'measurement_units' => 5461,
|
||||||
]);
|
]);
|
||||||
$this->setReference(self::USERS, $users);
|
$this->setReference(self::USERS, $users);
|
||||||
|
|
|
@ -29,6 +29,7 @@ use Doctrine\ORM\QueryBuilder;
|
||||||
use Omines\DataTablesBundle\Adapter\AdapterQuery;
|
use Omines\DataTablesBundle\Adapter\AdapterQuery;
|
||||||
use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter;
|
use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter;
|
||||||
use Omines\DataTablesBundle\Column\AbstractColumn;
|
use Omines\DataTablesBundle\Column\AbstractColumn;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override default ORM Adapter, to allow fetch joins (allow addSelect with ManyToOne Collections).
|
* Override default ORM Adapter, to allow fetch joins (allow addSelect with ManyToOne Collections).
|
||||||
|
@ -52,9 +53,9 @@ class CustomORMAdapter extends ORMAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Traversable
|
* @return Traversable
|
||||||
*/
|
*/
|
||||||
protected function getResults(AdapterQuery $query): \Traversable
|
protected function getResults(AdapterQuery $query): Traversable
|
||||||
{
|
{
|
||||||
/** @var QueryBuilder $builder */
|
/** @var QueryBuilder $builder */
|
||||||
$builder = $query->get('qb');
|
$builder = $query->get('qb');
|
||||||
|
|
|
@ -38,7 +38,7 @@ use Omines\DataTablesBundle\DataTable;
|
||||||
use Omines\DataTablesBundle\DataTableTypeInterface;
|
use Omines\DataTablesBundle\DataTableTypeInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
class AttachmentDataTable implements DataTableTypeInterface
|
final class AttachmentDataTable implements DataTableTypeInterface
|
||||||
{
|
{
|
||||||
protected $translator;
|
protected $translator;
|
||||||
protected $entityURLGenerator;
|
protected $entityURLGenerator;
|
||||||
|
|
|
@ -24,7 +24,10 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\DataTables\Column;
|
namespace App\DataTables\Column;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeInterface;
|
||||||
use IntlDateFormatter;
|
use IntlDateFormatter;
|
||||||
|
use Locale;
|
||||||
use Omines\DataTablesBundle\Column\AbstractColumn;
|
use Omines\DataTablesBundle\Column\AbstractColumn;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
@ -38,8 +41,8 @@ class LocaleDateTimeColumn extends AbstractColumn
|
||||||
{
|
{
|
||||||
if (null === $value) {
|
if (null === $value) {
|
||||||
return $this->options['nullValue'];
|
return $this->options['nullValue'];
|
||||||
} elseif (! $value instanceof \DateTimeInterface) {
|
} elseif (! $value instanceof DateTimeInterface) {
|
||||||
$value = new \DateTime((string) $value);
|
$value = new DateTime((string) $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
$formatValues = [
|
$formatValues = [
|
||||||
|
@ -51,7 +54,7 @@ class LocaleDateTimeColumn extends AbstractColumn
|
||||||
];
|
];
|
||||||
|
|
||||||
$formatter = IntlDateFormatter::create(
|
$formatter = IntlDateFormatter::create(
|
||||||
\Locale::getDefault(),
|
Locale::getDefault(),
|
||||||
$formatValues[$this->options['dateFormat']],
|
$formatValues[$this->options['dateFormat']],
|
||||||
$formatValues[$this->options['timeFormat']],
|
$formatValues[$this->options['timeFormat']],
|
||||||
$value->getTimezone()
|
$value->getTimezone()
|
||||||
|
|
|
@ -30,6 +30,7 @@ use App\Services\Attachments\AttachmentManager;
|
||||||
use App\Services\EntityURLGenerator;
|
use App\Services\EntityURLGenerator;
|
||||||
use App\Services\FAIconGenerator;
|
use App\Services\FAIconGenerator;
|
||||||
use Omines\DataTablesBundle\Column\AbstractColumn;
|
use Omines\DataTablesBundle\Column\AbstractColumn;
|
||||||
|
use RuntimeException;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
class PartAttachmentsColumn extends AbstractColumn
|
class PartAttachmentsColumn extends AbstractColumn
|
||||||
|
@ -60,7 +61,7 @@ class PartAttachmentsColumn extends AbstractColumn
|
||||||
public function render($value, $context)
|
public function render($value, $context)
|
||||||
{
|
{
|
||||||
if (! $context instanceof Part) {
|
if (! $context instanceof Part) {
|
||||||
throw new \RuntimeException('$context must be a Part object!');
|
throw new RuntimeException('$context must be a Part object!');
|
||||||
}
|
}
|
||||||
$tmp = '';
|
$tmp = '';
|
||||||
$attachments = $context->getAttachments()->filter(function (Attachment $attachment) {
|
$attachments = $context->getAttachments()->filter(function (Attachment $attachment) {
|
||||||
|
|
|
@ -50,17 +50,17 @@ use Omines\DataTablesBundle\DataTable;
|
||||||
use Omines\DataTablesBundle\DataTableTypeInterface;
|
use Omines\DataTablesBundle\DataTableTypeInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
class PartsDataTable implements DataTableTypeInterface
|
final class PartsDataTable implements DataTableTypeInterface
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var EntityURLGenerator
|
|
||||||
*/
|
|
||||||
protected $urlGenerator;
|
|
||||||
protected $translator;
|
protected $translator;
|
||||||
protected $treeBuilder;
|
protected $treeBuilder;
|
||||||
protected $amountFormatter;
|
protected $amountFormatter;
|
||||||
protected $previewGenerator;
|
protected $previewGenerator;
|
||||||
protected $attachmentURLGenerator;
|
protected $attachmentURLGenerator;
|
||||||
|
/**
|
||||||
|
* @var EntityURLGenerator
|
||||||
|
*/
|
||||||
|
protected $urlGenerator;
|
||||||
|
|
||||||
public function __construct(EntityURLGenerator $urlGenerator, TranslatorInterface $translator,
|
public function __construct(EntityURLGenerator $urlGenerator, TranslatorInterface $translator,
|
||||||
NodesListBuilder $treeBuilder, AmountFormatter $amountFormatter,
|
NodesListBuilder $treeBuilder, AmountFormatter $amountFormatter,
|
||||||
|
|
|
@ -26,6 +26,9 @@ namespace App\Entity\Attachments;
|
||||||
use App\Entity\Base\NamedDBElement;
|
use App\Entity\Base\NamedDBElement;
|
||||||
use App\Validator\Constraints\Selectable;
|
use App\Validator\Constraints\Selectable;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use function in_array;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use LogicException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Attachment.
|
* Class Attachment.
|
||||||
|
@ -65,7 +68,9 @@ abstract class Attachment extends NamedDBElement
|
||||||
*/
|
*/
|
||||||
public const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%', '%SECURE%'];
|
public const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%', '%SECURE%'];
|
||||||
|
|
||||||
/** @var array Placeholders for attachments which using built in files. */
|
/**
|
||||||
|
* @var array Placeholders for attachments which using built in files.
|
||||||
|
*/
|
||||||
public const BUILTIN_PLACEHOLDER = ['%FOOTPRINTS%', '%FOOTPRINTS3D%'];
|
public const BUILTIN_PLACEHOLDER = ['%FOOTPRINTS%', '%FOOTPRINTS3D%'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,10 +79,10 @@ abstract class Attachment extends NamedDBElement
|
||||||
public const ALLOWED_ELEMENT_CLASS = '';
|
public const ALLOWED_ELEMENT_CLASS = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var string the original filename the file had, when the user uploaded it
|
||||||
* @ORM\Column(type="boolean")
|
* @ORM\Column(type="string", nullable=true)
|
||||||
*/
|
*/
|
||||||
protected $show_in_table = false;
|
protected $original_filename;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string The path to the file relative to a placeholder path like %MEDIA%
|
* @var string The path to the file relative to a placeholder path like %MEDIA%
|
||||||
|
@ -85,17 +90,17 @@ abstract class Attachment extends NamedDBElement
|
||||||
*/
|
*/
|
||||||
protected $path = '';
|
protected $path = '';
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string the original filename the file had, when the user uploaded it
|
|
||||||
* @ORM\Column(type="string", nullable=true)
|
|
||||||
*/
|
|
||||||
protected $original_filename;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ORM mapping is done in sub classes (like PartAttachment).
|
* ORM mapping is done in sub classes (like PartAttachment).
|
||||||
*/
|
*/
|
||||||
protected $element;
|
protected $element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
* @ORM\Column(type="boolean")
|
||||||
|
*/
|
||||||
|
protected $show_in_table = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var AttachmentType
|
* @var AttachmentType
|
||||||
* @ORM\ManyToOne(targetEntity="AttachmentType", inversedBy="attachments_with_type")
|
* @ORM\ManyToOne(targetEntity="AttachmentType", inversedBy="attachments_with_type")
|
||||||
|
@ -108,7 +113,7 @@ abstract class Attachment extends NamedDBElement
|
||||||
{
|
{
|
||||||
//parent::__construct();
|
//parent::__construct();
|
||||||
if ('' === static::ALLOWED_ELEMENT_CLASS) {
|
if ('' === static::ALLOWED_ELEMENT_CLASS) {
|
||||||
throw new \LogicException('An *Attachment class must override the ALLOWED_ELEMENT_CLASS const!');
|
throw new LogicException('An *Attachment class must override the ALLOWED_ELEMENT_CLASS const!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +137,7 @@ abstract class Attachment extends NamedDBElement
|
||||||
|
|
||||||
$extension = pathinfo($this->getPath(), PATHINFO_EXTENSION);
|
$extension = pathinfo($this->getPath(), PATHINFO_EXTENSION);
|
||||||
|
|
||||||
return \in_array(strtolower($extension), static::PICTURE_EXTS, true);
|
return in_array(strtolower($extension), static::PICTURE_EXTS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,7 +153,7 @@ abstract class Attachment extends NamedDBElement
|
||||||
|
|
||||||
$extension = pathinfo($this->getPath(), PATHINFO_EXTENSION);
|
$extension = pathinfo($this->getPath(), PATHINFO_EXTENSION);
|
||||||
|
|
||||||
return \in_array(strtolower($extension), static::MODEL_EXTS, true);
|
return in_array(strtolower($extension), static::MODEL_EXTS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,7 +175,7 @@ abstract class Attachment extends NamedDBElement
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ! \in_array($tmp[0], array_merge(static::INTERNAL_PLACEHOLDER, static::BUILTIN_PLACEHOLDER), false);
|
return ! in_array($tmp[0], array_merge(static::INTERNAL_PLACEHOLDER, static::BUILTIN_PLACEHOLDER), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -363,7 +368,7 @@ abstract class Attachment extends NamedDBElement
|
||||||
public function setElement(AttachmentContainingDBElement $element): self
|
public function setElement(AttachmentContainingDBElement $element): self
|
||||||
{
|
{
|
||||||
if (! is_a($element, static::ALLOWED_ELEMENT_CLASS)) {
|
if (! is_a($element, static::ALLOWED_ELEMENT_CLASS)) {
|
||||||
throw new \InvalidArgumentException(sprintf('The element associated with a %s must be a %s!', static::class, static::ALLOWED_ELEMENT_CLASS));
|
throw new InvalidArgumentException(sprintf('The element associated with a %s must be a %s!', static::class, static::ALLOWED_ELEMENT_CLASS));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->element = $element;
|
$this->element = $element;
|
||||||
|
@ -406,7 +411,7 @@ abstract class Attachment extends NamedDBElement
|
||||||
//Only set if the URL is not empty
|
//Only set if the URL is not empty
|
||||||
if (! empty($url)) {
|
if (! empty($url)) {
|
||||||
if (false !== strpos($url, '%BASE%') || false !== strpos($url, '%MEDIA%')) {
|
if (false !== strpos($url, '%BASE%') || false !== strpos($url, '%MEDIA%')) {
|
||||||
throw new \InvalidArgumentException('You can not reference internal files via the url field! But nice try!');
|
throw new InvalidArgumentException('You can not reference internal files via the url field! But nice try!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->path = $url;
|
$this->path = $url;
|
||||||
|
@ -437,7 +442,7 @@ abstract class Attachment extends NamedDBElement
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return \in_array($tmp[0], static::BUILTIN_PLACEHOLDER, false);
|
return in_array($tmp[0], static::BUILTIN_PLACEHOLDER, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -43,7 +43,7 @@ abstract class AttachmentContainingDBElement extends NamedDBElement
|
||||||
*
|
*
|
||||||
* Mapping is done in sub classes like part
|
* Mapping is done in sub classes like part
|
||||||
*/
|
*/
|
||||||
protected $attachments;
|
protected $attachments = [];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,18 +37,6 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
*/
|
*/
|
||||||
class AttachmentType extends StructuralDBElement
|
class AttachmentType extends StructuralDBElement
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Collection|AttachmentTypeAttachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\AttachmentTypeAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Collection|Attachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="Attachment", mappedBy="attachment_type")
|
|
||||||
*/
|
|
||||||
protected $attachments_with_type;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="AttachmentType", mappedBy="parent", cascade={"persist"})
|
* @ORM\OneToMany(targetEntity="AttachmentType", mappedBy="parent", cascade={"persist"})
|
||||||
*/
|
*/
|
||||||
|
@ -66,6 +54,17 @@ class AttachmentType extends StructuralDBElement
|
||||||
* @ValidFileFilter
|
* @ValidFileFilter
|
||||||
*/
|
*/
|
||||||
protected $filetype_filter = '';
|
protected $filetype_filter = '';
|
||||||
|
/**
|
||||||
|
* @var Collection|AttachmentTypeAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\AttachmentTypeAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Collection|Attachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="Attachment", mappedBy="attachment_type")
|
||||||
|
*/
|
||||||
|
protected $attachments_with_type;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,7 @@ declare(strict_types=1);
|
||||||
namespace App\Entity\Base;
|
namespace App\Entity\Base;
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use function is_string;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,7 +158,7 @@ abstract class Company extends PartsContainingDBElement
|
||||||
*/
|
*/
|
||||||
public function getAutoProductUrl($partnr = null): string
|
public function getAutoProductUrl($partnr = null): string
|
||||||
{
|
{
|
||||||
if (\is_string($partnr)) {
|
if (is_string($partnr)) {
|
||||||
return str_replace('%PARTNUMBER%', $partnr, $this->auto_product_url);
|
return str_replace('%PARTNUMBER%', $partnr, $this->auto_product_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,13 @@ namespace App\Entity\Base;
|
||||||
|
|
||||||
use App\Entity\Attachments\AttachmentContainingDBElement;
|
use App\Entity\Attachments\AttachmentContainingDBElement;
|
||||||
use App\Validator\Constraints\NoneOfItsChildren;
|
use App\Validator\Constraints\NoneOfItsChildren;
|
||||||
|
use function count;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use function get_class;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use function is_array;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
|
@ -50,23 +54,11 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
{
|
{
|
||||||
public const ID_ROOT_ELEMENT = 0;
|
public const ID_ROOT_ELEMENT = 0;
|
||||||
|
|
||||||
/** This is a not standard character, so build a const, so a dev can easily use it */
|
/**
|
||||||
|
* This is a not standard character, so build a const, so a dev can easily use it
|
||||||
|
*/
|
||||||
public const PATH_DELIMITER_ARROW = ' → ';
|
public const PATH_DELIMITER_ARROW = ' → ';
|
||||||
|
|
||||||
/**
|
|
||||||
* We can not define the mapping here or we will get an exception. Unfortunately we have to do the mapping in the
|
|
||||||
* subclasses
|
|
||||||
* @var StructuralDBElement[]
|
|
||||||
* @Groups({"include_children"})
|
|
||||||
*/
|
|
||||||
protected $children;
|
|
||||||
/**
|
|
||||||
* @var StructuralDBElement
|
|
||||||
* @NoneOfItsChildren()
|
|
||||||
* @Groups({"include_parents"})
|
|
||||||
*/
|
|
||||||
protected $parent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string The comment info for this element
|
* @var string The comment info for this element
|
||||||
* @ORM\Column(type="text")
|
* @ORM\Column(type="text")
|
||||||
|
@ -86,10 +78,25 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
*/
|
*/
|
||||||
protected $level = 0;
|
protected $level = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We can not define the mapping here or we will get an exception. Unfortunately we have to do the mapping in the
|
||||||
|
* subclasses.
|
||||||
|
*
|
||||||
|
* @var StructuralDBElement[]
|
||||||
|
* @Groups({"include_children"})
|
||||||
|
*/
|
||||||
|
protected $children = [];
|
||||||
|
/**
|
||||||
|
* @var StructuralDBElement
|
||||||
|
* @NoneOfItsChildren()
|
||||||
|
* @Groups({"include_parents"})
|
||||||
|
*/
|
||||||
|
protected $parent;
|
||||||
|
|
||||||
/** @var string[] all names of all parent elements as a array of strings,
|
/** @var string[] all names of all parent elements as a array of strings,
|
||||||
* the last array element is the name of the element itself
|
* the last array element is the name of the element itself
|
||||||
*/
|
*/
|
||||||
private $full_path_strings;
|
private $full_path_strings = [];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -109,7 +116,7 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
*
|
*
|
||||||
* @return bool True, if this element is child of $another_element.
|
* @return bool True, if this element is child of $another_element.
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException if there was an error
|
* @throws InvalidArgumentException if there was an error
|
||||||
*/
|
*/
|
||||||
public function isChildOf(self $another_element): bool
|
public function isChildOf(self $another_element): bool
|
||||||
{
|
{
|
||||||
|
@ -117,8 +124,8 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
|
|
||||||
//Check if both elements compared, are from the same type
|
//Check if both elements compared, are from the same type
|
||||||
// (we have to check inheritance, or we get exceptions when using doctrine entities (they have a proxy type):
|
// (we have to check inheritance, or we get exceptions when using doctrine entities (they have a proxy type):
|
||||||
if (! is_a($another_element, $class_name) && ! is_a($this, \get_class($another_element))) {
|
if (! is_a($another_element, $class_name) && ! is_a($this, get_class($another_element))) {
|
||||||
throw new \InvalidArgumentException('isChildOf() only works for objects of the same type!');
|
throw new InvalidArgumentException('isChildOf() only works for objects of the same type!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $this->getParent()) { // this is the root node
|
if (null === $this->getParent()) { // this is the root node
|
||||||
|
@ -201,7 +208,7 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
*/
|
*/
|
||||||
public function getFullPath(string $delimiter = self::PATH_DELIMITER_ARROW): string
|
public function getFullPath(string $delimiter = self::PATH_DELIMITER_ARROW): string
|
||||||
{
|
{
|
||||||
if (! \is_array($this->full_path_strings)) {
|
if (empty($this->full_path_strings)) {
|
||||||
$this->full_path_strings = [];
|
$this->full_path_strings = [];
|
||||||
$this->full_path_strings[] = $this->getName();
|
$this->full_path_strings[] = $this->getName();
|
||||||
$element = $this;
|
$element = $this;
|
||||||
|
@ -233,7 +240,7 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
$tmp[] = $this;
|
$tmp[] = $this;
|
||||||
|
|
||||||
//We only allow 20 levels depth
|
//We only allow 20 levels depth
|
||||||
while (! end($tmp)->isRoot() && \count($tmp) < 20) {
|
while (! end($tmp)->isRoot() && count($tmp) < 20) {
|
||||||
$tmp[] = end($tmp)->parent;
|
$tmp[] = end($tmp)->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity\Base;
|
namespace App\Entity\Base;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,14 +33,14 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
trait TimestampTrait
|
trait TimestampTrait
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var \DateTime the date when this element was modified the last time
|
* @var DateTime the date when this element was modified the last time
|
||||||
* @ORM\Column(type="datetime", name="last_modified", options={"default"="CURRENT_TIMESTAMP"})
|
* @ORM\Column(type="datetime", name="last_modified", options={"default"="CURRENT_TIMESTAMP"})
|
||||||
* @Groups({"extended", "full"})
|
* @Groups({"extended", "full"})
|
||||||
*/
|
*/
|
||||||
protected $lastModified;
|
protected $lastModified;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \DateTime the date when this element was created
|
* @var DateTime the date when this element was created
|
||||||
* @ORM\Column(type="datetime", name="datetime_added", options={"default"="CURRENT_TIMESTAMP"})
|
* @ORM\Column(type="datetime", name="datetime_added", options={"default"="CURRENT_TIMESTAMP"})
|
||||||
* @Groups({"extended", "full"})
|
* @Groups({"extended", "full"})
|
||||||
*/
|
*/
|
||||||
|
@ -49,9 +50,9 @@ trait TimestampTrait
|
||||||
* Returns the last time when the element was modified.
|
* Returns the last time when the element was modified.
|
||||||
* Returns null if the element was not yet saved to DB yet.
|
* Returns null if the element was not yet saved to DB yet.
|
||||||
*
|
*
|
||||||
* @return \DateTime|null the time of the last edit
|
* @return DateTime|null the time of the last edit
|
||||||
*/
|
*/
|
||||||
public function getLastModified(): ?\DateTime
|
public function getLastModified(): ?DateTime
|
||||||
{
|
{
|
||||||
return $this->lastModified;
|
return $this->lastModified;
|
||||||
}
|
}
|
||||||
|
@ -60,9 +61,9 @@ trait TimestampTrait
|
||||||
* Returns the date/time when the element was created.
|
* Returns the date/time when the element was created.
|
||||||
* Returns null if the element was not yet saved to DB yet.
|
* Returns null if the element was not yet saved to DB yet.
|
||||||
*
|
*
|
||||||
* @return \DateTime|null the creation time of the part
|
* @return DateTime|null the creation time of the part
|
||||||
*/
|
*/
|
||||||
public function getAddedDate(): ?\DateTime
|
public function getAddedDate(): ?DateTime
|
||||||
{
|
{
|
||||||
return $this->addedDate;
|
return $this->addedDate;
|
||||||
}
|
}
|
||||||
|
@ -75,9 +76,9 @@ trait TimestampTrait
|
||||||
*/
|
*/
|
||||||
public function updatedTimestamps(): void
|
public function updatedTimestamps(): void
|
||||||
{
|
{
|
||||||
$this->lastModified = new \DateTime('now');
|
$this->lastModified = new DateTime('now');
|
||||||
if (null === $this->addedDate) {
|
if (null === $this->addedDate) {
|
||||||
$this->addedDate = new \DateTime('now');
|
$this->addedDate = new DateTime('now');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ use App\Entity\Attachments\DeviceAttachment;
|
||||||
use App\Entity\Base\PartsContainingDBElement;
|
use App\Entity\Base\PartsContainingDBElement;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AttachmentType.
|
* Class AttachmentType.
|
||||||
|
@ -64,12 +65,6 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
*/
|
*/
|
||||||
class Device extends PartsContainingDBElement
|
class Device extends PartsContainingDBElement
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Collection|DeviceAttachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\DeviceAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Device", mappedBy="parent")
|
* @ORM\OneToMany(targetEntity="Device", mappedBy="parent")
|
||||||
*/
|
*/
|
||||||
|
@ -81,6 +76,11 @@ class Device extends PartsContainingDBElement
|
||||||
*/
|
*/
|
||||||
protected $parent;
|
protected $parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\OneToMany(targetEntity="DevicePart", mappedBy="device")
|
||||||
|
*/
|
||||||
|
protected $parts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
* @ORM\Column(type="integer")
|
* @ORM\Column(type="integer")
|
||||||
|
@ -92,11 +92,11 @@ class Device extends PartsContainingDBElement
|
||||||
* @ORM\Column(type="boolean")
|
* @ORM\Column(type="boolean")
|
||||||
*/
|
*/
|
||||||
protected $order_only_missing_parts = false;
|
protected $order_only_missing_parts = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="DevicePart", mappedBy="device")
|
* @var Collection|DeviceAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\DeviceAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
*/
|
*/
|
||||||
protected $parts;
|
protected $attachments;
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
*
|
*
|
||||||
|
@ -140,7 +140,7 @@ class Device extends PartsContainingDBElement
|
||||||
public function setOrderQuantity(int $new_order_quantity): self
|
public function setOrderQuantity(int $new_order_quantity): self
|
||||||
{
|
{
|
||||||
if ($new_order_quantity < 0) {
|
if ($new_order_quantity < 0) {
|
||||||
throw new \InvalidArgumentException('The new order quantity must not be negative!');
|
throw new InvalidArgumentException('The new order quantity must not be negative!');
|
||||||
}
|
}
|
||||||
$this->order_quantity = $new_order_quantity;
|
$this->order_quantity = $new_order_quantity;
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,17 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
*/
|
*/
|
||||||
class DevicePart extends DBElement
|
class DevicePart extends DBElement
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
* @ORM\Column(type="integer", name="quantity")
|
||||||
|
*/
|
||||||
|
protected $quantity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
* @ORM\Column(type="text", name="mountnames")
|
||||||
|
*/
|
||||||
|
protected $mountnames;
|
||||||
/**
|
/**
|
||||||
* @var Device
|
* @var Device
|
||||||
* @ORM\ManyToOne(targetEntity="Device", inversedBy="parts")
|
* @ORM\ManyToOne(targetEntity="Device", inversedBy="parts")
|
||||||
|
@ -77,18 +88,6 @@ class DevicePart extends DBElement
|
||||||
*/
|
*/
|
||||||
protected $part;
|
protected $part;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
* @ORM\Column(type="integer", name="quantity")
|
|
||||||
*/
|
|
||||||
protected $quantity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
* @ORM\Column(type="text", name="mountnames")
|
|
||||||
*/
|
|
||||||
protected $mountnames;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ID as an string, defined by the element class.
|
* Returns the ID as an string, defined by the element class.
|
||||||
* This should have a form like P000014, for a part with ID 14.
|
* This should have a form like P000014, for a part with ID 14.
|
||||||
|
|
|
@ -36,12 +36,6 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
*/
|
*/
|
||||||
class Category extends PartsContainingDBElement
|
class Category extends PartsContainingDBElement
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Collection|CategoryAttachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\CategoryAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
|
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
|
||||||
*/
|
*/
|
||||||
|
@ -105,6 +99,11 @@ class Category extends PartsContainingDBElement
|
||||||
* @ORM\Column(type="text")
|
* @ORM\Column(type="text")
|
||||||
*/
|
*/
|
||||||
protected $default_comment = '';
|
protected $default_comment = '';
|
||||||
|
/**
|
||||||
|
* @var Collection|CategoryAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\CategoryAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ID as an string, defined by the element class.
|
* Returns the ID as an string, defined by the element class.
|
||||||
|
|
|
@ -65,26 +65,25 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
class Footprint extends PartsContainingDBElement
|
class Footprint extends PartsContainingDBElement
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var Collection|FootprintAttachment[]
|
* @ORM\ManyToOne(targetEntity="Footprint", inversedBy="children")
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\FootprintAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
|
||||||
*/
|
*/
|
||||||
protected $attachments;
|
protected $parent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Footprint", mappedBy="parent")
|
* @ORM\OneToMany(targetEntity="Footprint", mappedBy="parent")
|
||||||
*/
|
*/
|
||||||
protected $children;
|
protected $children;
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\ManyToOne(targetEntity="Footprint", inversedBy="children")
|
|
||||||
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
|
|
||||||
*/
|
|
||||||
protected $parent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Part", mappedBy="footprint", fetch="EXTRA_LAZY")
|
* @ORM\OneToMany(targetEntity="Part", mappedBy="footprint", fetch="EXTRA_LAZY")
|
||||||
*/
|
*/
|
||||||
protected $parts;
|
protected $parts;
|
||||||
|
/**
|
||||||
|
* @var Collection|FootprintAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\FootprintAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var FootprintAttachment|null
|
* @var FootprintAttachment|null
|
||||||
|
|
|
@ -65,26 +65,25 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
class Manufacturer extends Company
|
class Manufacturer extends Company
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var Collection|ManufacturerAttachment[]
|
* @ORM\ManyToOne(targetEntity="Manufacturer", inversedBy="children")
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\ManufacturerAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
|
||||||
*/
|
*/
|
||||||
protected $attachments;
|
protected $parent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Manufacturer", mappedBy="parent")
|
* @ORM\OneToMany(targetEntity="Manufacturer", mappedBy="parent")
|
||||||
*/
|
*/
|
||||||
protected $children;
|
protected $children;
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\ManyToOne(targetEntity="Manufacturer", inversedBy="children")
|
|
||||||
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
|
|
||||||
*/
|
|
||||||
protected $parent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Part", mappedBy="manufacturer", fetch="EXTRA_LAZY")
|
* @ORM\OneToMany(targetEntity="Part", mappedBy="manufacturer", fetch="EXTRA_LAZY")
|
||||||
*/
|
*/
|
||||||
protected $parts;
|
protected $parts;
|
||||||
|
/**
|
||||||
|
* @var Collection|ManufacturerAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\ManufacturerAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ID as an string, defined by the element class.
|
* Returns the ID as an string, defined by the element class.
|
||||||
|
|
|
@ -41,12 +41,6 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
*/
|
*/
|
||||||
class MeasurementUnit extends PartsContainingDBElement
|
class MeasurementUnit extends PartsContainingDBElement
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Collection|MeasurementUnitAttachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\MeasurementUnitAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string The unit symbol that should be used for the Unit. This could be something like "", g (for grams)
|
* @var string The unit symbol that should be used for the Unit. This could be something like "", g (for grams)
|
||||||
* or m (for meters).
|
* or m (for meters).
|
||||||
|
@ -84,6 +78,11 @@ class MeasurementUnit extends PartsContainingDBElement
|
||||||
* @ORM\OneToMany(targetEntity="Part", mappedBy="partUnit", fetch="EXTRA_LAZY")
|
* @ORM\OneToMany(targetEntity="Part", mappedBy="partUnit", fetch="EXTRA_LAZY")
|
||||||
*/
|
*/
|
||||||
protected $parts;
|
protected $parts;
|
||||||
|
/**
|
||||||
|
* @var Collection|MeasurementUnitAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\MeasurementUnitAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ID as an string, defined by the element class.
|
* Returns the ID as an string, defined by the element class.
|
||||||
|
|
|
@ -60,6 +60,7 @@ use App\Entity\Parts\PartTraits\InstockTrait;
|
||||||
use App\Entity\Parts\PartTraits\ManufacturerTrait;
|
use App\Entity\Parts\PartTraits\ManufacturerTrait;
|
||||||
use App\Entity\Parts\PartTraits\OrderTrait;
|
use App\Entity\Parts\PartTraits\OrderTrait;
|
||||||
use App\Security\Annotations\ColumnSecurity;
|
use App\Security\Annotations\ColumnSecurity;
|
||||||
|
use DateTime;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
@ -82,7 +83,9 @@ class Part extends AttachmentContainingDBElement
|
||||||
use ManufacturerTrait;
|
use ManufacturerTrait;
|
||||||
use OrderTrait;
|
use OrderTrait;
|
||||||
|
|
||||||
/** TODO */
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
protected $devices;
|
protected $devices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,16 +94,9 @@ class Part extends AttachmentContainingDBElement
|
||||||
*/
|
*/
|
||||||
protected $addedDate;
|
protected $addedDate;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \DateTime the date when this element was modified the last time
|
|
||||||
* @ColumnSecurity(type="datetime")
|
|
||||||
* @ORM\Column(type="datetime", name="last_modified", options={"default"="CURRENT_TIMESTAMP"})
|
|
||||||
*/
|
|
||||||
protected $lastModified;
|
|
||||||
|
|
||||||
/** *************************************************************
|
/** *************************************************************
|
||||||
* Overridden properties
|
* Overridden properties
|
||||||
* (They are defined here and not in a trait, to avoid conflicts)
|
* (They are defined here and not in a trait, to avoid conflicts).
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,6 +113,13 @@ class Part extends AttachmentContainingDBElement
|
||||||
*/
|
*/
|
||||||
protected $attachments;
|
protected $attachments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DateTime the date when this element was modified the last time
|
||||||
|
* @ColumnSecurity(type="datetime")
|
||||||
|
* @ORM\Column(type="datetime", name="last_modified", options={"default"="CURRENT_TIMESTAMP"})
|
||||||
|
*/
|
||||||
|
protected $lastModified;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Attachment
|
* @var Attachment
|
||||||
* @ORM\ManyToOne(targetEntity="App\Entity\Attachments\Attachment")
|
* @ORM\ManyToOne(targetEntity="App\Entity\Attachments\Attachment")
|
||||||
|
|
|
@ -29,7 +29,9 @@ use App\Entity\Base\TimestampTrait;
|
||||||
use App\Entity\Parts\PartTraits\InstockTrait;
|
use App\Entity\Parts\PartTraits\InstockTrait;
|
||||||
use App\Validator\Constraints\Selectable;
|
use App\Validator\Constraints\Selectable;
|
||||||
use App\Validator\Constraints\ValidPartLot;
|
use App\Validator\Constraints\ValidPartLot;
|
||||||
|
use DateTime;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Exception;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,8 +60,8 @@ class PartLot extends DBElement
|
||||||
protected $comment = '';
|
protected $comment = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ?\DateTime Set a time until when the lot must be used.
|
* @var ?DateTime Set a time until when the lot must be used.
|
||||||
* Set to null, if the lot can be used indefinitely.
|
* Set to null, if the lot can be used indefinitely.
|
||||||
* @ORM\Column(type="datetime", name="expiration_date", nullable=true)
|
* @ORM\Column(type="datetime", name="expiration_date", nullable=true)
|
||||||
*/
|
*/
|
||||||
protected $expiration_date;
|
protected $expiration_date;
|
||||||
|
@ -72,14 +74,6 @@ class PartLot extends DBElement
|
||||||
*/
|
*/
|
||||||
protected $storage_location;
|
protected $storage_location;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Part The part that is stored in this lot
|
|
||||||
* @ORM\ManyToOne(targetEntity="Part", inversedBy="partLots")
|
|
||||||
* @ORM\JoinColumn(name="id_part", referencedColumnName="id", nullable=false, onDelete="CASCADE")
|
|
||||||
* @Assert\NotNull()
|
|
||||||
*/
|
|
||||||
protected $part;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool If this is set to true, the instock amount is marked as not known
|
* @var bool If this is set to true, the instock amount is marked as not known
|
||||||
* @ORM\Column(type="boolean")
|
* @ORM\Column(type="boolean")
|
||||||
|
@ -99,6 +93,14 @@ class PartLot extends DBElement
|
||||||
*/
|
*/
|
||||||
protected $needs_refill = false;
|
protected $needs_refill = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Part The part that is stored in this lot
|
||||||
|
* @ORM\ManyToOne(targetEntity="Part", inversedBy="partLots")
|
||||||
|
* @ORM\JoinColumn(name="id_part", referencedColumnName="id", nullable=false, onDelete="CASCADE")
|
||||||
|
* @Assert\NotNull()
|
||||||
|
*/
|
||||||
|
protected $part;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ID as an string, defined by the element class.
|
* Returns the ID as an string, defined by the element class.
|
||||||
* This should have a form like P000014, for a part with ID 14.
|
* This should have a form like P000014, for a part with ID 14.
|
||||||
|
@ -116,7 +118,7 @@ class PartLot extends DBElement
|
||||||
*
|
*
|
||||||
* @return bool|null True, if the part lot is expired. Returns null, if no expiration date was set.
|
* @return bool|null True, if the part lot is expired. Returns null, if no expiration date was set.
|
||||||
*
|
*
|
||||||
* @throws \Exception If an error with the DateTime occurs
|
* @throws Exception If an error with the DateTime occurs
|
||||||
*/
|
*/
|
||||||
public function isExpired(): ?bool
|
public function isExpired(): ?bool
|
||||||
{
|
{
|
||||||
|
@ -125,7 +127,7 @@ class PartLot extends DBElement
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if the expiration date is bigger then current time
|
//Check if the expiration date is bigger then current time
|
||||||
return $this->expiration_date < new \DateTime('now');
|
return $this->expiration_date < new DateTime('now');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,9 +177,9 @@ class PartLot extends DBElement
|
||||||
/**
|
/**
|
||||||
* Gets the expiration date for the part lot. Returns null, if no expiration date was set.
|
* Gets the expiration date for the part lot. Returns null, if no expiration date was set.
|
||||||
*
|
*
|
||||||
* @return \DateTime|null
|
* @return DateTime|null
|
||||||
*/
|
*/
|
||||||
public function getExpirationDate(): ?\DateTime
|
public function getExpirationDate(): ?DateTime
|
||||||
{
|
{
|
||||||
return $this->expiration_date;
|
return $this->expiration_date;
|
||||||
}
|
}
|
||||||
|
@ -185,11 +187,11 @@ class PartLot extends DBElement
|
||||||
/**
|
/**
|
||||||
* Sets the expiration date for the part lot. Set to null, if the part lot does not expires.
|
* Sets the expiration date for the part lot. Set to null, if the part lot does not expires.
|
||||||
*
|
*
|
||||||
* @param \DateTime $expiration_date
|
* @param DateTime $expiration_date
|
||||||
*
|
*
|
||||||
* @return PartLot
|
* @return PartLot
|
||||||
*/
|
*/
|
||||||
public function setExpirationDate(?\DateTime $expiration_date): self
|
public function setExpirationDate(?DateTime $expiration_date): self
|
||||||
{
|
{
|
||||||
$this->expiration_date = $expiration_date;
|
$this->expiration_date = $expiration_date;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace App\Entity\Parts\PartTraits;
|
||||||
|
|
||||||
use App\Entity\PriceInformations\Orderdetail;
|
use App\Entity\PriceInformations\Orderdetail;
|
||||||
use App\Security\Annotations\ColumnSecurity;
|
use App\Security\Annotations\ColumnSecurity;
|
||||||
|
use function count;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,7 +184,7 @@ trait OrderTrait
|
||||||
{
|
{
|
||||||
$all_orderdetails = $this->getOrderdetails();
|
$all_orderdetails = $this->getOrderdetails();
|
||||||
|
|
||||||
if (0 === \count($all_orderdetails)) {
|
if (0 === count($all_orderdetails)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,12 +64,6 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
*/
|
*/
|
||||||
class Storelocation extends PartsContainingDBElement
|
class Storelocation extends PartsContainingDBElement
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Collection|StorelocationAttachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\StorelocationAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Storelocation", mappedBy="parent")
|
* @ORM\OneToMany(targetEntity="Storelocation", mappedBy="parent")
|
||||||
*/
|
*/
|
||||||
|
@ -81,6 +75,22 @@ class Storelocation extends PartsContainingDBElement
|
||||||
*/
|
*/
|
||||||
protected $parent;
|
protected $parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var MeasurementUnit|null The measurement unit, which parts can be stored in here
|
||||||
|
* @ORM\ManyToOne(targetEntity="MeasurementUnit")
|
||||||
|
* @ORM\JoinColumn(name="storage_type_id", referencedColumnName="id")
|
||||||
|
*/
|
||||||
|
protected $storage_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToMany(targetEntity="Part", fetch="EXTRA_LAZY")
|
||||||
|
* @ORM\JoinTable(name="part_lots",
|
||||||
|
* joinColumns={@ORM\JoinColumn(name="id_store_location", referencedColumnName="id")},
|
||||||
|
* inverseJoinColumns={@ORM\JoinColumn(name="id_part", referencedColumnName="id")}
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
protected $parts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
* @ORM\Column(type="boolean")
|
* @ORM\Column(type="boolean")
|
||||||
|
@ -98,22 +108,11 @@ class Storelocation extends PartsContainingDBElement
|
||||||
* @ORM\Column(type="boolean")
|
* @ORM\Column(type="boolean")
|
||||||
*/
|
*/
|
||||||
protected $limit_to_existing_parts = false;
|
protected $limit_to_existing_parts = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var MeasurementUnit|null The measurement unit, which parts can be stored in here
|
* @var Collection|StorelocationAttachment[]
|
||||||
* @ORM\ManyToOne(targetEntity="MeasurementUnit")
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\StorelocationAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
* @ORM\JoinColumn(name="storage_type_id", referencedColumnName="id")
|
|
||||||
*/
|
*/
|
||||||
protected $storage_type;
|
protected $attachments;
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\ManyToMany(targetEntity="Part", fetch="EXTRA_LAZY")
|
|
||||||
* @ORM\JoinTable(name="part_lots",
|
|
||||||
* joinColumns={@ORM\JoinColumn(name="id_store_location", referencedColumnName="id")},
|
|
||||||
* inverseJoinColumns={@ORM\JoinColumn(name="id_part", referencedColumnName="id")}
|
|
||||||
* )
|
|
||||||
*/
|
|
||||||
protected $parts;
|
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
*
|
*
|
||||||
|
|
|
@ -67,12 +67,6 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
*/
|
*/
|
||||||
class Supplier extends Company
|
class Supplier extends Company
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Collection|SupplierAttachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\SupplierAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Supplier", mappedBy="parent")
|
* @ORM\OneToMany(targetEntity="Supplier", mappedBy="parent")
|
||||||
*/
|
*/
|
||||||
|
@ -113,6 +107,11 @@ class Supplier extends Company
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
protected $parts;
|
protected $parts;
|
||||||
|
/**
|
||||||
|
* @var Collection|SupplierAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\SupplierAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the currency that should be used by default, when creating a orderdetail with this supplier.
|
* Gets the currency that should be used by default, when creating a orderdetail with this supplier.
|
||||||
|
|
|
@ -43,10 +43,12 @@ class Currency extends StructuralDBElement
|
||||||
public const PRICE_SCALE = 5;
|
public const PRICE_SCALE = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Collection|CurrencyAttachment[]
|
* @var string|null The exchange rate between this currency and the base currency
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\CurrencyAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
* (how many base units the current currency is worth)
|
||||||
|
* @ORM\Column(type="decimal", precision=11, scale=5, nullable=true)
|
||||||
|
* @Assert\Positive()
|
||||||
*/
|
*/
|
||||||
protected $attachments;
|
protected $exchange_rate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string the 3 letter ISO code of the currency
|
* @var string the 3 letter ISO code of the currency
|
||||||
|
@ -55,14 +57,6 @@ class Currency extends StructuralDBElement
|
||||||
*/
|
*/
|
||||||
protected $iso_code;
|
protected $iso_code;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The exchange rate between this currency and the base currency
|
|
||||||
* (how many base units the current currency is worth)
|
|
||||||
* @ORM\Column(type="decimal", precision=11, scale=5, nullable=true)
|
|
||||||
* @Assert\Positive()
|
|
||||||
*/
|
|
||||||
protected $exchange_rate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Currency", mappedBy="parent", cascade={"persist"})
|
* @ORM\OneToMany(targetEntity="Currency", mappedBy="parent", cascade={"persist"})
|
||||||
*/
|
*/
|
||||||
|
@ -74,6 +68,12 @@ class Currency extends StructuralDBElement
|
||||||
*/
|
*/
|
||||||
protected $parent;
|
protected $parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Collection|CurrencyAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\CurrencyAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the 3 letter ISO code of this currency.
|
* Returns the 3 letter ISO code of this currency.
|
||||||
*
|
*
|
||||||
|
|
|
@ -71,21 +71,6 @@ class Orderdetail extends DBElement
|
||||||
{
|
{
|
||||||
use TimestampTrait;
|
use TimestampTrait;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Part
|
|
||||||
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Part", inversedBy="orderdetails")
|
|
||||||
* @ORM\JoinColumn(name="part_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
|
|
||||||
* @Assert\NotNull()
|
|
||||||
*/
|
|
||||||
protected $part;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Supplier
|
|
||||||
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Supplier", inversedBy="orderdetails")
|
|
||||||
* @ORM\JoinColumn(name="id_supplier", referencedColumnName="id")
|
|
||||||
*/
|
|
||||||
protected $supplier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Pricedetail", mappedBy="orderdetail", cascade={"persist", "remove"}, orphanRemoval=true)
|
* @ORM\OneToMany(targetEntity="Pricedetail", mappedBy="orderdetail", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
* @Assert\Valid()
|
* @Assert\Valid()
|
||||||
|
@ -112,6 +97,21 @@ class Orderdetail extends DBElement
|
||||||
*/
|
*/
|
||||||
protected $supplier_product_url = '';
|
protected $supplier_product_url = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Part
|
||||||
|
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Part", inversedBy="orderdetails")
|
||||||
|
* @ORM\JoinColumn(name="part_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
|
||||||
|
* @Assert\NotNull()
|
||||||
|
*/
|
||||||
|
protected $part;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Supplier
|
||||||
|
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Supplier", inversedBy="orderdetails")
|
||||||
|
* @ORM\JoinColumn(name="id_supplier", referencedColumnName="id")
|
||||||
|
*/
|
||||||
|
protected $supplier;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->pricedetails = new ArrayCollection();
|
$this->pricedetails = new ArrayCollection();
|
||||||
|
|
|
@ -72,14 +72,6 @@ class Pricedetail extends DBElement
|
||||||
|
|
||||||
public const PRICE_PRECISION = 5;
|
public const PRICE_PRECISION = 5;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Orderdetail
|
|
||||||
* @ORM\ManyToOne(targetEntity="Orderdetail", inversedBy="pricedetails")
|
|
||||||
* @ORM\JoinColumn(name="orderdetails_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
|
|
||||||
* @Assert\NotNull()
|
|
||||||
*/
|
|
||||||
protected $orderdetail;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string The price related to the detail. (Given in the selected currency)
|
* @var string The price related to the detail. (Given in the selected currency)
|
||||||
* @ORM\Column(type="decimal", precision=11, scale=5)
|
* @ORM\Column(type="decimal", precision=11, scale=5)
|
||||||
|
@ -116,6 +108,14 @@ class Pricedetail extends DBElement
|
||||||
*/
|
*/
|
||||||
protected $manual_input = true;
|
protected $manual_input = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Orderdetail
|
||||||
|
* @ORM\ManyToOne(targetEntity="Orderdetail", inversedBy="pricedetails")
|
||||||
|
* @ORM\JoinColumn(name="orderdetails_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
|
||||||
|
* @Assert\NotNull()
|
||||||
|
*/
|
||||||
|
protected $orderdetail;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
bcscale(static::PRICE_PRECISION);
|
bcscale(static::PRICE_PRECISION);
|
||||||
|
@ -280,6 +280,7 @@ class Pricedetail extends DBElement
|
||||||
* quantity to 100. The single price (20$/100 = 0.2$) will be calculated automatically.
|
* quantity to 100. The single price (20$/100 = 0.2$) will be calculated automatically.
|
||||||
*
|
*
|
||||||
* @param float $new_price_related_quantity the price related quantity
|
* @param float $new_price_related_quantity the price related quantity
|
||||||
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPriceRelatedQuantity(float $new_price_related_quantity): self
|
public function setPriceRelatedQuantity(float $new_price_related_quantity): self
|
||||||
|
|
|
@ -39,12 +39,6 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
*/
|
*/
|
||||||
class Group extends StructuralDBElement implements HasPermissionsInterface
|
class Group extends StructuralDBElement implements HasPermissionsInterface
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Collection|GroupAttachment[]
|
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\ManufacturerAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="Group", mappedBy="parent")
|
* @ORM\OneToMany(targetEntity="Group", mappedBy="parent")
|
||||||
*/
|
*/
|
||||||
|
@ -61,17 +55,22 @@ class Group extends StructuralDBElement implements HasPermissionsInterface
|
||||||
*/
|
*/
|
||||||
protected $users;
|
protected $users;
|
||||||
|
|
||||||
/** @var PermissionsEmbed
|
|
||||||
* @ORM\Embedded(class="PermissionsEmbed", columnPrefix="perms_")
|
|
||||||
* @ValidPermission()
|
|
||||||
*/
|
|
||||||
protected $permissions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool If true all users associated with this group must have enabled some kind of 2 factor authentication
|
* @var bool If true all users associated with this group must have enabled some kind of 2 factor authentication
|
||||||
* @ORM\Column(type="boolean", name="enforce_2fa")
|
* @ORM\Column(type="boolean", name="enforce_2fa")
|
||||||
*/
|
*/
|
||||||
protected $enforce2FA = false;
|
protected $enforce2FA = false;
|
||||||
|
/**
|
||||||
|
* @var Collection|GroupAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\ManufacturerAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
|
/** @var PermissionsEmbed
|
||||||
|
* @ORM\Embedded(class="PermissionsEmbed", columnPrefix="perms_")
|
||||||
|
* @ValidPermission()
|
||||||
|
*/
|
||||||
|
protected $permissions;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||||
namespace App\Entity\UserSystem;
|
namespace App\Entity\UserSystem;
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use InvalidArgumentException;
|
||||||
use Webmozart\Assert\Assert;
|
use Webmozart\Assert\Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -316,7 +317,7 @@ class PermissionsEmbed
|
||||||
public function getBitValue(string $permission_name, int $bit_n): int
|
public function getBitValue(string $permission_name, int $bit_n): int
|
||||||
{
|
{
|
||||||
if (! $this->isValidPermissionName($permission_name)) {
|
if (! $this->isValidPermissionName($permission_name)) {
|
||||||
throw new \InvalidArgumentException(sprintf('No permission with the name "%s" is existing!', $permission_name));
|
throw new InvalidArgumentException(sprintf('No permission with the name "%s" is existing!', $permission_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
$perm_int = (int) $this->{$permission_name};
|
$perm_int = (int) $this->{$permission_name};
|
||||||
|
@ -386,7 +387,7 @@ class PermissionsEmbed
|
||||||
public function setBitValue(string $permission_name, int $bit_n, int $new_value): self
|
public function setBitValue(string $permission_name, int $bit_n, int $new_value): self
|
||||||
{
|
{
|
||||||
if (! $this->isValidPermissionName($permission_name)) {
|
if (! $this->isValidPermissionName($permission_name)) {
|
||||||
throw new \InvalidArgumentException('No permission with the given name is existing!');
|
throw new InvalidArgumentException('No permission with the given name is existing!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->{$permission_name} = static::writeBitPair($this->{$permission_name}, $bit_n, $new_value);
|
$this->{$permission_name} = static::writeBitPair($this->{$permission_name}, $bit_n, $new_value);
|
||||||
|
@ -405,7 +406,7 @@ class PermissionsEmbed
|
||||||
public function getRawPermissionValue(string $permission_name): int
|
public function getRawPermissionValue(string $permission_name): int
|
||||||
{
|
{
|
||||||
if (! $this->isValidPermissionName($permission_name)) {
|
if (! $this->isValidPermissionName($permission_name)) {
|
||||||
throw new \InvalidArgumentException('No permission with the given name is existing!');
|
throw new InvalidArgumentException('No permission with the given name is existing!');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->{$permission_name};
|
return $this->{$permission_name};
|
||||||
|
@ -422,7 +423,7 @@ class PermissionsEmbed
|
||||||
public function setRawPermissionValue(string $permission_name, int $value): self
|
public function setRawPermissionValue(string $permission_name, int $value): self
|
||||||
{
|
{
|
||||||
if (! $this->isValidPermissionName($permission_name)) {
|
if (! $this->isValidPermissionName($permission_name)) {
|
||||||
throw new \InvalidArgumentException(sprintf('No permission with the given name %s is existing!', $permission_name));
|
throw new InvalidArgumentException(sprintf('No permission with the given name %s is existing!', $permission_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->{$permission_name} = $value;
|
$this->{$permission_name} = $value;
|
||||||
|
@ -456,7 +457,7 @@ class PermissionsEmbed
|
||||||
* Reads a bit pair from $data.
|
* Reads a bit pair from $data.
|
||||||
*
|
*
|
||||||
* @param int|string $data The data from where the bits should be extracted from
|
* @param int|string $data The data from where the bits should be extracted from
|
||||||
* @param int $n The number of the lower bit (of the pair) that should be read. Starting from zero.
|
* @param int $n The number of the lower bit (of the pair) that should be read. Starting from zero.
|
||||||
*
|
*
|
||||||
* @return int the value of the bit pair
|
* @return int the value of the bit pair
|
||||||
*/
|
*/
|
||||||
|
@ -464,7 +465,7 @@ class PermissionsEmbed
|
||||||
{
|
{
|
||||||
Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.');
|
Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.');
|
||||||
if (0 !== $n % 2) {
|
if (0 !== $n % 2) {
|
||||||
throw new \InvalidArgumentException('$n must be dividable by 2, because we address bit pairs here!');
|
throw new InvalidArgumentException('$n must be dividable by 2, because we address bit pairs here!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$mask = 0b11 << $n; //Create a mask for the data
|
$mask = 0b11 << $n; //Create a mask for the data
|
||||||
|
@ -487,7 +488,7 @@ class PermissionsEmbed
|
||||||
Assert::greaterThanEq($new, 0, '$new must not be negative, because a bit pair is written! Got %s.');
|
Assert::greaterThanEq($new, 0, '$new must not be negative, because a bit pair is written! Got %s.');
|
||||||
|
|
||||||
if (0 !== $n % 2) {
|
if (0 !== $n % 2) {
|
||||||
throw new \InvalidArgumentException('$n must be dividable by 2, because we address bit pairs here!');
|
throw new InvalidArgumentException('$n must be dividable by 2, because we address bit pairs here!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$mask = 0b11 << $n; //Mask all bits that should be written
|
$mask = 0b11 << $n; //Mask all bits that should be written
|
||||||
|
|
|
@ -76,13 +76,6 @@ class U2FKey implements TwoFactorKeyInterface
|
||||||
*/
|
*/
|
||||||
protected $id;
|
protected $id;
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\ManyToOne(targetEntity="App\Entity\UserSystem\User", inversedBy="u2fKeys")
|
|
||||||
*
|
|
||||||
* @var User
|
|
||||||
**/
|
|
||||||
protected $user;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string")
|
* @ORM\Column(type="string")
|
||||||
*
|
*
|
||||||
|
@ -90,6 +83,13 @@ class U2FKey implements TwoFactorKeyInterface
|
||||||
**/
|
**/
|
||||||
protected $name;
|
protected $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity="App\Entity\UserSystem\User", inversedBy="u2fKeys")
|
||||||
|
*
|
||||||
|
* @var User
|
||||||
|
**/
|
||||||
|
protected $user;
|
||||||
|
|
||||||
public function fromRegistrationData(Registration $data): void
|
public function fromRegistrationData(Registration $data): void
|
||||||
{
|
{
|
||||||
$this->keyHandle = $data->keyHandle;
|
$this->keyHandle = $data->keyHandle;
|
||||||
|
|
|
@ -59,9 +59,13 @@ use App\Entity\PriceInformations\Currency;
|
||||||
use App\Security\Interfaces\HasPermissionsInterface;
|
use App\Security\Interfaces\HasPermissionsInterface;
|
||||||
use App\Validator\Constraints\Selectable;
|
use App\Validator\Constraints\Selectable;
|
||||||
use App\Validator\Constraints\ValidPermission;
|
use App\Validator\Constraints\ValidPermission;
|
||||||
|
use function count;
|
||||||
|
use DateTime;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Exception;
|
||||||
|
use function in_array;
|
||||||
use R\U2FTwoFactorBundle\Model\U2F\TwoFactorInterface as U2FTwoFactorInterface;
|
use R\U2FTwoFactorBundle\Model\U2F\TwoFactorInterface as U2FTwoFactorInterface;
|
||||||
use R\U2FTwoFactorBundle\Model\U2F\TwoFactorKeyInterface;
|
use R\U2FTwoFactorBundle\Model\U2F\TwoFactorKeyInterface;
|
||||||
use Scheb\TwoFactorBundle\Model\BackupCodeInterface;
|
use Scheb\TwoFactorBundle\Model\BackupCodeInterface;
|
||||||
|
@ -84,7 +88,9 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
{
|
{
|
||||||
use MasterAttachmentTrait;
|
use MasterAttachmentTrait;
|
||||||
|
|
||||||
/** The User id of the anonymous user */
|
/**
|
||||||
|
* The User id of the anonymous user
|
||||||
|
*/
|
||||||
public const ID_ANONYMOUS = 1;
|
public const ID_ANONYMOUS = 1;
|
||||||
|
|
||||||
public const AVAILABLE_THEMES = ['bootstrap', 'cerulean', 'cosmo', 'cyborg', 'darkly', 'flatly', 'journal',
|
public const AVAILABLE_THEMES = ['bootstrap', 'cerulean', 'cosmo', 'cyborg', 'darkly', 'flatly', 'journal',
|
||||||
|
@ -92,79 +98,10 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
'spacelab', 'united', 'yeti', ];
|
'spacelab', 'united', 'yeti', ];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Collection|UserAttachment[]
|
* @var bool Determines if the user is disabled (user can not log in)
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\UserAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
|
||||||
*/
|
|
||||||
protected $attachments;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\Id()
|
|
||||||
* @ORM\GeneratedValue()
|
|
||||||
* @ORM\Column(type="integer")
|
|
||||||
*/
|
|
||||||
protected $id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\Column(type="string", length=180, unique=true)
|
|
||||||
* @Assert\NotBlank
|
|
||||||
*/
|
|
||||||
protected $name = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* //@ORM\Column(type="json").
|
|
||||||
*/
|
|
||||||
//protected $roles = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The hashed password
|
|
||||||
* @ORM\Column(type="string", nullable=true)
|
|
||||||
*/
|
|
||||||
protected $password;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool True if the user needs to change password after log in
|
|
||||||
* @ORM\Column(type="boolean")
|
* @ORM\Column(type="boolean")
|
||||||
*/
|
*/
|
||||||
protected $need_pw_change = true;
|
protected $disabled = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The first name of the User
|
|
||||||
* @ORM\Column(type="string", length=255, nullable=true)
|
|
||||||
*/
|
|
||||||
protected $first_name = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The last name of the User
|
|
||||||
* @ORM\Column(type="string", length=255, nullable=true)
|
|
||||||
*/
|
|
||||||
protected $last_name = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The department the user is working
|
|
||||||
* @ORM\Column(type="string", length=255, nullable=true)
|
|
||||||
*/
|
|
||||||
protected $department = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The email address of the user
|
|
||||||
* @ORM\Column(type="string", length=255, nullable=true)
|
|
||||||
* @Assert\Email()
|
|
||||||
*/
|
|
||||||
protected $email = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The language/locale the user prefers
|
|
||||||
* @ORM\Column(type="string", name="config_language", nullable=true)
|
|
||||||
* @Assert\Language()
|
|
||||||
*/
|
|
||||||
protected $language = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The timezone the user prefers
|
|
||||||
* @ORM\Column(type="string", name="config_timezone", nullable=true)
|
|
||||||
* @Assert\Timezone()
|
|
||||||
*/
|
|
||||||
protected $timezone = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null The theme
|
* @var string|null The theme
|
||||||
|
@ -173,6 +110,40 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
*/
|
*/
|
||||||
protected $theme = '';
|
protected $theme = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null The hash of a token the user must provide when he wants to reset his password.
|
||||||
|
* @ORM\Column(type="string", nullable=true)
|
||||||
|
*/
|
||||||
|
protected $pw_reset_token = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="text", name="config_instock_comment_a")
|
||||||
|
*/
|
||||||
|
protected $instock_comment_a = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="text", name="config_instock_comment_w")
|
||||||
|
*/
|
||||||
|
protected $instock_comment_w = '';
|
||||||
|
|
||||||
|
/** @var int The version of the trusted device cookie. Used to invalidate all trusted device cookies at once.
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
protected $trustedDeviceCookieVersion = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]|null A list of backup codes that can be used, if the user has no access to its Google Authenticator device
|
||||||
|
* @ORM\Column(type="json")
|
||||||
|
*/
|
||||||
|
protected $backupCodes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Id()
|
||||||
|
* @ORM\GeneratedValue()
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
protected $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Group|null the group this user belongs to
|
* @var Group|null the group this user belongs to
|
||||||
* @ORM\ManyToOne(targetEntity="Group", inversedBy="users", fetch="EAGER")
|
* @ORM\ManyToOne(targetEntity="Group", inversedBy="users", fetch="EAGER")
|
||||||
|
@ -188,25 +159,66 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
protected $googleAuthenticatorSecret;
|
protected $googleAuthenticatorSecret;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[]|null A list of backup codes that can be used, if the user has no access to its Google Authenticator device
|
* @var string|null The timezone the user prefers
|
||||||
* @ORM\Column(type="json")
|
* @ORM\Column(type="string", name="config_timezone", nullable=true)
|
||||||
|
* @Assert\Timezone()
|
||||||
*/
|
*/
|
||||||
protected $backupCodes = [];
|
protected $timezone = '';
|
||||||
|
|
||||||
/** @var \DateTime The time when the backup codes were generated
|
/**
|
||||||
* @ORM\Column(type="datetime", nullable=true)
|
* @var string|null The language/locale the user prefers
|
||||||
|
* @ORM\Column(type="string", name="config_language", nullable=true)
|
||||||
|
* @Assert\Language()
|
||||||
*/
|
*/
|
||||||
protected $backupCodesGenerationDate;
|
protected $language = '';
|
||||||
|
|
||||||
/** @var int The version of the trusted device cookie. Used to invalidate all trusted device cookies at once.
|
/**
|
||||||
* @ORM\Column(type="integer")
|
* @var string|null The email address of the user
|
||||||
|
* @ORM\Column(type="string", length=255, nullable=true)
|
||||||
|
* @Assert\Email()
|
||||||
*/
|
*/
|
||||||
protected $trustedDeviceCookieVersion = 0;
|
protected $email = '';
|
||||||
|
|
||||||
/** @var Collection<TwoFactorKeyInterface>
|
/**
|
||||||
* @ORM\OneToMany(targetEntity="App\Entity\UserSystem\U2FKey", mappedBy="user", cascade={"REMOVE"}, orphanRemoval=true)
|
* @var string|null The department the user is working
|
||||||
|
* @ORM\Column(type="string", length=255, nullable=true)
|
||||||
*/
|
*/
|
||||||
protected $u2fKeys;
|
protected $department = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null The last name of the User
|
||||||
|
* @ORM\Column(type="string", length=255, nullable=true)
|
||||||
|
*/
|
||||||
|
protected $last_name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null The first name of the User
|
||||||
|
* @ORM\Column(type="string", length=255, nullable=true)
|
||||||
|
*/
|
||||||
|
protected $first_name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool True if the user needs to change password after log in
|
||||||
|
* @ORM\Column(type="boolean")
|
||||||
|
*/
|
||||||
|
protected $need_pw_change = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* //@ORM\Column(type="json").
|
||||||
|
*/
|
||||||
|
//protected $roles = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null The hashed password
|
||||||
|
* @ORM\Column(type="string", nullable=true)
|
||||||
|
*/
|
||||||
|
protected $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=180, unique=true)
|
||||||
|
* @Assert\NotBlank
|
||||||
|
*/
|
||||||
|
protected $name = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
|
@ -214,6 +226,22 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
*/
|
*/
|
||||||
protected $settings = [];
|
protected $settings = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Collection|UserAttachment[]
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\UserAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $attachments;
|
||||||
|
|
||||||
|
/** @var DateTime The time when the backup codes were generated
|
||||||
|
* @ORM\Column(type="datetime", nullable=true)
|
||||||
|
*/
|
||||||
|
protected $backupCodesGenerationDate;
|
||||||
|
|
||||||
|
/** @var Collection<TwoFactorKeyInterface>
|
||||||
|
* @ORM\OneToMany(targetEntity="App\Entity\UserSystem\U2FKey", mappedBy="user", cascade={"REMOVE"}, orphanRemoval=true)
|
||||||
|
*/
|
||||||
|
protected $u2fKeys;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Currency|null The currency the user wants to see prices in.
|
* @var Currency|null The currency the user wants to see prices in.
|
||||||
* Dont use fetch=EAGER here, this will cause problems with setting the currency setting.
|
* Dont use fetch=EAGER here, this will cause problems with setting the currency setting.
|
||||||
|
@ -232,33 +260,11 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
protected $permissions;
|
protected $permissions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="text", name="config_instock_comment_w")
|
* @var DateTime The time until the password reset token is valid.
|
||||||
*/
|
|
||||||
protected $instock_comment_w = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ORM\Column(type="text", name="config_instock_comment_a")
|
|
||||||
*/
|
|
||||||
protected $instock_comment_a = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The hash of a token the user must provide when he wants to reset his password.
|
|
||||||
* @ORM\Column(type="string", nullable=true)
|
|
||||||
*/
|
|
||||||
protected $pw_reset_token = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \DateTime The time until the password reset token is valid.
|
|
||||||
* @ORM\Column(type="datetime", nullable=true)
|
* @ORM\Column(type="datetime", nullable=true)
|
||||||
*/
|
*/
|
||||||
protected $pw_reset_expires = null;
|
protected $pw_reset_expires = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool Determines if the user is disabled (user can not log in)
|
|
||||||
* @ORM\Column(type="boolean")
|
|
||||||
*/
|
|
||||||
protected $disabled = false;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
@ -466,9 +472,9 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
/**
|
/**
|
||||||
* Gets the datetime when the password reset token expires.
|
* Gets the datetime when the password reset token expires.
|
||||||
*
|
*
|
||||||
* @return \DateTime
|
* @return DateTime
|
||||||
*/
|
*/
|
||||||
public function getPwResetExpires(): \DateTime
|
public function getPwResetExpires(): DateTime
|
||||||
{
|
{
|
||||||
return $this->pw_reset_expires;
|
return $this->pw_reset_expires;
|
||||||
}
|
}
|
||||||
|
@ -478,7 +484,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
*
|
*
|
||||||
* @return User
|
* @return User
|
||||||
*/
|
*/
|
||||||
public function setPwResetExpires(\DateTime $pw_reset_expires): self
|
public function setPwResetExpires(DateTime $pw_reset_expires): self
|
||||||
{
|
{
|
||||||
$this->pw_reset_expires = $pw_reset_expires;
|
$this->pw_reset_expires = $pw_reset_expires;
|
||||||
|
|
||||||
|
@ -769,7 +775,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
*/
|
*/
|
||||||
public function isBackupCode(string $code): bool
|
public function isBackupCode(string $code): bool
|
||||||
{
|
{
|
||||||
return \in_array($code, $this->backupCodes, true);
|
return in_array($code, $this->backupCodes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -802,7 +808,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
*
|
||||||
* @throws \Exception If an error with the datetime occurs
|
* @throws Exception If an error with the datetime occurs
|
||||||
*/
|
*/
|
||||||
public function setBackupCodes(array $codes): self
|
public function setBackupCodes(array $codes): self
|
||||||
{
|
{
|
||||||
|
@ -810,7 +816,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
if (empty($codes)) {
|
if (empty($codes)) {
|
||||||
$this->backupCodesGenerationDate = null;
|
$this->backupCodesGenerationDate = null;
|
||||||
} else {
|
} else {
|
||||||
$this->backupCodesGenerationDate = new \DateTime();
|
$this->backupCodesGenerationDate = new DateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -819,9 +825,9 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
/**
|
/**
|
||||||
* Return the date when the backup codes were generated.
|
* Return the date when the backup codes were generated.
|
||||||
*
|
*
|
||||||
* @return \DateTime|null
|
* @return DateTime|null
|
||||||
*/
|
*/
|
||||||
public function getBackupCodesGenerationDate(): ?\DateTime
|
public function getBackupCodesGenerationDate(): ?DateTime
|
||||||
{
|
{
|
||||||
return $this->backupCodesGenerationDate;
|
return $this->backupCodesGenerationDate;
|
||||||
}
|
}
|
||||||
|
@ -852,7 +858,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
|
||||||
*/
|
*/
|
||||||
public function isU2FAuthEnabled(): bool
|
public function isU2FAuthEnabled(): bool
|
||||||
{
|
{
|
||||||
return \count($this->u2fKeys) > 0;
|
return count($this->u2fKeys) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,6 +32,7 @@ use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||||
use Doctrine\ORM\Mapping\PostRemove;
|
use Doctrine\ORM\Mapping\PostRemove;
|
||||||
use Doctrine\ORM\Mapping\PreUpdate;
|
use Doctrine\ORM\Mapping\PreUpdate;
|
||||||
|
use SplFileInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This listener watches for changes on attachments and deletes the files associated with an attachment, that are not
|
* This listener watches for changes on attachments and deletes the files associated with an attachment, that are not
|
||||||
|
@ -63,7 +64,7 @@ class AttachmentDeleteListener
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = new \SplFileInfo($this->pathResolver->placeholderToRealPath($event->getOldValue('path')));
|
$file = new SplFileInfo($this->pathResolver->placeholderToRealPath($event->getOldValue('path')));
|
||||||
$this->attachmentReverseSearch->deleteIfNotUsed($file);
|
$this->attachmentReverseSearch->deleteIfNotUsed($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ use App\Entity\UserSystem\User;
|
||||||
use App\Services\UserCacheKeyGenerator;
|
use App\Services\UserCacheKeyGenerator;
|
||||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use function get_class;
|
||||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||||
|
|
||||||
class TreeCacheInvalidationListener
|
class TreeCacheInvalidationListener
|
||||||
|
@ -53,7 +54,7 @@ class TreeCacheInvalidationListener
|
||||||
{
|
{
|
||||||
//If an element was changed, then invalidate all cached trees with this element class
|
//If an element was changed, then invalidate all cached trees with this element class
|
||||||
if ($element instanceof StructuralDBElement) {
|
if ($element instanceof StructuralDBElement) {
|
||||||
$secure_class_name = str_replace('\\', '_', \get_class($element));
|
$secure_class_name = str_replace('\\', '_', get_class($element));
|
||||||
$this->cache->invalidateTags([$secure_class_name]);
|
$this->cache->invalidateTags([$secure_class_name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
/**
|
/**
|
||||||
* This event listener shows an login successful flash to the user after login.
|
* This event listener shows an login successful flash to the user after login.
|
||||||
*/
|
*/
|
||||||
class LoginSuccessListener implements EventSubscriberInterface
|
final class LoginSuccessListener implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
protected $translator;
|
protected $translator;
|
||||||
protected $flashBag;
|
protected $flashBag;
|
||||||
|
|
|
@ -32,7 +32,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
class LogoutOnDisabledUserListener implements EventSubscriberInterface
|
final class LogoutOnDisabledUserListener implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
protected $security;
|
protected $security;
|
||||||
protected $translator;
|
protected $translator;
|
||||||
|
|
|
@ -29,7 +29,7 @@ use Symfony\Component\Mailer\Event\MessageEvent;
|
||||||
use Symfony\Component\Mime\Address;
|
use Symfony\Component\Mime\Address;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
|
|
||||||
class MailFromListener implements EventSubscriberInterface
|
final class MailFromListener implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
protected $email;
|
protected $email;
|
||||||
protected $name;
|
protected $name;
|
||||||
|
|
|
@ -37,7 +37,7 @@ use Symfony\Component\Security\Http\HttpUtils;
|
||||||
* to setup a 2FA method (enforcement can be set per group).
|
* to setup a 2FA method (enforcement can be set per group).
|
||||||
* In this cases the user is unable to access sites other than the whitelisted (see ALLOWED_ROUTES).
|
* In this cases the user is unable to access sites other than the whitelisted (see ALLOWED_ROUTES).
|
||||||
*/
|
*/
|
||||||
class PasswordChangeNeededSubscriber implements EventSubscriberInterface
|
final class PasswordChangeNeededSubscriber implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string[] The routes the user is allowed to access without being redirected.
|
* @var string[] The routes the user is allowed to access without being redirected.
|
||||||
|
@ -51,7 +51,9 @@ class PasswordChangeNeededSubscriber implements EventSubscriberInterface
|
||||||
'logout',
|
'logout',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var string The route the user will redirected to, if he needs to change this password */
|
/**
|
||||||
|
* @var string The route the user will redirected to, if he needs to change this password
|
||||||
|
*/
|
||||||
public const REDIRECT_TARGET = 'user_settings';
|
public const REDIRECT_TARGET = 'user_settings';
|
||||||
protected $security;
|
protected $security;
|
||||||
protected $flashBag;
|
protected $flashBag;
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||||
|
|
||||||
class SymfonyDebugToolbarSubscriber implements EventSubscriberInterface
|
final class SymfonyDebugToolbarSubscriber implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
protected $kernel;
|
protected $kernel;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ use Symfony\Component\Security\Core\Security;
|
||||||
/**
|
/**
|
||||||
* The purpose of this event listener is to set the timezone to the one preferred by the user.
|
* The purpose of this event listener is to set the timezone to the one preferred by the user.
|
||||||
*/
|
*/
|
||||||
class TimezoneListener implements EventSubscriberInterface
|
final class TimezoneListener implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
protected $default_timezone;
|
protected $default_timezone;
|
||||||
protected $security;
|
protected $security;
|
||||||
|
|
|
@ -32,13 +32,15 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
|
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
class U2FRegistrationSubscriber implements EventSubscriberInterface
|
final class U2FRegistrationSubscriber implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
protected $em;
|
protected $em;
|
||||||
|
|
||||||
protected $demo_mode;
|
protected $demo_mode;
|
||||||
protected $flashBag;
|
protected $flashBag;
|
||||||
/** @var UrlGeneratorInterface */
|
/**
|
||||||
|
* @var UrlGeneratorInterface
|
||||||
|
*/
|
||||||
private $router;
|
private $router;
|
||||||
|
|
||||||
public function __construct(UrlGeneratorInterface $router, EntityManagerInterface $entityManager, FlashBagInterface $flashBag, bool $demo_mode)
|
public function __construct(UrlGeneratorInterface $router, EntityManagerInterface $entityManager, FlashBagInterface $flashBag, bool $demo_mode)
|
||||||
|
@ -49,7 +51,9 @@ class U2FRegistrationSubscriber implements EventSubscriberInterface
|
||||||
$this->flashBag = $flashBag;
|
$this->flashBag = $flashBag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return string[] **/
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
public static function getSubscribedEvents(): array
|
public static function getSubscribedEvents(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -24,6 +24,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
class AttachmentDownloadException extends \RuntimeException
|
use RuntimeException;
|
||||||
|
|
||||||
|
class AttachmentDownloadException extends RuntimeException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
class EntityNotSupportedException extends \InvalidArgumentException
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
class EntityNotSupportedException extends InvalidArgumentException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,12 +46,16 @@ class AttachmentTypeAdminForm extends BaseEntityAdminForm
|
||||||
{
|
{
|
||||||
$is_new = null === $entity->getID();
|
$is_new = null === $entity->getID();
|
||||||
|
|
||||||
$builder->add('filetype_filter', TextType::class, ['required' => false,
|
$builder->add('filetype_filter', TextType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'attachment_type.edit.filetype_filter',
|
'label' => 'attachment_type.edit.filetype_filter',
|
||||||
'help' => 'attachment_type.edit.filetype_filter.help',
|
'help' => 'attachment_type.edit.filetype_filter.help',
|
||||||
'attr' => ['placeholder' => 'attachment_type.edit.filetype_filter.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'attachment_type.edit.filetype_filter.placeholder',
|
||||||
|
],
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
//Normalize data before writing it to database
|
//Normalize data before writing it to database
|
||||||
$builder->get('filetype_filter')->addViewTransformer(new CallbackTransformer(
|
$builder->get('filetype_filter')->addViewTransformer(new CallbackTransformer(
|
||||||
|
|
|
@ -31,6 +31,7 @@ use App\Form\AttachmentFormType;
|
||||||
use App\Form\Type\MasterPictureAttachmentType;
|
use App\Form\Type\MasterPictureAttachmentType;
|
||||||
use App\Form\Type\StructuralEntityType;
|
use App\Form\Type\StructuralEntityType;
|
||||||
use FOS\CKEditorBundle\Form\Type\CKEditorType;
|
use FOS\CKEditorBundle\Form\Type\CKEditorType;
|
||||||
|
use function get_class;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
@ -66,24 +67,42 @@ class BaseEntityAdminForm extends AbstractType
|
||||||
$is_new = null === $entity->getID();
|
$is_new = null === $entity->getID();
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->add('name', TextType::class, ['empty_data' => '', 'label' => 'name.label',
|
->add('name', TextType::class, [
|
||||||
'attr' => ['placeholder' => 'part.name.placeholder'],
|
'empty_data' => '',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ])
|
'label' => 'name.label',
|
||||||
|
'attr' => [
|
||||||
|
'placeholder' => 'part.name.placeholder',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
])
|
||||||
|
|
||||||
->add('parent', StructuralEntityType::class, ['class' => \get_class($entity),
|
->add('parent', StructuralEntityType::class, [
|
||||||
'required' => false, 'label' => 'parent.label',
|
'class' => get_class($entity),
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity), ])
|
'required' => false,
|
||||||
|
'label' => 'parent.label',
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||||
|
])
|
||||||
|
|
||||||
->add('not_selectable', CheckboxType::class, ['required' => false,
|
->add('not_selectable', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'entity.edit.not_selectable',
|
'label' => 'entity.edit.not_selectable',
|
||||||
'help' => 'entity.edit.not_selectable.help',
|
'help' => 'entity.edit.not_selectable.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ])
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
])
|
||||||
|
|
||||||
->add('comment', CKEditorType::class, ['required' => false, 'empty_data' => '',
|
->add('comment', CKEditorType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => '',
|
||||||
'label' => 'comment.label',
|
'label' => 'comment.label',
|
||||||
'attr' => ['rows' => 4], 'help' => 'bbcode.hint',
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'rows' => 4,
|
||||||
|
],
|
||||||
|
'help' => 'bbcode.hint',
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$this->additionalFormElements($builder, $options, $entity);
|
$this->additionalFormElements($builder, $options, $entity);
|
||||||
|
|
||||||
|
@ -110,10 +129,15 @@ class BaseEntityAdminForm extends AbstractType
|
||||||
//Buttons
|
//Buttons
|
||||||
$builder->add('save', SubmitType::class, [
|
$builder->add('save', SubmitType::class, [
|
||||||
'label' => $is_new ? 'entity.create' : 'entity.edit.save',
|
'label' => $is_new ? 'entity.create' : 'entity.edit.save',
|
||||||
'attr' => ['class' => $is_new ? 'btn-success' : ''],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ])
|
'class' => $is_new ? 'btn-success' : '',
|
||||||
->add('reset', ResetType::class, ['label' => 'entity.edit.reset',
|
],
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
])
|
||||||
|
->add('reset', ResetType::class, [
|
||||||
|
'label' => 'entity.edit.reset',
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function additionalFormElements(FormBuilderInterface $builder, array $options, NamedDBElement $entity): void
|
protected function additionalFormElements(FormBuilderInterface $builder, array $options, NamedDBElement $entity): void
|
||||||
|
|
|
@ -35,48 +35,84 @@ class CategoryAdminForm extends BaseEntityAdminForm
|
||||||
{
|
{
|
||||||
$is_new = null === $entity->getID();
|
$is_new = null === $entity->getID();
|
||||||
|
|
||||||
$builder->add('disable_footprints', CheckboxType::class, ['required' => false,
|
$builder->add('disable_footprints', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'category.edit.disable_footprints',
|
'label' => 'category.edit.disable_footprints',
|
||||||
'help' => 'category.edit.disable_footprints.help',
|
'help' => 'category.edit.disable_footprints.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('disable_manufacturers', CheckboxType::class, ['required' => false,
|
$builder->add('disable_manufacturers', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'category.edit.disable_manufacturers',
|
'label' => 'category.edit.disable_manufacturers',
|
||||||
'help' => 'category.edit.disable_manufacturers.help',
|
'help' => 'category.edit.disable_manufacturers.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('disable_autodatasheets', CheckboxType::class, ['required' => false,
|
$builder->add('disable_autodatasheets', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'category.edit.disable_autodatasheets',
|
'label' => 'category.edit.disable_autodatasheets',
|
||||||
'help' => 'category.edit.disable_autodatasheets.help',
|
'help' => 'category.edit.disable_autodatasheets.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('disable_properties', CheckboxType::class, ['required' => false,
|
$builder->add('disable_properties', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'category.edit.disable_properties',
|
'label' => 'category.edit.disable_properties',
|
||||||
'help' => 'category.edit.disable_properties.help',
|
'help' => 'category.edit.disable_properties.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('partname_hint', TextType::class, ['required' => false, 'empty_data' => '',
|
$builder->add('partname_hint', TextType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => '',
|
||||||
'label' => 'category.edit.partname_hint',
|
'label' => 'category.edit.partname_hint',
|
||||||
'attr' => ['placeholder' => 'category.edit.partname_hint.placeholder'],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'placeholder' => 'category.edit.partname_hint.placeholder',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('partname_regex', TextType::class, ['required' => false, 'empty_data' => '',
|
$builder->add('partname_regex', TextType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => '',
|
||||||
'label' => 'category.edit.partname_regex',
|
'label' => 'category.edit.partname_regex',
|
||||||
'attr' => ['placeholder' => 'category.edit.partname_regex.placeholder'],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'placeholder' => 'category.edit.partname_regex.placeholder',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('default_description', TextType::class, ['required' => false, 'empty_data' => '',
|
$builder->add('default_description', TextType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => '',
|
||||||
'label' => 'category.edit.default_description',
|
'label' => 'category.edit.default_description',
|
||||||
'attr' => ['placeholder' => 'category.edit.default_description.placeholder'],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'placeholder' => 'category.edit.default_description.placeholder',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('default_comment', TextType::class, ['required' => false, 'empty_data' => '',
|
$builder->add('default_comment', TextType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => '',
|
||||||
'label' => 'category.edit.default_comment',
|
'label' => 'category.edit.default_comment',
|
||||||
'attr' => ['placeholder' => 'category.edit.default_comment.placeholder'],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'placeholder' => 'category.edit.default_comment.placeholder',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,14 +40,19 @@ class CompanyForm extends BaseEntityAdminForm
|
||||||
$builder->add('address', TextareaType::class, [
|
$builder->add('address', TextareaType::class, [
|
||||||
'label' => 'company.edit.address',
|
'label' => 'company.edit.address',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
'attr' => ['placeholder' => 'company.edit.address.placeholder'], 'required' => false,
|
'attr' => [
|
||||||
|
'placeholder' => 'company.edit.address.placeholder',
|
||||||
|
],
|
||||||
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('phone_number', TelType::class, [
|
$builder->add('phone_number', TelType::class, [
|
||||||
'label' => 'company.edit.phone_number',
|
'label' => 'company.edit.phone_number',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
'attr' => ['placeholder' => 'company.edit.phone_number.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'company.edit.phone_number.placeholder',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
@ -55,21 +60,30 @@ class CompanyForm extends BaseEntityAdminForm
|
||||||
$builder->add('fax_number', TelType::class, [
|
$builder->add('fax_number', TelType::class, [
|
||||||
'label' => 'company.edit.fax_number',
|
'label' => 'company.edit.fax_number',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
'attr' => ['placeholder' => 'company.fax_number.placeholder'], 'required' => false,
|
'attr' => [
|
||||||
|
'placeholder' => 'company.fax_number.placeholder',
|
||||||
|
],
|
||||||
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('email_address', EmailType::class, [
|
$builder->add('email_address', EmailType::class, [
|
||||||
'label' => 'company.edit.email',
|
'label' => 'company.edit.email',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
'attr' => ['placeholder' => 'company.edit.email.placeholder'], 'required' => false,
|
'attr' => [
|
||||||
|
'placeholder' => 'company.edit.email.placeholder',
|
||||||
|
],
|
||||||
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('website', UrlType::class, [
|
$builder->add('website', UrlType::class, [
|
||||||
'label' => 'company.edit.website',
|
'label' => 'company.edit.website',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
'attr' => ['placeholder' => 'company.edit.website.placeholder'], 'required' => false,
|
'attr' => [
|
||||||
|
'placeholder' => 'company.edit.website.placeholder',
|
||||||
|
],
|
||||||
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -77,7 +91,9 @@ class CompanyForm extends BaseEntityAdminForm
|
||||||
'label' => 'company.edit.auto_product_url',
|
'label' => 'company.edit.auto_product_url',
|
||||||
'help' => 'company.edit.auto_product_url.help',
|
'help' => 'company.edit.auto_product_url.help',
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
'attr' => ['placeholder' => 'company.edit.auto_product_url.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'company.edit.auto_product_url.placeholder',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -39,14 +39,19 @@ class CurrencyAdminForm extends BaseEntityAdminForm
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'currency.edit.iso_code',
|
'label' => 'currency.edit.iso_code',
|
||||||
'preferred_choices' => ['EUR', 'USD', 'GBP', 'JPY', 'CNY'],
|
'preferred_choices' => ['EUR', 'USD', 'GBP', 'JPY', 'CNY'],
|
||||||
'attr' => ['class' => 'selectpicker', 'data-live-search' => true],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'class' => 'selectpicker',
|
||||||
|
'data-live-search' => true,
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('exchange_rate', MoneyType::class, [
|
$builder->add('exchange_rate', MoneyType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'currency.edit.exchange_rate',
|
'label' => 'currency.edit.exchange_rate',
|
||||||
'currency' => $this->params->get('default_currency'),
|
'currency' => $this->params->get('default_currency'),
|
||||||
'scale' => 6,
|
'scale' => 6,
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,13 @@ class GroupAdminForm extends BaseEntityAdminForm
|
||||||
{
|
{
|
||||||
$is_new = null === $entity->getID();
|
$is_new = null === $entity->getID();
|
||||||
|
|
||||||
$builder->add('enforce2FA', CheckboxType::class, ['required' => false,
|
$builder->add('enforce2FA', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'group.edit.enforce_2fa',
|
'label' => 'group.edit.enforce_2fa',
|
||||||
'help' => 'entity.edit.enforce_2fa.help',
|
'help' => 'entity.edit.enforce_2fa.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -56,12 +56,20 @@ class ImportType extends AbstractType
|
||||||
$builder
|
$builder
|
||||||
|
|
||||||
->add('format', ChoiceType::class, [
|
->add('format', ChoiceType::class, [
|
||||||
'choices' => ['JSON' => 'json', 'XML' => 'xml', 'CSV' => 'csv', 'YAML' => 'yaml'],
|
'choices' => [
|
||||||
|
'JSON' => 'json',
|
||||||
|
'XML' => 'xml',
|
||||||
|
'CSV' => 'csv',
|
||||||
|
'YAML' => 'yaml',
|
||||||
|
],
|
||||||
'label' => 'export.format',
|
'label' => 'export.format',
|
||||||
'disabled' => $disabled, ])
|
'disabled' => $disabled,
|
||||||
->add('csv_separator', TextType::class, ['data' => ';',
|
])
|
||||||
|
->add('csv_separator', TextType::class, [
|
||||||
|
'data' => ';',
|
||||||
'label' => 'import.csv_separator',
|
'label' => 'import.csv_separator',
|
||||||
'disabled' => $disabled, ]);
|
'disabled' => $disabled,
|
||||||
|
]);
|
||||||
|
|
||||||
if ($entity instanceof StructuralDBElement) {
|
if ($entity instanceof StructuralDBElement) {
|
||||||
$builder->add('parent', StructuralEntityType::class, [
|
$builder->add('parent', StructuralEntityType::class, [
|
||||||
|
@ -74,19 +82,38 @@ class ImportType extends AbstractType
|
||||||
|
|
||||||
$builder->add('file', FileType::class, [
|
$builder->add('file', FileType::class, [
|
||||||
'label' => 'import.file',
|
'label' => 'import.file',
|
||||||
'attr' => ['class' => 'file', 'data-show-preview' => 'false', 'data-show-upload' => 'false'],
|
'attr' => [
|
||||||
|
'class' => 'file',
|
||||||
|
'data-show-preview' => 'false',
|
||||||
|
'data-show-upload' => 'false',
|
||||||
|
],
|
||||||
'disabled' => $disabled,
|
'disabled' => $disabled,
|
||||||
])
|
])
|
||||||
|
|
||||||
->add('preserve_children', CheckboxType::class, ['data' => true, 'required' => false,
|
->add('preserve_children', CheckboxType::class, [
|
||||||
|
'data' => true,
|
||||||
|
'required' => false,
|
||||||
'label' => 'import.preserve_children',
|
'label' => 'import.preserve_children',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'], 'disabled' => $disabled, ])
|
'label_attr' => [
|
||||||
->add('abort_on_validation_error', CheckboxType::class, ['data' => true, 'required' => false,
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => $disabled,
|
||||||
|
])
|
||||||
|
->add('abort_on_validation_error', CheckboxType::class, [
|
||||||
|
'data' => true,
|
||||||
|
'required' => false,
|
||||||
'label' => 'import.abort_on_validation',
|
'label' => 'import.abort_on_validation',
|
||||||
'help' => 'import.abort_on_validation.help',
|
'help' => 'import.abort_on_validation.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'], 'disabled' => $disabled, ])
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => $disabled,
|
||||||
|
])
|
||||||
|
|
||||||
//Buttons
|
//Buttons
|
||||||
->add('import', SubmitType::class, ['label' => 'import.btn', 'disabled' => $disabled]);
|
->add('import', SubmitType::class, [
|
||||||
|
'label' => 'import.btn',
|
||||||
|
'disabled' => $disabled,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,11 @@ class MassCreationForm extends AbstractType
|
||||||
$disabled = ! $this->security->isGranted($perm_name, $entity);
|
$disabled = ! $this->security->isGranted($perm_name, $entity);
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->add('lines', TextareaType::class, ['data' => '',
|
->add('lines', TextareaType::class, [
|
||||||
|
'data' => '',
|
||||||
'label' => 'mass_creation.lines',
|
'label' => 'mass_creation.lines',
|
||||||
'disabled' => $disabled, 'required' => true,
|
'disabled' => $disabled,
|
||||||
|
'required' => true,
|
||||||
'attr' => [
|
'attr' => [
|
||||||
'placeholder' => 'mass_creation.lines.placeholder',
|
'placeholder' => 'mass_creation.lines.placeholder',
|
||||||
'rows' => 10,
|
'rows' => 10,
|
||||||
|
@ -64,7 +66,8 @@ class MassCreationForm extends AbstractType
|
||||||
'class' => $data['entity_class'],
|
'class' => $data['entity_class'],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'parent.label',
|
'label' => 'parent.label',
|
||||||
'disabled' => $disabled, ]);
|
'disabled' => $disabled,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Buttons
|
//Buttons
|
||||||
|
|
|
@ -35,21 +35,33 @@ class MeasurementUnitAdminForm extends BaseEntityAdminForm
|
||||||
{
|
{
|
||||||
$is_new = null === $entity->getID();
|
$is_new = null === $entity->getID();
|
||||||
|
|
||||||
$builder->add('is_integer', CheckboxType::class, ['required' => false,
|
$builder->add('is_integer', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'measurement_unit.edit.is_integer',
|
'label' => 'measurement_unit.edit.is_integer',
|
||||||
'help' => 'measurement_unit.edit.is_integer.help',
|
'help' => 'measurement_unit.edit.is_integer.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('use_si_prefix', CheckboxType::class, ['required' => false,
|
$builder->add('use_si_prefix', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'measurement_unit.edit.use_si_prefix',
|
'label' => 'measurement_unit.edit.use_si_prefix',
|
||||||
'help' => 'measurement_unit.edit.use_si_prefix.help',
|
'help' => 'measurement_unit.edit.use_si_prefix.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('unit', TextType::class, ['required' => false,
|
$builder->add('unit', TextType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'measurement_unit.edit.unit_symbol',
|
'label' => 'measurement_unit.edit.unit_symbol',
|
||||||
'attr' => ['placeholder' => 'measurement_unit.edit.unit_symbol.placeholder'],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]);
|
'placeholder' => 'measurement_unit.edit.unit_symbol.placeholder',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,28 +40,39 @@ class StorelocationAdminForm extends BaseEntityAdminForm
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'storelocation.edit.is_full.label',
|
'label' => 'storelocation.edit.is_full.label',
|
||||||
'help' => 'storelocation.edit.is_full.help',
|
'help' => 'storelocation.edit.is_full.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('limit_to_existing_parts', CheckboxType::class, [
|
$builder->add('limit_to_existing_parts', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'storelocation.limit_to_existing.label',
|
'label' => 'storelocation.limit_to_existing.label',
|
||||||
'help' => 'storelocation.limit_to_existing.help',
|
'help' => 'storelocation.limit_to_existing.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('only_single_part', CheckboxType::class, [
|
$builder->add('only_single_part', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'storelocation.only_single_part.label',
|
'label' => 'storelocation.only_single_part.label',
|
||||||
'help' => 'storelocation.only_single_part.help',
|
'help' => 'storelocation.only_single_part.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity), ]);
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('storage_type', StructuralEntityType::class, [
|
$builder->add('storage_type', StructuralEntityType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'storelocation.storage_type.label',
|
'label' => 'storelocation.storage_type.label',
|
||||||
'help' => 'storelocation.storage_type.help',
|
'help' => 'storelocation.storage_type.help',
|
||||||
'class' => MeasurementUnit::class, 'disable_not_selectable' => true,
|
'class' => MeasurementUnit::class,
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity), ]);
|
'disable_not_selectable' => true,
|
||||||
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,8 @@ class SupplierForm extends CompanyForm
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'supplier.edit.default_currency',
|
'label' => 'supplier.edit.default_currency',
|
||||||
'disable_not_selectable' => true,
|
'disable_not_selectable' => true,
|
||||||
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity), ]);
|
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('shipping_costs', MoneyType::class, [
|
$builder->add('shipping_costs', MoneyType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
|
|
@ -65,20 +65,34 @@ class AttachmentFormType extends AbstractType
|
||||||
'label' => 'attachment.edit.attachment_type',
|
'label' => 'attachment.edit.attachment_type',
|
||||||
'class' => AttachmentType::class,
|
'class' => AttachmentType::class,
|
||||||
'disable_not_selectable' => true,
|
'disable_not_selectable' => true,
|
||||||
'attr' => ['class' => 'attachment_type_selector'],
|
'attr' => [
|
||||||
|
'class' => 'attachment_type_selector',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('showInTable', CheckboxType::class, ['required' => false,
|
$builder->add('showInTable', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'attachment.edit.show_in_table',
|
'label' => 'attachment.edit.show_in_table',
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
'label_attr' => ['class' => 'checkbox-custom'], ]);
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('secureFile', CheckboxType::class, ['required' => false,
|
$builder->add('secureFile', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'attachment.edit.secure_file',
|
'label' => 'attachment.edit.secure_file',
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
'help' => 'attachment.edit.secure_file.help',
|
'help' => 'attachment.edit.secure_file.help',
|
||||||
'label_attr' => ['class' => 'checkbox-custom'], ]);
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('url', TextType::class, [
|
$builder->add('url', TextType::class, [
|
||||||
'label' => 'attachment.edit.url',
|
'label' => 'attachment.edit.url',
|
||||||
|
@ -94,18 +108,28 @@ class AttachmentFormType extends AbstractType
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('downloadURL', CheckboxType::class, ['required' => false,
|
$builder->add('downloadURL', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'attachment.edit.download_url',
|
'label' => 'attachment.edit.download_url',
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
'disabled' => ! $this->allow_attachments_download,
|
'disabled' => ! $this->allow_attachments_download,
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
'label_attr' => ['class' => 'checkbox-custom'], ]);
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('file', FileType::class, [
|
$builder->add('file', FileType::class, [
|
||||||
'label' => 'attachment.edit.file',
|
'label' => 'attachment.edit.file',
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => ['class' => 'file', 'data-show-preview' => 'false', 'data-show-upload' => 'false'],
|
'attr' => [
|
||||||
|
'class' => 'file',
|
||||||
|
'data-show-preview' => 'false',
|
||||||
|
'data-show-upload' => 'false',
|
||||||
|
],
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
new AllowedFileExtension(),
|
new AllowedFileExtension(),
|
||||||
new File([
|
new File([
|
||||||
|
|
|
@ -56,13 +56,16 @@ class OrderdetailType extends AbstractType
|
||||||
|
|
||||||
$builder->add('supplierpartnr', TextType::class, [
|
$builder->add('supplierpartnr', TextType::class, [
|
||||||
'label' => 'orderdetails.edit.supplierpartnr',
|
'label' => 'orderdetails.edit.supplierpartnr',
|
||||||
'attr' => ['placeholder' => 'orderdetails.edit.supplierpartnr.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'orderdetails.edit.supplierpartnr.placeholder',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('supplier', StructuralEntityType::class, [
|
$builder->add('supplier', StructuralEntityType::class, [
|
||||||
'class' => Supplier::class, 'disable_not_selectable' => true,
|
'class' => Supplier::class,
|
||||||
|
'disable_not_selectable' => true,
|
||||||
'label' => 'orderdetails.edit.supplier',
|
'label' => 'orderdetails.edit.supplier',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -74,7 +77,9 @@ class OrderdetailType extends AbstractType
|
||||||
|
|
||||||
$builder->add('obsolete', CheckboxType::class, [
|
$builder->add('obsolete', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
'label' => 'orderdetails.edit.obsolete',
|
'label' => 'orderdetails.edit.obsolete',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,9 @@ class PartBaseType extends AbstractType
|
||||||
->add('name', TextType::class, [
|
->add('name', TextType::class, [
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'part.edit.name',
|
'label' => 'part.edit.name',
|
||||||
'attr' => ['placeholder' => 'part.edit.name.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'part.edit.name.placeholder',
|
||||||
|
],
|
||||||
'disabled' => ! $this->security->isGranted('name.edit', $part),
|
'disabled' => ! $this->security->isGranted('name.edit', $part),
|
||||||
])
|
])
|
||||||
->add('description', CKEditorType::class, [
|
->add('description', CKEditorType::class, [
|
||||||
|
@ -89,11 +91,17 @@ class PartBaseType extends AbstractType
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'part.edit.description',
|
'label' => 'part.edit.description',
|
||||||
'config_name' => 'description_config',
|
'config_name' => 'description_config',
|
||||||
'attr' => ['placeholder' => 'part.edit.description.placeholder', 'rows' => 2],
|
'attr' => [
|
||||||
|
'placeholder' => 'part.edit.description.placeholder',
|
||||||
|
'rows' => 2,
|
||||||
|
],
|
||||||
'disabled' => ! $this->security->isGranted('description.edit', $part),
|
'disabled' => ! $this->security->isGranted('description.edit', $part),
|
||||||
])
|
])
|
||||||
->add('minAmount', SIUnitType::class, [
|
->add('minAmount', SIUnitType::class, [
|
||||||
'attr' => ['min' => 0, 'placeholder' => 'part.editmininstock.placeholder'],
|
'attr' => [
|
||||||
|
'min' => 0,
|
||||||
|
'placeholder' => 'part.editmininstock.placeholder',
|
||||||
|
],
|
||||||
'label' => 'part.edit.mininstock',
|
'label' => 'part.edit.mininstock',
|
||||||
'measurement_unit' => $part->getPartUnit(),
|
'measurement_unit' => $part->getPartUnit(),
|
||||||
'disabled' => ! $this->security->isGranted('minamount.edit', $part),
|
'disabled' => ! $this->security->isGranted('minamount.edit', $part),
|
||||||
|
@ -117,7 +125,8 @@ class PartBaseType extends AbstractType
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'attr' => [
|
'attr' => [
|
||||||
'class' => 'tagsinput',
|
'class' => 'tagsinput',
|
||||||
'data-autocomplete' => $this->urlGenerator->generate('typeahead_tags', ['query' => 'QUERY']), ],
|
'data-autocomplete' => $this->urlGenerator->generate('typeahead_tags', ['query' => 'QUERY']),
|
||||||
|
],
|
||||||
'disabled' => ! $this->security->isGranted('tags.edit', $part),
|
'disabled' => ! $this->security->isGranted('tags.edit', $part),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -139,7 +148,8 @@ class PartBaseType extends AbstractType
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'part.edit.mpn',
|
'label' => 'part.edit.mpn',
|
||||||
'disabled' => ! $this->security->isGranted('mpn.edit', $part), ])
|
'disabled' => ! $this->security->isGranted('mpn.edit', $part),
|
||||||
|
])
|
||||||
->add('manufacturing_status', ChoiceType::class, [
|
->add('manufacturing_status', ChoiceType::class, [
|
||||||
'label' => 'part.edit.manufacturing_status',
|
'label' => 'part.edit.manufacturing_status',
|
||||||
'choices' => $status_choices,
|
'choices' => $status_choices,
|
||||||
|
@ -149,13 +159,17 @@ class PartBaseType extends AbstractType
|
||||||
|
|
||||||
//Advanced section
|
//Advanced section
|
||||||
$builder->add('needsReview', CheckboxType::class, [
|
$builder->add('needsReview', CheckboxType::class, [
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'part.edit.needs_review',
|
'label' => 'part.edit.needs_review',
|
||||||
'disabled' => ! $this->security->isGranted('edit', $part),
|
'disabled' => ! $this->security->isGranted('edit', $part),
|
||||||
])
|
])
|
||||||
->add('favorite', CheckboxType::class, [
|
->add('favorite', CheckboxType::class, [
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'part.edit.is_favorite',
|
'label' => 'part.edit.is_favorite',
|
||||||
'disabled' => ! $this->security->isGranted('change_favorite', $part),
|
'disabled' => ! $this->security->isGranted('change_favorite', $part),
|
||||||
|
@ -178,8 +192,11 @@ class PartBaseType extends AbstractType
|
||||||
$builder->add('comment', CKEditorType::class, [
|
$builder->add('comment', CKEditorType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'part.edit.comment',
|
'label' => 'part.edit.comment',
|
||||||
'attr' => ['rows' => 4],
|
'attr' => [
|
||||||
'disabled' => ! $this->security->isGranted('comment.edit', $part), 'empty_data' => '',
|
'rows' => 4,
|
||||||
|
],
|
||||||
|
'disabled' => ! $this->security->isGranted('comment.edit', $part),
|
||||||
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//Part Lots section
|
//Part Lots section
|
||||||
|
|
|
@ -52,43 +52,65 @@ class PartLotType extends AbstractType
|
||||||
'label' => 'part_lot.edit.description',
|
'label' => 'part_lot.edit.description',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('storage_location', StructuralEntityType::class, ['class' => Storelocation::class,
|
$builder->add('storage_location', StructuralEntityType::class, [
|
||||||
|
'class' => Storelocation::class,
|
||||||
'label' => 'part_lot.edit.location',
|
'label' => 'part_lot.edit.location',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'disable_not_selectable' => true,
|
'disable_not_selectable' => true,
|
||||||
'attr' => ['class' => 'selectpicker form-control-sm', 'data-live-search' => true],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker form-control-sm',
|
||||||
|
'data-live-search' => true,
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('amount', SIUnitType::class, [
|
$builder->add('amount', SIUnitType::class, [
|
||||||
'measurement_unit' => $options['measurement_unit'],
|
'measurement_unit' => $options['measurement_unit'],
|
||||||
'label' => 'part_lot.edit.amount',
|
'label' => 'part_lot.edit.amount',
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('instock_unknown', CheckboxType::class, ['required' => false,
|
$builder->add('instock_unknown', CheckboxType::class, [
|
||||||
|
'required' => false,
|
||||||
'label' => 'part_lot.edit.instock_unknown',
|
'label' => 'part_lot.edit.instock_unknown',
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('needs_refill', CheckboxType::class, ['label_attr' => ['class' => 'checkbox-custom'],
|
$builder->add('needs_refill', CheckboxType::class, [
|
||||||
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
'label' => 'part_lot.edit.needs_refill',
|
'label' => 'part_lot.edit.needs_refill',
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->add('expirationDate', DateTimeType::class, [
|
$builder->add('expirationDate', DateTimeType::class, [
|
||||||
'label' => 'part_lot.edit.expiration_date',
|
'label' => 'part_lot.edit.expiration_date',
|
||||||
'attr' => [],
|
'attr' => [],
|
||||||
'required' => false, ]);
|
'required' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('comment', TextType::class, [
|
$builder->add('comment', TextType::class, [
|
||||||
'label' => 'part_lot.edit.comment',
|
'label' => 'part_lot.edit.comment',
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
'required' => false, 'empty_data' => '',
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => '',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,18 +41,25 @@ class PricedetailType extends AbstractType
|
||||||
$builder->add('min_discount_quantity', SIUnitType::class, [
|
$builder->add('min_discount_quantity', SIUnitType::class, [
|
||||||
'label' => false,
|
'label' => false,
|
||||||
'measurement_unit' => $options['measurement_unit'],
|
'measurement_unit' => $options['measurement_unit'],
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
$builder->add('price_related_quantity', SIUnitType::class, [
|
$builder->add('price_related_quantity', SIUnitType::class, [
|
||||||
'label' => false,
|
'label' => false,
|
||||||
'measurement_unit' => $options['measurement_unit'],
|
'measurement_unit' => $options['measurement_unit'],
|
||||||
'attr' => ['class' => 'form-control-sm'],
|
'attr' => [
|
||||||
|
'class' => 'form-control-sm',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
$builder->add('price', NumberType::class, [
|
$builder->add('price', NumberType::class, [
|
||||||
'label' => false,
|
'label' => false,
|
||||||
'scale' => 5,
|
'scale' => 5,
|
||||||
'html5' => true,
|
'html5' => true,
|
||||||
'attr' => ['min' => 0, 'step' => 'any'],
|
'attr' => [
|
||||||
|
'min' => 0,
|
||||||
|
'step' => 'any',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
$builder->add('currency', CurrencyEntityType::class, [
|
$builder->add('currency', CurrencyEntityType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
|
|
@ -25,14 +25,16 @@ declare(strict_types=1);
|
||||||
namespace App\Form\Permissions;
|
namespace App\Form\Permissions;
|
||||||
|
|
||||||
use App\Services\PermissionResolver;
|
use App\Services\PermissionResolver;
|
||||||
|
use RuntimeException;
|
||||||
use Symfony\Component\Form\DataMapperInterface;
|
use Symfony\Component\Form\DataMapperInterface;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is a data mapper that maps the permission data from DB (accessed via a PermissionResolver),
|
* This class is a data mapper that maps the permission data from DB (accessed via a PermissionResolver),
|
||||||
* to TristateCheckboxes and vice versa.
|
* to TristateCheckboxes and vice versa.
|
||||||
*/
|
*/
|
||||||
class PermissionsMapper implements DataMapperInterface
|
final class PermissionsMapper implements DataMapperInterface
|
||||||
{
|
{
|
||||||
protected $resolver;
|
protected $resolver;
|
||||||
protected $inherit;
|
protected $inherit;
|
||||||
|
@ -49,8 +51,8 @@ class PermissionsMapper implements DataMapperInterface
|
||||||
* The method is responsible for calling {@link FormInterface::setData()}
|
* The method is responsible for calling {@link FormInterface::setData()}
|
||||||
* on the children of compound forms, defining their underlying model data.
|
* on the children of compound forms, defining their underlying model data.
|
||||||
*
|
*
|
||||||
* @param mixed $viewData View data of the compound form being initialized
|
* @param mixed $viewData View data of the compound form being initialized
|
||||||
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
|
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances
|
||||||
*/
|
*/
|
||||||
public function mapDataToForms($viewData, $forms): void
|
public function mapDataToForms($viewData, $forms): void
|
||||||
{
|
{
|
||||||
|
@ -95,14 +97,14 @@ class PermissionsMapper implements DataMapperInterface
|
||||||
* The model data can be an array or an object, so this second argument is always passed
|
* The model data can be an array or an object, so this second argument is always passed
|
||||||
* by reference.
|
* by reference.
|
||||||
*
|
*
|
||||||
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
|
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances
|
||||||
* @param mixed $viewData The compound form's view data that get mapped
|
* @param mixed $viewData The compound form's view data that get mapped
|
||||||
* its children model data
|
* its children model data
|
||||||
*/
|
*/
|
||||||
public function mapFormsToData($forms, &$viewData): void
|
public function mapFormsToData($forms, &$viewData): void
|
||||||
{
|
{
|
||||||
if ($this->inherit) {
|
if ($this->inherit) {
|
||||||
throw new \RuntimeException('The permission type is readonly when it is showing read only data!');
|
throw new RuntimeException('The permission type is readonly when it is showing read only data!');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($forms as $form) {
|
foreach ($forms as $form) {
|
||||||
|
|
|
@ -58,7 +58,12 @@ class TFAGoogleSettingsType extends AbstractType
|
||||||
TextType::class,
|
TextType::class,
|
||||||
[
|
[
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
'attr' => ['maxlength' => '6', 'minlength' => '6', 'pattern' => '\d*', 'autocomplete' => 'off'],
|
'attr' => [
|
||||||
|
'maxlength' => '6',
|
||||||
|
'minlength' => '6',
|
||||||
|
'pattern' => '\d*',
|
||||||
|
'autocomplete' => 'off',
|
||||||
|
],
|
||||||
'constraints' => [new ValidGoogleAuthCode()],
|
'constraints' => [new ValidGoogleAuthCode()],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -77,7 +82,9 @@ class TFAGoogleSettingsType extends AbstractType
|
||||||
} else {
|
} else {
|
||||||
$form->add('submit', SubmitType::class, [
|
$form->add('submit', SubmitType::class, [
|
||||||
'label' => 'tfa_google.disable',
|
'label' => 'tfa_google.disable',
|
||||||
'attr' => ['class' => 'btn-danger'],
|
'attr' => [
|
||||||
|
'class' => 'btn-danger',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace App\Form\Type;
|
||||||
use App\Entity\Attachments\Attachment;
|
use App\Entity\Attachments\Attachment;
|
||||||
use App\Entity\Attachments\AttachmentContainingDBElement;
|
use App\Entity\Attachments\AttachmentContainingDBElement;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use ReflectionClass;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\OptionsResolver\Options;
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
@ -41,7 +42,9 @@ class MasterPictureAttachmentType extends AbstractType
|
||||||
|
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'filter' => 'picture',
|
'filter' => 'picture',
|
||||||
'attr' => ['class' => 'selectpicker'],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
],
|
||||||
'choice_attr' => function (Options $options) {
|
'choice_attr' => function (Options $options) {
|
||||||
return function ($choice, $key, $value) use ($options) {
|
return function ($choice, $key, $value) use ($options) {
|
||||||
/** @var Attachment $choice */
|
/** @var Attachment $choice */
|
||||||
|
@ -58,7 +61,7 @@ class MasterPictureAttachmentType extends AbstractType
|
||||||
},
|
},
|
||||||
'choice_label' => 'name',
|
'choice_label' => 'name',
|
||||||
'class' => function (Options $options) {
|
'class' => function (Options $options) {
|
||||||
$short_class_name = (new \ReflectionClass($options['entity']))->getShortName();
|
$short_class_name = (new ReflectionClass($options['entity']))->getShortName();
|
||||||
//Category becomes CategoryAttachment
|
//Category becomes CategoryAttachment
|
||||||
return 'App\\Entity\\Attachments\\'.$short_class_name.'Attachment';
|
return 'App\\Entity\\Attachments\\'.$short_class_name.'Attachment';
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,8 +36,9 @@ use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\Form\FormView;
|
use Symfony\Component\Form\FormView;
|
||||||
use Symfony\Component\OptionsResolver\Options;
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
class SIUnitType extends AbstractType implements DataMapperInterface
|
final class SIUnitType extends AbstractType implements DataMapperInterface
|
||||||
{
|
{
|
||||||
protected $si_formatter;
|
protected $si_formatter;
|
||||||
|
|
||||||
|
@ -80,7 +81,9 @@ class SIUnitType extends AbstractType implements DataMapperInterface
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
'error_mapping' => ['.' => 'value'],
|
'error_mapping' => [
|
||||||
|
'.' => 'value',
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$resolver->setAllowedTypes('measurement_unit', [MeasurementUnit::class, 'null']);
|
$resolver->setAllowedTypes('measurement_unit', [MeasurementUnit::class, 'null']);
|
||||||
|
@ -117,7 +120,13 @@ class SIUnitType extends AbstractType implements DataMapperInterface
|
||||||
if ($options['show_prefix']) {
|
if ($options['show_prefix']) {
|
||||||
$builder->add('prefix', ChoiceType::class, [
|
$builder->add('prefix', ChoiceType::class, [
|
||||||
'label' => 'false',
|
'label' => 'false',
|
||||||
'choices' => ['M' => 6, 'k' => 3, '' => 0, 'm' => -3, 'µ' => -6],
|
'choices' => [
|
||||||
|
'M' => 6,
|
||||||
|
'k' => 3,
|
||||||
|
'' => 0,
|
||||||
|
'm' => -3,
|
||||||
|
'µ' => -6,
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,8 +152,8 @@ class SIUnitType extends AbstractType implements DataMapperInterface
|
||||||
* The method is responsible for calling {@link FormInterface::setData()}
|
* The method is responsible for calling {@link FormInterface::setData()}
|
||||||
* on the children of compound forms, defining their underlying model data.
|
* on the children of compound forms, defining their underlying model data.
|
||||||
*
|
*
|
||||||
* @param mixed $viewData View data of the compound form being initialized
|
* @param mixed $viewData View data of the compound form being initialized
|
||||||
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
|
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances
|
||||||
*
|
*
|
||||||
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
|
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
|
||||||
*/
|
*/
|
||||||
|
@ -193,9 +202,9 @@ class SIUnitType extends AbstractType implements DataMapperInterface
|
||||||
* The model data can be an array or an object, so this second argument is always passed
|
* The model data can be an array or an object, so this second argument is always passed
|
||||||
* by reference.
|
* by reference.
|
||||||
*
|
*
|
||||||
* @param FormInterface[]|\Traversable $forms A list of {@link FormInterface} instances
|
* @param FormInterface[]|Traversable $forms A list of {@link FormInterface} instances
|
||||||
* @param mixed $viewData The compound form's view data that get mapped
|
* @param mixed $viewData The compound form's view data that get mapped
|
||||||
* its children model data
|
* its children model data
|
||||||
*
|
*
|
||||||
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
|
* @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,7 +50,9 @@ class StructuralEntityType extends AbstractType
|
||||||
{
|
{
|
||||||
protected $em;
|
protected $em;
|
||||||
protected $options;
|
protected $options;
|
||||||
/** @var NodesListBuilder */
|
/**
|
||||||
|
* @var NodesListBuilder
|
||||||
|
*/
|
||||||
protected $builder;
|
protected $builder;
|
||||||
|
|
||||||
public function __construct(EntityManagerInterface $em, NodesListBuilder $builder)
|
public function __construct(EntityManagerInterface $em, NodesListBuilder $builder)
|
||||||
|
@ -81,9 +83,11 @@ class StructuralEntityType extends AbstractType
|
||||||
return new CallbackChoiceLoader(function () use ($options) {
|
return new CallbackChoiceLoader(function () use ($options) {
|
||||||
return $this->getEntries($options);
|
return $this->getEntries($options);
|
||||||
});
|
});
|
||||||
}, 'choice_label' => function ($choice, $key, $value) {
|
},
|
||||||
|
'choice_label' => function ($choice, $key, $value) {
|
||||||
return $this->generateChoiceLabels($choice, $key, $value);
|
return $this->generateChoiceLabels($choice, $key, $value);
|
||||||
}, 'choice_attr' => function ($choice, $key, $value) {
|
},
|
||||||
|
'choice_attr' => function ($choice, $key, $value) {
|
||||||
return $this->generateChoiceAttr($choice, $key, $value);
|
return $this->generateChoiceAttr($choice, $key, $value);
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -91,7 +95,10 @@ class StructuralEntityType extends AbstractType
|
||||||
$resolver->setDefault('empty_message', null);
|
$resolver->setDefault('empty_message', null);
|
||||||
|
|
||||||
$resolver->setDefault('attr', function (Options $options) {
|
$resolver->setDefault('attr', function (Options $options) {
|
||||||
$tmp = ['class' => 'selectpicker', 'data-live-search' => true];
|
$tmp = [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
'data-live-search' => true,
|
||||||
|
];
|
||||||
if ($options['empty_message']) {
|
if ($options['empty_message']) {
|
||||||
$tmp['data-none-Selected-Text'] = $options['empty_message'];
|
$tmp['data-none-Selected-Text'] = $options['empty_message'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Form\Type;
|
namespace App\Form\Type;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\DataTransformerInterface;
|
use Symfony\Component\Form\DataTransformerInterface;
|
||||||
use Symfony\Component\Form\Exception\TransformationFailedException;
|
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||||
|
@ -32,7 +33,7 @@ use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\Form\FormView;
|
use Symfony\Component\Form\FormView;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
class TriStateCheckboxType extends AbstractType implements DataTransformerInterface
|
final class TriStateCheckboxType extends AbstractType implements DataTransformerInterface
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
{
|
{
|
||||||
|
@ -42,8 +43,12 @@ class TriStateCheckboxType extends AbstractType implements DataTransformerInterf
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'label_attr' => ['class' => 'checkbox-custom checkbox-inline'],
|
'label_attr' => [
|
||||||
'attr' => ['class' => 'tristate'],
|
'class' => 'checkbox-custom checkbox-inline',
|
||||||
|
],
|
||||||
|
'attr' => [
|
||||||
|
'class' => 'tristate',
|
||||||
|
],
|
||||||
'compound' => false,
|
'compound' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +120,7 @@ class TriStateCheckboxType extends AbstractType implements DataTransformerInterf
|
||||||
return 'indeterminate';
|
return 'indeterminate';
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \InvalidArgumentException('Invalid value encountered!: '.$value);
|
throw new InvalidArgumentException('Invalid value encountered!: '.$value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,7 +161,7 @@ class TriStateCheckboxType extends AbstractType implements DataTransformerInterf
|
||||||
case 'indeterminate':
|
case 'indeterminate':
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
throw new \InvalidArgumentException('Invalid value encountered!: '.$value);
|
throw new InvalidArgumentException('Invalid value encountered!: '.$value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,9 @@ class UserAdminForm extends AbstractType
|
||||||
->add('name', TextType::class, [
|
->add('name', TextType::class, [
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'user.username.label',
|
'label' => 'user.username.label',
|
||||||
'attr' => ['placeholder' => 'user.username.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'user.username.placeholder',
|
||||||
|
],
|
||||||
'disabled' => ! $this->security->isGranted('edit_username', $entity),
|
'disabled' => ! $this->security->isGranted('edit_username', $entity),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -82,19 +84,25 @@ class UserAdminForm extends AbstractType
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label' => 'group.label',
|
'label' => 'group.label',
|
||||||
'disable_not_selectable' => true,
|
'disable_not_selectable' => true,
|
||||||
'disabled' => ! $this->security->isGranted('change_group', $entity), ])
|
'disabled' => ! $this->security->isGranted('change_group', $entity),
|
||||||
|
])
|
||||||
|
|
||||||
->add('first_name', TextType::class, [
|
->add('first_name', TextType::class, [
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'user.firstName.label',
|
'label' => 'user.firstName.label',
|
||||||
'attr' => ['placeholder' => 'user.firstName.placeholder'], 'required' => false,
|
'attr' => [
|
||||||
|
'placeholder' => 'user.firstName.placeholder',
|
||||||
|
],
|
||||||
|
'required' => false,
|
||||||
'disabled' => ! $this->security->isGranted('edit_infos', $entity),
|
'disabled' => ! $this->security->isGranted('edit_infos', $entity),
|
||||||
])
|
])
|
||||||
|
|
||||||
->add('last_name', TextType::class, [
|
->add('last_name', TextType::class, [
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'user.lastName.label',
|
'label' => 'user.lastName.label',
|
||||||
'attr' => ['placeholder' => 'user.lastName.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'user.lastName.placeholder',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'disabled' => ! $this->security->isGranted('edit_infos', $entity),
|
'disabled' => ! $this->security->isGranted('edit_infos', $entity),
|
||||||
])
|
])
|
||||||
|
@ -102,14 +110,19 @@ class UserAdminForm extends AbstractType
|
||||||
->add('email', TextType::class, [
|
->add('email', TextType::class, [
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'user.email.label',
|
'label' => 'user.email.label',
|
||||||
'attr' => ['placeholder' => 'user.email.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'user.email.placeholder',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'disabled' => ! $this->security->isGranted('edit_infos', $entity), ])
|
'disabled' => ! $this->security->isGranted('edit_infos', $entity),
|
||||||
|
])
|
||||||
|
|
||||||
->add('department', TextType::class, [
|
->add('department', TextType::class, [
|
||||||
'empty_data' => '',
|
'empty_data' => '',
|
||||||
'label' => 'user.department.label',
|
'label' => 'user.department.label',
|
||||||
'attr' => ['placeholder' => 'user.department.placeholder'],
|
'attr' => [
|
||||||
|
'placeholder' => 'user.department.placeholder',
|
||||||
|
],
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'disabled' => ! $this->security->isGranted('edit_infos', $entity),
|
'disabled' => ! $this->security->isGranted('edit_infos', $entity),
|
||||||
])
|
])
|
||||||
|
@ -117,7 +130,10 @@ class UserAdminForm extends AbstractType
|
||||||
//Config section
|
//Config section
|
||||||
->add('language', LanguageType::class, [
|
->add('language', LanguageType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => ['class' => 'selectpicker', 'data-live-search' => true],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
'data-live-search' => true,
|
||||||
|
],
|
||||||
'placeholder' => 'user_settings.language.placeholder',
|
'placeholder' => 'user_settings.language.placeholder',
|
||||||
'label' => 'user.language_select',
|
'label' => 'user.language_select',
|
||||||
'preferred_choices' => ['en', 'de'],
|
'preferred_choices' => ['en', 'de'],
|
||||||
|
@ -125,7 +141,10 @@ class UserAdminForm extends AbstractType
|
||||||
])
|
])
|
||||||
->add('timezone', TimezoneType::class, [
|
->add('timezone', TimezoneType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => ['class' => 'selectpicker', 'data-live-search' => true],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
'data-live-search' => true,
|
||||||
|
],
|
||||||
'placeholder' => 'user_settings.timezone.placeholder',
|
'placeholder' => 'user_settings.timezone.placeholder',
|
||||||
'label' => 'user.timezone.label',
|
'label' => 'user.timezone.label',
|
||||||
'preferred_choices' => ['Europe/Berlin'],
|
'preferred_choices' => ['Europe/Berlin'],
|
||||||
|
@ -137,7 +156,9 @@ class UserAdminForm extends AbstractType
|
||||||
'choice_label' => function ($entity, $key, $value) {
|
'choice_label' => function ($entity, $key, $value) {
|
||||||
return $value;
|
return $value;
|
||||||
},
|
},
|
||||||
'attr' => ['class' => 'selectpicker'],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
],
|
||||||
'placeholder' => 'user_settings.theme.placeholder',
|
'placeholder' => 'user_settings.theme.placeholder',
|
||||||
'label' => 'user.theme.label',
|
'label' => 'user.theme.label',
|
||||||
'disabled' => ! $this->security->isGranted('change_user_settings', $entity),
|
'disabled' => ! $this->security->isGranted('change_user_settings', $entity),
|
||||||
|
@ -150,8 +171,12 @@ class UserAdminForm extends AbstractType
|
||||||
|
|
||||||
->add('new_password', RepeatedType::class, [
|
->add('new_password', RepeatedType::class, [
|
||||||
'type' => PasswordType::class,
|
'type' => PasswordType::class,
|
||||||
'first_options' => ['label' => 'user.settings.pw_new.label'],
|
'first_options' => [
|
||||||
'second_options' => ['label' => 'user.settings.pw_confirm.label'],
|
'label' => 'user.settings.pw_new.label',
|
||||||
|
],
|
||||||
|
'second_options' => [
|
||||||
|
'label' => 'user.settings.pw_confirm.label',
|
||||||
|
],
|
||||||
'invalid_message' => 'password_must_match',
|
'invalid_message' => 'password_must_match',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'mapped' => false,
|
'mapped' => false,
|
||||||
|
@ -164,14 +189,18 @@ class UserAdminForm extends AbstractType
|
||||||
|
|
||||||
->add('need_pw_change', CheckboxType::class, [
|
->add('need_pw_change', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
'label' => 'user.edit.needs_pw_change',
|
'label' => 'user.edit.needs_pw_change',
|
||||||
'disabled' => ! $this->security->isGranted('set_password', $entity),
|
'disabled' => ! $this->security->isGranted('set_password', $entity),
|
||||||
])
|
])
|
||||||
|
|
||||||
->add('disabled', CheckboxType::class, [
|
->add('disabled', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'label_attr' => ['class' => 'checkbox-custom'],
|
'label_attr' => [
|
||||||
|
'class' => 'checkbox-custom',
|
||||||
|
],
|
||||||
'label' => 'user.edit.user_disabled',
|
'label' => 'user.edit.user_disabled',
|
||||||
'disabled' => ! $this->security->isGranted('set_password', $entity)
|
'disabled' => ! $this->security->isGranted('set_password', $entity)
|
||||||
|| $entity === $this->security->getUser(),
|
|| $entity === $this->security->getUser(),
|
||||||
|
@ -206,7 +235,9 @@ class UserAdminForm extends AbstractType
|
||||||
//Buttons
|
//Buttons
|
||||||
$builder->add('save', SubmitType::class, [
|
$builder->add('save', SubmitType::class, [
|
||||||
'label' => $is_new ? 'user.create' : 'user.edit.save',
|
'label' => $is_new ? 'user.create' : 'user.edit.save',
|
||||||
'attr' => ['class' => $is_new ? 'btn-success' : ''],
|
'attr' => [
|
||||||
|
'class' => $is_new ? 'btn-success' : '',
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->add('reset', ResetType::class, [
|
->add('reset', ResetType::class, [
|
||||||
'label' => 'entity.edit.reset',
|
'label' => 'entity.edit.reset',
|
||||||
|
|
|
@ -79,7 +79,10 @@ class UserSettingsType extends AbstractType
|
||||||
->add('language', LanguageType::class, [
|
->add('language', LanguageType::class, [
|
||||||
'disabled' => $this->demo_mode,
|
'disabled' => $this->demo_mode,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => ['class' => 'selectpicker', 'data-live-search' => true],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
'data-live-search' => true,
|
||||||
|
],
|
||||||
'placeholder' => 'user_settings.language.placeholder',
|
'placeholder' => 'user_settings.language.placeholder',
|
||||||
'label' => 'user.language_select',
|
'label' => 'user.language_select',
|
||||||
'preferred_choices' => ['en', 'de'],
|
'preferred_choices' => ['en', 'de'],
|
||||||
|
@ -87,7 +90,10 @@ class UserSettingsType extends AbstractType
|
||||||
->add('timezone', TimezoneType::class, [
|
->add('timezone', TimezoneType::class, [
|
||||||
'disabled' => $this->demo_mode,
|
'disabled' => $this->demo_mode,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => ['class' => 'selectpicker', 'data-live-search' => true],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
'data-live-search' => true,
|
||||||
|
],
|
||||||
'placeholder' => 'user_settings.timezone.placeholder',
|
'placeholder' => 'user_settings.timezone.placeholder',
|
||||||
'label' => 'user.timezone.label',
|
'label' => 'user.timezone.label',
|
||||||
'preferred_choices' => ['Europe/Berlin'],
|
'preferred_choices' => ['Europe/Berlin'],
|
||||||
|
@ -95,7 +101,9 @@ class UserSettingsType extends AbstractType
|
||||||
->add('theme', ChoiceType::class, [
|
->add('theme', ChoiceType::class, [
|
||||||
'disabled' => $this->demo_mode,
|
'disabled' => $this->demo_mode,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'attr' => ['class' => 'selectpicker'],
|
'attr' => [
|
||||||
|
'class' => 'selectpicker',
|
||||||
|
],
|
||||||
'choices' => User::AVAILABLE_THEMES,
|
'choices' => User::AVAILABLE_THEMES,
|
||||||
'choice_label' => function ($entity, $key, $value) {
|
'choice_label' => function ($entity, $key, $value) {
|
||||||
return $value;
|
return $value;
|
||||||
|
|
|
@ -25,8 +25,10 @@ declare(strict_types=1);
|
||||||
namespace App\Helpers\Trees;
|
namespace App\Helpers\Trees;
|
||||||
|
|
||||||
use App\Entity\Base\StructuralDBElement;
|
use App\Entity\Base\StructuralDBElement;
|
||||||
|
use ArrayIterator;
|
||||||
|
use RecursiveIterator;
|
||||||
|
|
||||||
class StructuralDBElementIterator extends \ArrayIterator implements \RecursiveIterator
|
final class StructuralDBElementIterator extends ArrayIterator implements RecursiveIterator
|
||||||
{
|
{
|
||||||
public function __construct($nodes)
|
public function __construct($nodes)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,11 +24,13 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Helpers\Trees;
|
namespace App\Helpers\Trees;
|
||||||
|
|
||||||
|
use JsonSerializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a node for the bootstrap treeview node.
|
* This class represents a node for the bootstrap treeview node.
|
||||||
* When you serialize an array of these objects to JSON, you can use the serialized data in data for the treeview.
|
* When you serialize an array of these objects to JSON, you can use the serialized data in data for the treeview.
|
||||||
*/
|
*/
|
||||||
class TreeViewNode implements \JsonSerializable
|
final class TreeViewNode implements JsonSerializable
|
||||||
{
|
{
|
||||||
protected $text;
|
protected $text;
|
||||||
protected $href;
|
protected $href;
|
||||||
|
|
|
@ -24,7 +24,10 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Helpers\Trees;
|
namespace App\Helpers\Trees;
|
||||||
|
|
||||||
class TreeViewNodeIterator extends \ArrayIterator implements \RecursiveIterator
|
use ArrayIterator;
|
||||||
|
use RecursiveIterator;
|
||||||
|
|
||||||
|
final class TreeViewNodeIterator extends ArrayIterator implements RecursiveIterator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param TreeViewNode[] $nodes
|
* @param TreeViewNode[] $nodes
|
||||||
|
|
|
@ -24,18 +24,28 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Helpers\Trees;
|
namespace App\Helpers\Trees;
|
||||||
|
|
||||||
class TreeViewNodeState implements \JsonSerializable
|
use JsonSerializable;
|
||||||
|
|
||||||
|
final class TreeViewNodeState implements JsonSerializable
|
||||||
{
|
{
|
||||||
/** @var bool|null */
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
protected $checked = null;
|
protected $checked = null;
|
||||||
|
|
||||||
/** @var bool|null */
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
protected $disabled = null;
|
protected $disabled = null;
|
||||||
|
|
||||||
/** @var bool|null */
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
protected $expanded = null;
|
protected $expanded = null;
|
||||||
|
|
||||||
/** @var bool|null */
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
protected $selected = null;
|
protected $selected = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,6 +24,8 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Helpers;
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||||
use Doctrine\DBAL\Types\ConversionException;
|
use Doctrine\DBAL\Types\ConversionException;
|
||||||
use Doctrine\DBAL\Types\DateTimeType;
|
use Doctrine\DBAL\Types\DateTimeType;
|
||||||
|
@ -39,10 +41,10 @@ class UTCDateTimeType extends DateTimeType
|
||||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||||
{
|
{
|
||||||
if (! self::$utc_timezone) {
|
if (! self::$utc_timezone) {
|
||||||
self::$utc_timezone = new \DateTimeZone('UTC');
|
self::$utc_timezone = new DateTimeZone('UTC');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($value instanceof \DateTime) {
|
if ($value instanceof DateTime) {
|
||||||
$value->setTimezone(self::$utc_timezone);
|
$value->setTimezone(self::$utc_timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,14 +54,14 @@ class UTCDateTimeType extends DateTimeType
|
||||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||||
{
|
{
|
||||||
if (! self::$utc_timezone) {
|
if (! self::$utc_timezone) {
|
||||||
self::$utc_timezone = new \DateTimeZone('UTC');
|
self::$utc_timezone = new DateTimeZone('UTC');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $value || $value instanceof \DateTime) {
|
if (null === $value || $value instanceof DateTime) {
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$converted = \DateTime::createFromFormat(
|
$converted = DateTime::createFromFormat(
|
||||||
$platform->getDateTimeFormatString(),
|
$platform->getDateTimeFormatString(),
|
||||||
$value,
|
$value,
|
||||||
self::$utc_timezone
|
self::$utc_timezone
|
||||||
|
|
|
@ -43,7 +43,7 @@ final class Version1 extends AbstractMigration
|
||||||
//Check if we can use this migration method:
|
//Check if we can use this migration method:
|
||||||
$version = (int) $this->connection->fetchColumn("SELECT keyValue AS version FROM `internal` WHERE `keyName` = 'dbVersion'");
|
$version = (int) $this->connection->fetchColumn("SELECT keyValue AS version FROM `internal` WHERE `keyName` = 'dbVersion'");
|
||||||
$this->skipIf(true, 'Old Part-DB Database detected! Continue with upgrade...');
|
$this->skipIf(true, 'Old Part-DB Database detected! Continue with upgrade...');
|
||||||
} catch (DBALException $ex) {
|
} catch (DBALException $dBALException) {
|
||||||
//when the table was not found, we can proceed, because we have an empty DB!
|
//when the table was not found, we can proceed, because we have an empty DB!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ final class Version20190902140506 extends AbstractMigration
|
||||||
//Check if we can use this migration method:
|
//Check if we can use this migration method:
|
||||||
$version = (int) $this->connection->fetchColumn("SELECT keyValue AS version FROM `internal` WHERE `keyName` = 'dbVersion'");
|
$version = (int) $this->connection->fetchColumn("SELECT keyValue AS version FROM `internal` WHERE `keyName` = 'dbVersion'");
|
||||||
$this->abortIf(26 !== $version, 'This database migration can only be used if the database version is 26! Install Part-DB 0.5.6 and update database there!');
|
$this->abortIf(26 !== $version, 'This database migration can only be used if the database version is 26! Install Part-DB 0.5.6 and update database there!');
|
||||||
} catch (DBALException $ex) {
|
} catch (DBALException $dBALException) {
|
||||||
//when the table was not found, then you can not use this migration
|
//when the table was not found, then you can not use this migration
|
||||||
$this->skipIf(true, 'Empty database detected. Skip migration.');
|
$this->skipIf(true, 'Empty database detected. Skip migration.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace App\Repository;
|
||||||
use App\Entity\Base\StructuralDBElement;
|
use App\Entity\Base\StructuralDBElement;
|
||||||
use App\Helpers\Trees\StructuralDBElementIterator;
|
use App\Helpers\Trees\StructuralDBElementIterator;
|
||||||
use App\Helpers\Trees\TreeViewNode;
|
use App\Helpers\Trees\TreeViewNode;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
|
||||||
class StructuralDBElementRepository extends NamedDBElementRepository
|
class StructuralDBElementRepository extends NamedDBElementRepository
|
||||||
{
|
{
|
||||||
|
@ -80,7 +81,7 @@ class StructuralDBElementRepository extends NamedDBElementRepository
|
||||||
$entities = $this->findBy(['parent' => $parent], ['name' => 'ASC']);
|
$entities = $this->findBy(['parent' => $parent], ['name' => 'ASC']);
|
||||||
|
|
||||||
$elementIterator = new StructuralDBElementIterator($entities);
|
$elementIterator = new StructuralDBElementIterator($entities);
|
||||||
$recursiveIterator = new \RecursiveIteratorIterator($elementIterator, \RecursiveIteratorIterator::SELF_FIRST);
|
$recursiveIterator = new RecursiveIteratorIterator($elementIterator, RecursiveIteratorIterator::SELF_FIRST);
|
||||||
//$result = iterator_to_array($recursiveIterator);
|
//$result = iterator_to_array($recursiveIterator);
|
||||||
|
|
||||||
//We can not use iterator_to_array here or we get only the parent elements
|
//We can not use iterator_to_array here or we get only the parent elements
|
||||||
|
|
|
@ -35,7 +35,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
* @method User[] findAll()
|
* @method User[] findAll()
|
||||||
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
*/
|
*/
|
||||||
class UserRepository extends NamedDBElementRepository implements PasswordUpgraderInterface
|
final class UserRepository extends NamedDBElementRepository implements PasswordUpgraderInterface
|
||||||
{
|
{
|
||||||
protected $anonymous_user;
|
protected $anonymous_user;
|
||||||
|
|
||||||
|
@ -74,11 +74,14 @@ class UserRepository extends NamedDBElementRepository implements PasswordUpgrade
|
||||||
->where('u.name = (:name)')
|
->where('u.name = (:name)')
|
||||||
->orWhere('u.email = (:email)');
|
->orWhere('u.email = (:email)');
|
||||||
|
|
||||||
$qb->setParameters(['email' => $name_or_password, 'name' => $name_or_password]);
|
$qb->setParameters([
|
||||||
|
'email' => $name_or_password,
|
||||||
|
'name' => $name_or_password,
|
||||||
|
]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $qb->getQuery()->getOneOrNullResult();
|
return $qb->getQuery()->getOneOrNullResult();
|
||||||
} catch (NonUniqueResultException $exception) {
|
} catch (NonUniqueResultException $nonUniqueResultException) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,11 @@ declare(strict_types=1);
|
||||||
namespace App\Security\Annotations;
|
namespace App\Security\Annotations;
|
||||||
|
|
||||||
use App\Entity\Base\NamedDBElement;
|
use App\Entity\Base\NamedDBElement;
|
||||||
|
use DateTime;
|
||||||
use Doctrine\Common\Annotations\Annotation;
|
use Doctrine\Common\Annotations\Annotation;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use function is_string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Annotation
|
* @Annotation
|
||||||
|
@ -90,7 +92,7 @@ class ColumnSecurity
|
||||||
if (class_exists($this->type)) {
|
if (class_exists($this->type)) {
|
||||||
$object = new $this->type();
|
$object = new $this->type();
|
||||||
if ($object instanceof NamedDBElement) {
|
if ($object instanceof NamedDBElement) {
|
||||||
if (\is_string($this->placeholder) && '' !== $this->placeholder) {
|
if (is_string($this->placeholder) && '' !== $this->placeholder) {
|
||||||
$object->setName($this->placeholder);
|
$object->setName($this->placeholder);
|
||||||
} else {
|
} else {
|
||||||
$object->setName('???');
|
$object->setName('???');
|
||||||
|
@ -117,7 +119,7 @@ class ColumnSecurity
|
||||||
case 'bool':
|
case 'bool':
|
||||||
return false;
|
return false;
|
||||||
case 'datetime':
|
case 'datetime':
|
||||||
return (new \DateTime())->setTimestamp(0);
|
return (new DateTime())->setTimestamp(0);
|
||||||
default:
|
default:
|
||||||
throw new InvalidArgumentException('Unknown type! You have to specify a placeholder!');
|
throw new InvalidArgumentException('Unknown type! You have to specify a placeholder!');
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace App\Security\EntityListeners;
|
||||||
use App\Entity\Base\DBElement;
|
use App\Entity\Base\DBElement;
|
||||||
use App\Entity\UserSystem\User;
|
use App\Entity\UserSystem\User;
|
||||||
use App\Security\Annotations\ColumnSecurity;
|
use App\Security\Annotations\ColumnSecurity;
|
||||||
|
use function count;
|
||||||
use Doctrine\Common\Annotations\Reader;
|
use Doctrine\Common\Annotations\Reader;
|
||||||
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
|
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
@ -34,6 +35,8 @@ use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Doctrine\ORM\Mapping\PostLoad;
|
use Doctrine\ORM\Mapping\PostLoad;
|
||||||
use Doctrine\ORM\Mapping\PreUpdate;
|
use Doctrine\ORM\Mapping\PreUpdate;
|
||||||
|
use function get_class;
|
||||||
|
use InvalidArgumentException;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
@ -167,7 +170,7 @@ class ElementPermissionListener
|
||||||
*/
|
*/
|
||||||
protected function isRunningFromCLI()
|
protected function isRunningFromCLI()
|
||||||
{
|
{
|
||||||
if (empty($_SERVER['REMOTE_ADDR']) && ! isset($_SERVER['HTTP_USER_AGENT']) && \count($_SERVER['argv']) > 0) {
|
if (empty($_SERVER['REMOTE_ADDR']) && ! isset($_SERVER['HTTP_USER_AGENT']) && count($_SERVER['argv']) > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +194,7 @@ class ElementPermissionListener
|
||||||
} elseif ('edit' === $mode) {
|
} elseif ('edit' === $mode) {
|
||||||
$operation = $annotation->getEditOperationName();
|
$operation = $annotation->getEditOperationName();
|
||||||
} else {
|
} else {
|
||||||
throw new \InvalidArgumentException('$mode must be either "read" or "edit"!');
|
throw new InvalidArgumentException('$mode must be either "read" or "edit"!');
|
||||||
}
|
}
|
||||||
|
|
||||||
//Users must always be checked, because its return value can differ if it is the user itself or something else
|
//Users must always be checked, because its return value can differ if it is the user itself or something else
|
||||||
|
@ -200,10 +203,10 @@ class ElementPermissionListener
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if we have already have saved the permission, otherwise save it to cache
|
//Check if we have already have saved the permission, otherwise save it to cache
|
||||||
if (! isset($this->perm_cache[$mode][\get_class($element)][$operation])) {
|
if (! isset($this->perm_cache[$mode][get_class($element)][$operation])) {
|
||||||
$this->perm_cache[$mode][\get_class($element)][$operation] = $this->security->isGranted($operation, $element);
|
$this->perm_cache[$mode][get_class($element)][$operation] = $this->security->isGranted($operation, $element);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->perm_cache[$mode][\get_class($element)][$operation];
|
return $this->perm_cache[$mode][get_class($element)][$operation];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ use Symfony\Component\Security\Core\Exception\DisabledException;
|
||||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
|
||||||
class UserChecker implements UserCheckerInterface
|
final class UserChecker implements UserCheckerInterface
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace App\Security\Voter;
|
||||||
|
|
||||||
use App\Entity\Attachments\Attachment;
|
use App\Entity\Attachments\Attachment;
|
||||||
use App\Entity\UserSystem\User;
|
use App\Entity\UserSystem\User;
|
||||||
|
use function in_array;
|
||||||
|
|
||||||
class AttachmentVoter extends ExtendedVoter
|
class AttachmentVoter extends ExtendedVoter
|
||||||
{
|
{
|
||||||
|
@ -54,7 +55,7 @@ class AttachmentVoter extends ExtendedVoter
|
||||||
protected function supports($attribute, $subject)
|
protected function supports($attribute, $subject)
|
||||||
{
|
{
|
||||||
if ($subject instanceof Attachment) {
|
if ($subject instanceof Attachment) {
|
||||||
return \in_array($attribute, $this->resolver->listOperationsForPermission('parts_attachments'), false);
|
return in_array($attribute, $this->resolver->listOperationsForPermission('parts_attachments'), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -35,13 +35,12 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||||
*/
|
*/
|
||||||
abstract class ExtendedVoter extends Voter
|
abstract class ExtendedVoter extends Voter
|
||||||
{
|
{
|
||||||
|
protected $entityManager;
|
||||||
/**
|
/**
|
||||||
* @var PermissionResolver
|
* @var PermissionResolver
|
||||||
*/
|
*/
|
||||||
protected $resolver;
|
protected $resolver;
|
||||||
|
|
||||||
protected $entityManager;
|
|
||||||
|
|
||||||
public function __construct(PermissionResolver $resolver, EntityManagerInterface $entityManager)
|
public function __construct(PermissionResolver $resolver, EntityManagerInterface $entityManager)
|
||||||
{
|
{
|
||||||
$this->resolver = $resolver;
|
$this->resolver = $resolver;
|
||||||
|
|
|
@ -58,7 +58,7 @@ class PermissionVoter extends ExtendedVoter
|
||||||
protected function supports($attribute, $subject)
|
protected function supports($attribute, $subject)
|
||||||
{
|
{
|
||||||
//Check if the attribute has the form @permission.operation
|
//Check if the attribute has the form @permission.operation
|
||||||
if (preg_match('/^@\\w+\\.\\w+$/', $attribute)) {
|
if (preg_match('#^@\\w+\\.\\w+$#', $attribute)) {
|
||||||
$attribute = ltrim($attribute, '@');
|
$attribute = ltrim($attribute, '@');
|
||||||
[$perm, $op] = explode('.', $attribute);
|
[$perm, $op] = explode('.', $attribute);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue