Merge remote-tracking branch 'origin/l10n_master' into l10n_master

This commit is contained in:
Jan Böhmer 2020-04-10 12:37:54 +02:00
commit 8343fffc1c
140 changed files with 3217 additions and 4762 deletions

View file

@ -110,9 +110,12 @@ $(document).on("ajaxUI:start ajaxUI:reload", function() {
});
//Register bootstrap select picker
$(document).on("ajaxUI:reload", function () {
$(document).on("ajaxUI:reload ajaxUI:start", function () {
//@ts-ignore
$(".selectpicker").selectpicker();
$(".selectpicker").selectpicker({
dropdownAlignRight: 'auto',
container: '#content',
});
});
//Use bootstrap tooltips for the most tooltips

View file

@ -64,6 +64,7 @@
"phpstan/phpstan": "^0.12.8",
"phpstan/phpstan-doctrine": "^0.12.9",
"phpstan/phpstan-symfony": "^0.12.4",
"psalm/plugin-symfony": "^1.1",
"roave/security-advisories": "dev-master",
"symfony/debug-pack": "*",
"symfony/maker-bundle": "^1.13",

635
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,26 +2,14 @@ doctrine:
orm:
auto_generate_proxy_classes: false
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
type: pool
pool: doctrine.system_cache_pool
query_cache_driver:
type: service
id: doctrine.system_cache_provider
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: service
id: doctrine.result_cache_provider
services:
doctrine.result_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.result_cache_pool'
doctrine.system_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.system_cache_pool'
type: pool
pool: doctrine.result_cache_pool
framework:
cache:

View file

@ -4,4 +4,4 @@ webpack_encore:
cache: true
# Preload in production
preload: false
preload: true

View file

@ -8,7 +8,7 @@ webpack_encore:
# crossorigin: 'anonymous'
# preload all rendered script and link tags automatically via the http2 Link header
#preload: false
preload: false
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
# strict_mode: false

View file

@ -187,6 +187,10 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
label: "perm.revert_elements"
bit: 10
alsoSet: ["read", "edit", "create", "delete", "show_history"]
show_private:
label: "perm.attachment_show_private"
bit: 12
alsoSet: ["read"]
parts_order:
<<: *PART_ATTRIBUTE

View file

@ -33,6 +33,8 @@ services:
bind:
bool $demo_mode: '%demo_mode%'
bool $gpdr_compliance : '%gpdr_compliance%'
bool $kernel_debug: '%kernel.debug%'
string $kernel_cache_dir: '%kernel.cache_dir%'
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name

View file

@ -1,5 +1,6 @@
<?xml version="1.0"?>
<psalm
errorLevel="5"
totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@ -52,4 +53,4 @@
<InvalidStringClass errorLevel="info"/>
</issueHandlers>
</psalm>
<plugins><pluginClass class="Psalm\SymfonyPsalmPlugin\Plugin"/></plugins></psalm>

View file

@ -197,7 +197,7 @@ abstract class BaseAdminController extends AbstractController
//We can not use dynamic form events here, because the parent entity list is build from database!
$form = $this->createForm($this->form_class, $entity, [
'attachment_class' => $this->attachment_class,
'parameter_class' => $this->parameter_class
'parameter_class' => $this->parameter_class,
]);
} elseif ($form->isSubmitted() && ! $form->isValid()) {
$this->addFlash('error', 'entity.edit_flash.invalid');

View file

@ -72,7 +72,7 @@ class FootprintController extends BaseAdminController
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function delete(Request $request, Footprint $entity, StructuralElementRecursionHelper $recursionHelper)
public function delete(Request $request, Footprint $entity, StructuralElementRecursionHelper $recursionHelper): \Symfony\Component\HttpFoundation\RedirectResponse
{
return $this->_delete($request, $entity, $recursionHelper);
}
@ -83,7 +83,7 @@ class FootprintController extends BaseAdminController
*
* @return Response
*/
public function edit(Footprint $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null)
public function edit(Footprint $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response
{
return $this->_edit($entity, $request, $em, $timestamp);
}

View file

@ -69,6 +69,10 @@ class AttachmentFileController extends AbstractController
{
$this->denyAccessUnlessGranted('read', $attachment);
if ($attachment->isSecure()) {
$this->denyAccessUnlessGranted('show_private', $attachment);
}
if ($attachment->isExternal()) {
throw new RuntimeException('You can not download external attachments!');
}
@ -97,6 +101,10 @@ class AttachmentFileController extends AbstractController
{
$this->denyAccessUnlessGranted('read', $attachment);
if ($attachment->isSecure()) {
$this->denyAccessUnlessGranted('show_private', $attachment);
}
if ($attachment->isExternal()) {
throw new RuntimeException('You can not download external attachments!');
}

View file

@ -53,7 +53,6 @@ use App\Services\LogSystem\EventUndoHelper;
use App\Services\LogSystem\TimeTravel;
use Doctrine\ORM\EntityManagerInterface;
use Omines\DataTablesBundle\DataTableFactory;
use phpDocumentor\Reflection\Element;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@ -100,7 +99,7 @@ class LogController extends AbstractController
/**
* @Route("/undo", name="log_undo", methods={"POST"})
*/
public function undoRevertLog(Request $request, EventUndoHelper $eventUndoHelper)
public function undoRevertLog(Request $request, EventUndoHelper $eventUndoHelper): \Symfony\Component\HttpFoundation\RedirectResponse
{
$mode = EventUndoHelper::MODE_UNDO;
$id = $request->request->get('undo');

View file

@ -44,7 +44,12 @@ namespace App\Controller;
use App\DataTables\LogDataTable;
use App\Entity\Parts\Category;
use App\Entity\Parts\Footprint;
use App\Entity\Parts\Part;
use App\Entity\Parts\PartLot;
use App\Entity\Parts\Storelocation;
use App\Entity\Parts\Supplier;
use App\Entity\PriceInformations\Orderdetail;
use App\Exceptions\AttachmentDownloadException;
use App\Form\Part\PartBaseType;
use App\Services\Attachments\AttachmentManager;
@ -57,6 +62,7 @@ use App\Services\Parameters\ParameterExtractor;
use App\Services\PricedetailHelper;
use Doctrine\ORM\EntityManagerInterface;
use Omines\DataTablesBundle\DataTableFactory;
use Proxies\__CG__\App\Entity\Parts\Manufacturer;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
@ -135,7 +141,7 @@ class PartController extends AbstractController
'pictures' => $this->partPreviewGenerator->getPreviewAttachments($part),
'timeTravel' => $timeTravel_timestamp,
'description_params' => $parameterExtractor->extractParameters($part->getDescription()),
'comment_params' => $parameterExtractor->extractParameters($part->getComment())
'comment_params' => $parameterExtractor->extractParameters($part->getComment()),
]
);
}
@ -235,13 +241,42 @@ class PartController extends AbstractController
$this->denyAccessUnlessGranted('create', $new_part);
$cid = $request->get('cid', 1);
$category = $em->find(Category::class, $cid);
$cid = $request->get('category', null);
$category = $cid ? $em->find(Category::class, $cid) : null;
if (null !== $category && null === $new_part->getCategory()) {
$new_part->setCategory($category);
}
$fid = $request->get('footprint', null);
$footprint = $fid ? $em->find(Footprint::class, $cid) : null;
if (null !== $footprint && null === $new_part->getFootprint()) {
$new_part->setFootprint($footprint);
}
$mid = $request->get('manufacturer', null);
$manufacturer = $mid ? $em->find(Manufacturer::class, $mid) : null;
if (null !== $manufacturer && null === $new_part->getManufacturer()) {
$new_part->setManufacturer($manufacturer);
}
$store_id = $request->get('storelocation', null);
$storelocation = $store_id ? $em->find(Storelocation::class, $store_id): null;
if (null !== $storelocation && $new_part->getPartLots()->isEmpty()) {
$partLot = new PartLot();
$partLot->setStorageLocation($storelocation);
$partLot->setInstockUnknown(true);
$new_part->addPartLot($partLot);
}
$supplier_id = $request->get('supplier', null);
$supplier = $supplier_id ? $em->find(Supplier::class, $supplier_id): null;
if (null !== $supplier && $new_part->getOrderdetails()->isEmpty()) {
$orderdetail = new Orderdetail();
$orderdetail->setSupplier($supplier);
$new_part->addOrderdetail($orderdetail);
}
$form = $this->createForm(PartBaseType::class, $new_part);
$form->handleRequest($request);

View file

@ -62,9 +62,11 @@ class TypeaheadController extends AbstractController
/**
* @Route("/builtInResources/search/{query}", name="typeahead_builtInRessources", requirements={"query"= ".+"})
*
* @param string $query
* @param BuiltinAttachmentsFinder $finder
* @return JsonResponse
*/
public function builtInResources(Request $request, string $query, BuiltinAttachmentsFinder $finder)
public function builtInResources(string $query, BuiltinAttachmentsFinder $finder)
{
$array = $finder->find($query);

View file

@ -43,7 +43,6 @@ declare(strict_types=1);
namespace App\Controller;
use App\Entity\Attachments\UserAttachment;
use App\Entity\Parameters\PartParameter;
use App\Entity\UserSystem\User;
use App\Form\Permissions\PermissionsType;
use App\Form\UserAdminForm;
@ -69,7 +68,7 @@ class UserController extends AdminPages\BaseAdminController
protected $route_base = 'user';
protected $attachment_class = UserAttachment::class;
//Just define a value here to prevent error. It is not used.
protected $parameter_class = "not used";
protected $parameter_class = 'not used';
/**
* @Route("/{id}/edit/{timestamp}", requirements={"id"="\d+"}, name="user_edit")

View file

@ -43,7 +43,7 @@ declare(strict_types=1);
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Persistence\ObjectManager;
class AppFixtures extends Fixture
{

View file

@ -52,7 +52,7 @@ use App\Entity\Parts\MeasurementUnit;
use App\Entity\Parts\Storelocation;
use App\Entity\Parts\Supplier;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Persistence\ObjectManager;
use Doctrine\ORM\EntityManagerInterface;
use InvalidArgumentException;

View file

@ -44,7 +44,7 @@ namespace App\DataFixtures;
use App\Entity\UserSystem\Group;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Persistence\ObjectManager;
class GroupFixtures extends Fixture
{

View file

@ -89,16 +89,16 @@ class PartFixtures extends Fixture
$orderdetail = new Orderdetail();
$orderdetail->setSupplier($manager->find(Supplier::class, 1));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(1.0)->setPrice("10.0"));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(10.0)->setPrice("15.0"));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(1.0)->setPrice('10.0'));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(10.0)->setPrice('15.0'));
$part->addOrderdetail($orderdetail);
$orderdetail = new Orderdetail();
$orderdetail->setSupplierpartnr('BC 547');
$orderdetail->setObsolete(true);
$orderdetail->setSupplier($manager->find(Supplier::class, 1));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(1.0)->setPrice("10.0"));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(10.0)->setPrice("15.1"));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(1.0)->setPrice('10.0'));
$orderdetail->addPricedetail((new Pricedetail())->setPriceRelatedQuantity(10.0)->setPrice('15.1'));
$part->addOrderdetail($orderdetail);
$attachment = new PartAttachment();

View file

@ -44,7 +44,7 @@ namespace App\DataFixtures;
use App\Entity\UserSystem\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Persistence\ObjectManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

View file

@ -98,7 +98,7 @@ class FetchJoinORMAdapter extends ORMAdapter
}
}
public function getCount(QueryBuilder $queryBuilder, $identifier)
public function getCount(QueryBuilder $queryBuilder, string $identifier)
{
$paginator = new Paginator($queryBuilder);

View file

@ -216,7 +216,7 @@ class ORMAdapter extends AbstractAdapter
*
* @return int
*/
protected function getCount(QueryBuilder $queryBuilder, $identifier)
protected function getCount(QueryBuilder $queryBuilder, string $identifier)
{
$qb = clone $queryBuilder;

View file

@ -44,7 +44,6 @@ namespace App\DataTables\Column;
use App\Entity\Attachments\Attachment;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Contracts\NamedElementInterface;
use App\Entity\LogSystem\AbstractLogEntry;
use App\Entity\Parameters\AbstractParameter;
@ -126,15 +125,15 @@ class LogEntryTargetColumn extends AbstractColumn
//Add a hint to the associated element if possible
if (null !== $target && $this->options['show_associated']) {
if ($target instanceof Attachment && $target->getElement() !== null) {
if ($target instanceof Attachment && null !== $target->getElement()) {
$on = $target->getElement();
} elseif ($target instanceof AbstractParameter && $target->getElement() !== null) {
} elseif ($target instanceof AbstractParameter && null !== $target->getElement()) {
$on = $target->getElement();
} elseif ($target instanceof PartLot && $target->getPart() !== null) {
} elseif ($target instanceof PartLot && null !== $target->getPart()) {
$on = $target->getPart();
} elseif ($target instanceof Orderdetail && $target->getPart() !== null) {
} elseif ($target instanceof Orderdetail && null !== $target->getPart()) {
$on = $target->getPart();
} elseif ($target instanceof Pricedetail && $target->getOrderdetail() !== null && $target->getOrderdetail()->getPart() !== null) {
} elseif ($target instanceof Pricedetail && null !== $target->getOrderdetail() && null !== $target->getOrderdetail()->getPart()) {
$on = $target->getOrderdetail()->getPart();
}

View file

@ -49,7 +49,6 @@ class RevertLogColumn extends AbstractColumn
public function render($value, $context)
{
$revertable = true;
if (
$context instanceof CollectionElementDeleted
|| ($context instanceof ElementDeletedLogEntry && $context->hasOldDataInformations())

View file

@ -212,7 +212,7 @@ class LogDataTable implements DataTableTypeInterface
$dataTable->add('target', LogEntryTargetColumn::class, [
'label' => $this->translator->trans('log.target'),
'show_associated' => $options['mode'] !== 'element_history',
'show_associated' => 'element_history' !== $options['mode'],
]);
$dataTable->add('extra', LogEntryExtraColumn::class, [

View file

@ -329,8 +329,6 @@ final class PartsDataTable implements DataTableTypeInterface
private function buildCriteria(QueryBuilder $builder, array $options): void
{
$em = $builder->getEntityManager();
if (isset($options['category'])) {
$category = $options['category'];
$list = $this->treeBuilder->typeToNodesList(Category::class, $category);

View file

@ -40,6 +40,7 @@ class AttachmentType extends AbstractStructuralDBElement
{
/**
* @ORM\OneToMany(targetEntity="AttachmentType", mappedBy="parent", cascade={"persist"})
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -56,13 +57,14 @@ class AttachmentType extends AbstractStructuralDBElement
*/
protected $filetype_filter = '';
/**
* @var Collection|AttachmentTypeAttachment[]
* @var Collection<int, AttachmentTypeAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\AttachmentTypeAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
/** @var AttachmentTypeParameter[]
/** @var Collection<int, AttachmentTypeParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\AttachmentTypeParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
@ -70,7 +72,7 @@ class AttachmentType extends AbstractStructuralDBElement
protected $parameters;
/**
* @var Collection|Attachment[]
* @var Collection<int, Attachment>
* @ORM\OneToMany(targetEntity="Attachment", mappedBy="attachment_type")
*/
protected $attachments_with_type;

View file

@ -43,11 +43,13 @@ declare(strict_types=1);
namespace App\Entity\Attachments;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to an attachmentType element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class AttachmentTypeAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\Parts\Category;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a category element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class CategoryAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\PriceInformations\Currency;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a currency element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class CurrencyAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\Devices\Device;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a device element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class DeviceAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\Parts\Footprint;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a footprint element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class FootprintAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\UserSystem\Group;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a Group element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class GroupAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\Parts\Manufacturer;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a manufacturer element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class ManufacturerAttachment extends Attachment
{

View file

@ -45,11 +45,13 @@ namespace App\Entity\Attachments;
use App\Entity\Parts\Manufacturer;
use App\Entity\Parts\MeasurementUnit;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a measurement unit element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class MeasurementUnitAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\Parts\Part;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a part element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class PartAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\Parts\Storelocation;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a measurement unit element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class StorelocationAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\Parts\Supplier;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a supplier element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class SupplierAttachment extends Attachment
{

View file

@ -44,11 +44,13 @@ namespace App\Entity\Attachments;
use App\Entity\UserSystem\User;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* A attachment attached to a user element.
*
* @ORM\Entity()
* @UniqueEntity({"name", "attachment_type", "element"})
*/
class UserAttachment extends Attachment
{

View file

@ -254,6 +254,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
* Get all sub elements of this element.
*
* @return Collection<static>|iterable all subelements as an array of objects (sorted by their full path)
* @psalm-return Collection<int, static>
*/
public function getSubelements(): iterable
{
@ -262,6 +263,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
/**
* @return Collection<static>|iterable
* @psalm-return Collection<int, static>
*/
public function getChildren(): iterable
{

View file

@ -67,6 +67,7 @@ class Device extends AbstractPartsContainingDBElement
{
/**
* @ORM\OneToMany(targetEntity="Device", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -93,12 +94,13 @@ class Device extends AbstractPartsContainingDBElement
*/
protected $order_only_missing_parts = false;
/**
* @var Collection|DeviceAttachment[]
* @var Collection<int, DeviceAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\DeviceAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $attachments;
/** @var DeviceParameter[]
/** @var Collection<int, DeviceParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\DeviceParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
*/

View file

@ -84,11 +84,7 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
return array_keys($this->getOldData());
}
if (isset($this->extra['f'])) {
return $this->extra['f'];
}
return [];
return $this->extra['f'] ?? [];
}
/**

View file

@ -28,7 +28,6 @@ use App\Entity\Base\AbstractNamedDBElement;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
use LogicException;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
/**
@ -121,16 +120,6 @@ abstract class AbstractParameter extends AbstractNamedDBElement
}
}
/**
* Returns the name of the specification (e.g. "Collector-Base Voltage").
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Returns the element this parameter belongs to.
*
@ -213,7 +202,8 @@ abstract class AbstractParameter extends AbstractNamedDBElement
}
/**
* Returns the name of the group this parameter is associated to (e.g. Technical Parameters)
* Returns the name of the group this parameter is associated to (e.g. Technical Parameters).
*
* @return string
*/
public function getGroup(): string
@ -223,12 +213,13 @@ abstract class AbstractParameter extends AbstractNamedDBElement
/**
* Sets the name of the group this parameter is associated to.
* @param string $group
*
* @return $this
*/
public function setGroup(string $group): self
{
$this->group = $group;
return $this;
}

View file

@ -31,7 +31,7 @@ trait ParametersTrait
/**
* Mapping done in subclasses.
*
* @var AbstractParameter[]|Collection
* @var Collection<int, AbstractParameter>
* @Assert\Valid()
*/
protected $parameters;
@ -39,9 +39,11 @@ trait ParametersTrait
/**
* Return all associated specifications.
*
* @return AbstractParameter[]|Collection
* @return Collection
*
* @psalm-return Collection<int, PartParameter>
*/
public function getParameters(): Collection
public function getParameters(): \Doctrine\Common\Collections\Collection
{
return $this->parameters;
}
@ -73,6 +75,7 @@ trait ParametersTrait
foreach ($this->parameters as $parameter) {
$tmp[$parameter->getGroup()][] = $parameter;
}
return $tmp;
}
}

View file

@ -39,6 +39,7 @@ class Category extends AbstractPartsContainingDBElement
{
/**
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -101,13 +102,14 @@ class Category extends AbstractPartsContainingDBElement
*/
protected $default_comment = '';
/**
* @var Collection|CategoryAttachment[]
* @var Collection<int, CategoryAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\CategoryAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
/** @var CategoryParameter[]
/** @var Collection<int, CategoryParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\CategoryParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()

View file

@ -73,6 +73,7 @@ class Footprint extends AbstractPartsContainingDBElement
/**
* @ORM\OneToMany(targetEntity="Footprint", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -81,8 +82,9 @@ class Footprint extends AbstractPartsContainingDBElement
*/
protected $parts;
/**
* @var Collection|FootprintAttachment[]
* @var Collection<int, FootprintAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\FootprintAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
@ -94,9 +96,9 @@ class Footprint extends AbstractPartsContainingDBElement
*/
protected $footprint_3d;
/** @var FootprintParameter[]
/** @var Collection<int, FootprintParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\FootprintParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})@ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
*/
protected $parameters;

View file

@ -73,6 +73,7 @@ class Manufacturer extends AbstractCompany
/**
* @ORM\OneToMany(targetEntity="Manufacturer", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -81,13 +82,14 @@ class Manufacturer extends AbstractCompany
*/
protected $parts;
/**
* @var Collection|ManufacturerAttachment[]
* @var Collection<int, ManufacturerAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\ManufacturerAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
/** @var ManufacturerParameter[]
/** @var Collection<int, ManufacturerParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\ManufacturerParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()

View file

@ -84,6 +84,7 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
/**
* @ORM\OneToMany(targetEntity="MeasurementUnit", mappedBy="parent", cascade={"persist"})
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -98,13 +99,14 @@ class MeasurementUnit extends AbstractPartsContainingDBElement
*/
protected $parts;
/**
* @var Collection|MeasurementUnitAttachment[]
* @var Collection<int, MeasurementUnitAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\MeasurementUnitAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
/** @var MeasurementUnitParameter[]
/** @var Collection<int, MeasurementUnitParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\MeasurementUnitParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()

View file

@ -52,6 +52,7 @@ namespace App\Entity\Parts;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Attachments\PartAttachment;
use App\Entity\Devices\Device;
use App\Entity\Parameters\ParametersTrait;
use App\Entity\Parameters\PartParameter;
@ -63,6 +64,7 @@ use App\Entity\Parts\PartTraits\OrderTrait;
use App\Security\Annotations\ColumnSecurity;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
@ -90,11 +92,10 @@ class Part extends AttachmentContainingDBElement
*/
protected $devices = [];
/** @var PartParameter[]
/** @var Collection<int, PartParameter>
* @Assert\Valid()
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\PartParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
*/
protected $parameters;
@ -117,8 +118,10 @@ class Part extends AttachmentContainingDBElement
protected $name = '';
/**
* @var Collection<int, PartAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\PartAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ColumnSecurity(type="collection", prefix="attachments")
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;

View file

@ -303,8 +303,20 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
return (float) $this->amount;
}
public function setAmount(float $new_amount): self
/**
* Sets the amount of parts in the part lot.
* If null is passed, amount will be set to unknown.
* @param float|null $new_amount
* @return $this
*/
public function setAmount(?float $new_amount): self
{
//Treat null like unknown amount
if ($new_amount === null) {
$this->instock_unknown = true;
$new_amount = 0.0;
}
$this->amount = $new_amount;
return $this;
@ -328,9 +340,6 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named
return $this;
}
/**
* @inheritDoc
*/
public function getName(): string
{
return $this->description;

View file

@ -57,6 +57,7 @@ trait InstockTrait
* @ORM\OneToMany(targetEntity="PartLot", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=true)
* @Assert\Valid()
* @ColumnSecurity(type="collection", prefix="lots")
* @ORM\OrderBy({"amount" = "DESC"})
*/
protected $partLots;

View file

@ -44,6 +44,7 @@ namespace App\Entity\Parts\PartTraits;
use App\Entity\PriceInformations\Orderdetail;
use App\Security\Annotations\ColumnSecurity;
use Doctrine\ORM\Mapping as ORM;
use function count;
use Doctrine\Common\Collections\Collection;
@ -57,6 +58,7 @@ trait OrderTrait
* @ORM\OneToMany(targetEntity="App\Entity\PriceInformations\Orderdetail", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=true)
* @Assert\Valid()
* @ColumnSecurity(prefix="orderdetails", type="collection")
* @ORM\OrderBy({"supplierpartnr" = "ASC"})
*/
protected $orderdetails;

View file

@ -67,6 +67,7 @@ class Storelocation extends AbstractPartsContainingDBElement
{
/**
* @ORM\OneToMany(targetEntity="Storelocation", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -92,7 +93,7 @@ class Storelocation extends AbstractPartsContainingDBElement
*/
protected $parts;
/** @var StorelocationParameter[]
/** @var Collection<int, StorelocationParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\StorelocationParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()
@ -117,7 +118,7 @@ class Storelocation extends AbstractPartsContainingDBElement
*/
protected $limit_to_existing_parts = false;
/**
* @var Collection|StorelocationAttachment[]
* @var Collection<int, StorelocationAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\StorelocationAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @Assert\Valid()
*/

View file

@ -69,6 +69,7 @@ class Supplier extends AbstractCompany
{
/**
* @ORM\OneToMany(targetEntity="Supplier", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -107,14 +108,16 @@ class Supplier extends AbstractCompany
* )
*/
protected $parts;
/**
* @var Collection|SupplierAttachment[]
* @var Collection<int, SupplierAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\SupplierAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
/** @var SupplierParameter[]
/** @var Collection<int, SupplierParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\SupplierParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()

View file

@ -78,6 +78,7 @@ class Currency extends AbstractStructuralDBElement
/**
* @ORM\OneToMany(targetEntity="Currency", mappedBy="parent", cascade={"persist"})
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -88,13 +89,14 @@ class Currency extends AbstractStructuralDBElement
protected $parent;
/**
* @var Collection|CurrencyAttachment[]
* @var Collection<int, CurrencyAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\CurrencyAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
/** @var CurrencyParameter[]
/** @var Collection<int, CurrencyParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\CurrencyParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()

View file

@ -59,6 +59,7 @@ use App\Entity\Parts\Supplier;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
/**
@ -67,6 +68,7 @@ use Symfony\Component\Validator\Constraints as Assert;
* @ORM\Table("`orderdetails`")
* @ORM\Entity()
* @ORM\HasLifecycleCallbacks()
* @UniqueEntity({"supplierpartnr", "supplier", "part"})
*/
class Orderdetail extends AbstractDBElement implements TimeStampableInterface, NamedElementInterface
{
@ -361,9 +363,6 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
return $this;
}
/**
* @inheritDoc
*/
public function getName(): string
{
return $this->getSupplierPartNr();

View file

@ -64,7 +64,7 @@ use Symfony\Component\Validator\Constraints as Assert;
* @ORM\Entity()
* @ORM\Table("`pricedetails`")
* @ORM\HasLifecycleCallbacks()
* @UniqueEntity(fields={"orderdetail", "min_discount_quantity"})
* @UniqueEntity(fields={"min_discount_quantity", "orderdetail"})
*/
class Pricedetail extends AbstractDBElement implements TimeStampableInterface
{
@ -138,9 +138,9 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface
/**
* Get the orderdetail to which this pricedetail belongs to this pricedetails.
*
* @return Orderdetail the orderdetail this price belongs to
* @return Orderdetail|null the orderdetail this price belongs to
*/
public function getOrderdetail(): Orderdetail
public function getOrderdetail(): ?Orderdetail
{
return $this->orderdetail;
}
@ -165,9 +165,12 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface
* You will get the price for $multiplier parts. If you want the price which is stored
* in the database, you have to pass the "price_related_quantity" count as $multiplier.
*
* @return string the price as a bcmath string
* @param float|string $multiplier The returned price (float or string) will be multiplied
* with this multiplier.
*
* @return null|string the price as a bcmath string
*/
public function getPricePerUnit($multiplier = 1.0): string
public function getPricePerUnit($multiplier = 1.0): ?string
{
$multiplier = (string) $multiplier;
$tmp = bcmul($this->price, $multiplier, static::PRICE_PRECISION);

View file

@ -61,6 +61,7 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa
{
/**
* @ORM\OneToMany(targetEntity="Group", mappedBy="parent")
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $children;
@ -81,8 +82,9 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa
*/
protected $enforce2FA = false;
/**
* @var Collection|GroupAttachment[]
* @var Collection<int, GroupAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\ManufacturerAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
* @Assert\Valid()
*/
protected $attachments;
@ -93,7 +95,7 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa
*/
protected $permissions;
/** @var GroupParameter[]
/** @var Collection<int, GroupParameter>
* @ORM\OneToMany(targetEntity="App\Entity\Parameters\GroupParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"group" = "ASC" ,"name" = "ASC"})
* @Assert\Valid()

View file

@ -53,7 +53,6 @@ namespace App\Entity\UserSystem;
use App\Entity\Attachments\AttachmentContainingDBElement;
use App\Entity\Attachments\UserAttachment;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Base\MasterAttachmentTrait;
use App\Entity\PriceInformations\Currency;
use App\Security\Interfaces\HasPermissionsInterface;
use App\Validator\Constraints\Selectable;
@ -114,7 +113,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
* @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;
protected $pw_reset_token;
/**
* @ORM\Column(type="text", name="config_instock_comment_a")
@ -228,8 +227,9 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
protected $settings = [];
/**
* @var Collection|UserAttachment[]
* @var Collection<int, UserAttachment>
* @ORM\OneToMany(targetEntity="App\Entity\Attachments\UserAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $attachments;
@ -238,7 +238,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
*/
protected $backupCodesGenerationDate;
/** @var Collection<TwoFactorKeyInterface>
/** @var Collection<int, TwoFactorKeyInterface>
* @ORM\OneToMany(targetEntity="App\Entity\UserSystem\U2FKey", mappedBy="user", cascade={"REMOVE"}, orphanRemoval=true)
*/
protected $u2fKeys;
@ -252,7 +252,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
* @ORM\JoinColumn(name="currency_id", referencedColumnName="id")
* @Selectable()
*/
protected $currency = null;
protected $currency;
/** @var PermissionsEmbed
* @ORM\Embedded(class="PermissionsEmbed", columnPrefix="perms_")
@ -264,7 +264,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
* @var DateTime The time until the password reset token is valid.
* @ORM\Column(type="datetime", nullable=true)
*/
protected $pw_reset_expires = null;
protected $pw_reset_expires;
public function __construct()
{
@ -865,7 +865,9 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe
/**
* Get all U2F Keys that are associated with this user.
*
* @return Collection<TwoFactorKeyInterface>
* @return Collection
*
* @psalm-return Collection<int, TwoFactorKeyInterface>
*/
public function getU2FKeys(): Collection
{

View file

@ -77,12 +77,21 @@ class AttachmentDeleteListener
public function preUpdateHandler(Attachment $attachment, PreUpdateEventArgs $event): void
{
if ($event->hasChangedField('path')) {
$old_path = $event->getOldValue('path');
//Dont delete file if the attachment uses a builtin ressource:
if (Attachment::checkIfBuiltin($event->getOldValue('path'))) {
if (Attachment::checkIfBuiltin($old_path)) {
return;
}
$file = new SplFileInfo($this->pathResolver->placeholderToRealPath($event->getOldValue('path')));
$real_path = $this->pathResolver->placeholderToRealPath($old_path);
//If the attachment does not point to a valid file, ignore it!
if ($real_path === null) {
return;
}
$file = new SplFileInfo($real_path);
$this->attachmentReverseSearch->deleteIfNotUsed($file);
}
}

View file

@ -60,7 +60,7 @@ class EventLoggerSubscriber implements EventSubscriber
Orderdetail::class => ['part'],
Pricedetail::class => ['orderdetail'],
Attachment::class => ['element'],
AbstractParameter::class => ['element']
AbstractParameter::class => ['element'],
];
protected const MAX_STRING_LENGTH = 2000;
@ -163,7 +163,7 @@ class EventLoggerSubscriber implements EventSubscriber
*/
public function hasFieldRestrictions(AbstractDBElement $element): bool
{
foreach (static::FIELD_BLACKLIST as $class => $blacklist) {
foreach (array_keys(static::FIELD_BLACKLIST) as $class) {
if (is_a($element, $class)) {
return true;
}
@ -283,7 +283,7 @@ class EventLoggerSubscriber implements EventSubscriber
}, ARRAY_FILTER_USE_BOTH);
}
protected function saveChangeSet(AbstractDBElement $entity, AbstractLogEntry $logEntry, EntityManagerInterface $em, $element_deleted = false): void
protected function saveChangeSet(AbstractDBElement $entity, AbstractLogEntry $logEntry, EntityManagerInterface $em, bool $element_deleted = false): void
{
$uow = $em->getUnitOfWork();

View file

@ -53,8 +53,6 @@ use Symfony\Component\Security\Core\Security;
final class LogoutOnDisabledUserListener implements EventSubscriberInterface
{
private $security;
private $translator;
private $flashBag;
private $urlGenerator;
public function __construct(Security $security, UrlGeneratorInterface $urlGenerator)

View file

@ -45,14 +45,15 @@ namespace App\EventSubscriber;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
final class SymfonyDebugToolbarSubscriber implements EventSubscriberInterface
{
private $kernel;
private $kernel_debug;
public function __construct(ContainerInterface $kernel)
public function __construct(bool $kernel_debug)
{
$this->kernel = $kernel;
$this->kernel_debug = $kernel_debug;
}
/**
@ -78,9 +79,9 @@ final class SymfonyDebugToolbarSubscriber implements EventSubscriberInterface
return ['kernel.response' => 'onKernelResponse'];
}
public function onKernelResponse(FilterResponseEvent $event): void
public function onKernelResponse(ResponseEvent $event): void
{
if (! $this->kernel->getParameter('kernel.debug')) {
if (! $this->kernel_debug) {
return;
}

View file

@ -45,7 +45,6 @@ namespace App\Form\AdminPages;
use App\Entity\Attachments\Attachment;
use App\Entity\Base\AbstractNamedDBElement;
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Parameters\PartParameter;
use App\Form\AttachmentFormType;
use App\Form\ParameterType;
use App\Form\Type\MasterPictureAttachmentType;
@ -133,6 +132,7 @@ class BaseEntityAdminForm extends AbstractType
'allow_add' => true,
'allow_delete' => true,
'label' => false,
'reindex_enable' => true,
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
'entry_options' => [
'data_class' => $options['attachment_class'],
@ -159,6 +159,7 @@ class BaseEntityAdminForm extends AbstractType
'allow_add' => $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
'allow_delete' => $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
'disabled' => ! $this->security->isGranted($is_new ? 'create' : 'edit', $entity),
'reindex_enable' => true,
'label' => false,
'by_reference' => false,
'prototype_data' => new $options['parameter_class'](),

View file

@ -57,6 +57,7 @@ use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\Validator\Constraints\Url;
@ -65,13 +66,15 @@ class AttachmentFormType extends AbstractType
protected $attachment_helper;
protected $urlGenerator;
protected $allow_attachments_download;
protected $security;
public function __construct(AttachmentManager $attachmentHelper,
UrlGeneratorInterface $urlGenerator, bool $allow_attachments_downloads)
UrlGeneratorInterface $urlGenerator, Security $security, bool $allow_attachments_downloads)
{
$this->attachment_helper = $attachmentHelper;
$this->urlGenerator = $urlGenerator;
$this->allow_attachments_download = $allow_attachments_downloads;
$this->security = $security;
}
public function buildForm(FormBuilderInterface $builder, array $options): void
@ -103,6 +106,7 @@ class AttachmentFormType extends AbstractType
'required' => false,
'label' => 'attachment.edit.secure_file',
'mapped' => false,
'disabled' => !$this->security->isGranted('@parts_attachments.show_private'),
'attr' => [
'class' => 'form-control-sm',
],

View file

@ -0,0 +1,120 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Form;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormConfigBuilder;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
/**
* Perform a reindexing on CollectionType elements, by assigning the database id as index.
* This prevents issues when the collection that is edited uses a OrderBy annotation and therefore the direction of the
* elements can change during requests.
* Must me enabled by setting reindex_enable to true in Type options.
* @package App\Form
*/
class CollectionTypeExtension extends AbstractTypeExtension
{
protected $propertyAccess;
public function __construct(PropertyAccessorInterface $propertyAccess)
{
$this->propertyAccess = $propertyAccess;
}
public static function getExtendedTypes(): iterable
{
return [CollectionType::class];
}
public function configureOptions(OptionsResolver $resolver)
{
/*$resolver->setDefault('error_mapping', function (Options $options) {
$options->
});*/
$resolver->setDefaults([
'reindex_enable' => false,
'reindex_prefix' => 'db_',
'reindex_path' => 'id',
]);
$resolver->setAllowedTypes('reindex_enable', 'bool');
$resolver->setAllowedTypes('reindex_prefix', 'string');
$resolver->setAllowedTypes('reindex_path', 'string');
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
$data = $event->getData();
$config = $event->getForm()->getConfig();
//If enabled do a reindexing of the collection
if ($options['reindex_enable'] && $data instanceof Collection) {
$reindexed_data = new ArrayCollection();
$error_mapping = [];
foreach ($data->toArray() as $key => $item) {
$index = $options['reindex_prefix'] . $this->propertyAccess->getValue($item, $options['reindex_path']);
$error_mapping['[' . $key . ']'] = $index;
$reindexed_data->set($index, $item);
}
$event->setData($reindexed_data);
//Add error mapping, so that validator error are mapped correctly to the new index fields
if ($config instanceof FormBuilder && empty($config->getOption('error_mapping'))) {
$this->setOption($config, 'error_mapping', $error_mapping);
}
}
}, 100); //We need to have a higher priority then the PRE_SET_DATA listener on CollectionType
}
/**
* Set the option of the form.
* This a bit hacky cause we access private properties....
* @param $builder
* @param string $option
* @param $value
* @throws \ReflectionException
*/
public function setOption(FormBuilder $builder, string $option, $value): void
{
//We have to use FormConfigBuilder::class here, because options is private and not available in sub classes
$reflection = new \ReflectionClass(FormConfigBuilder::class);
$property = $reflection->getProperty('options');
$property->setAccessible(true);
$tmp = $property->getValue($builder);
$tmp[$option] = $value;
$property->setValue($builder, $tmp);
$property->setAccessible(false);
}
}

View file

@ -113,7 +113,7 @@ class ParameterType extends AbstractType
'attr' => [
'placeholder' => 'parameter.group.placeholder',
'class' => 'form-control-sm',
]
],
]);
}

View file

@ -69,9 +69,6 @@ class OrderdetailType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options): void
{
/** @var Orderdetail $orderdetail */
$orderdetail = $builder->getData();
$builder->add('supplierpartnr', TextType::class, [
'label' => 'orderdetails.edit.supplierpartnr',
'attr' => [
@ -117,6 +114,7 @@ class OrderdetailType extends AbstractType
'allow_add' => $this->security->isGranted('@parts_prices.create'),
'allow_delete' => $this->security->isGranted('@parts_prices.delete'),
'label' => false,
'reindex_enable' => true,
'prototype_data' => $dummy_pricedetail,
'by_reference' => false,
'entry_options' => [

View file

@ -52,7 +52,6 @@ use App\Entity\Parts\MeasurementUnit;
use App\Entity\Parts\Part;
use App\Entity\PriceInformations\Orderdetail;
use App\Form\AttachmentFormType;
use App\Form\ParameterGroupType;
use App\Form\ParameterType;
use App\Form\Type\MasterPictureAttachmentType;
use App\Form\Type\SIUnitType;
@ -225,6 +224,7 @@ class PartBaseType extends AbstractType
'entry_type' => PartLotType::class,
'allow_add' => $this->security->isGranted('lots.create', $part),
'allow_delete' => $this->security->isGranted('lots.delete', $part),
'reindex_enable' => true,
'label' => false,
'entry_options' => [
'measurement_unit' => $part->getPartUnit(),
@ -238,6 +238,7 @@ class PartBaseType extends AbstractType
'entry_type' => AttachmentFormType::class,
'allow_add' => $this->security->isGranted('attachments.create', $part),
'allow_delete' => $this->security->isGranted('attachments.delete', $part),
'reindex_enable' => true,
'label' => false,
'entry_options' => [
'data_class' => PartAttachment::class,
@ -258,6 +259,7 @@ class PartBaseType extends AbstractType
'entry_type' => OrderdetailType::class,
'allow_add' => $this->security->isGranted('orderdetails.create', $part),
'allow_delete' => $this->security->isGranted('orderdetails.delete', $part),
'reindex_enable' => true,
'label' => false,
'by_reference' => false,
'prototype_data' => new Orderdetail(),
@ -272,6 +274,7 @@ class PartBaseType extends AbstractType
'allow_add' => $this->security->isGranted('parameters.create', $part),
'allow_delete' => $this->security->isGranted('parameters.delete', $part),
'label' => false,
'reindex_enable' => true,
'by_reference' => false,
'prototype_data' => new PartParameter(),
'entry_options' => [

View file

@ -49,7 +49,7 @@ use App\Form\Type\SIUnitType;
use App\Form\Type\StructuralEntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -88,6 +88,7 @@ class PartLotType extends AbstractType
$builder->add('amount', SIUnitType::class, [
'measurement_unit' => $options['measurement_unit'],
'required' => false,
'label' => 'part_lot.edit.amount',
'attr' => [
'class' => 'form-control-sm',
@ -116,9 +117,11 @@ class PartLotType extends AbstractType
'required' => false,
]);
$builder->add('expirationDate', DateTimeType::class, [
$builder->add('expirationDate', DateType::class, [
'label' => 'part_lot.edit.expiration_date',
'attr' => [],
'widget' => 'single_text',
'model_timezone' => 'UTC',
'required' => false,
]);

View file

@ -86,7 +86,7 @@ class PermissionsType extends AbstractType
{
$groups = $this->perm_structure['groups'];
foreach ($groups as $key => $group) {
foreach (array_keys($groups) as $key) {
$builder->add($key, PermissionGroupType::class, [
'group_name' => $key,
'mapped' => false,

View file

@ -102,7 +102,7 @@ class CurrencyEntityType extends StructuralEntityType
$level -= $parent->getLevel() - 1;
}
$tmp = str_repeat('&nbsp;&nbsp;&nbsp;', $choice->getLevel()); //Use 3 spaces for intendation
$tmp = str_repeat('&nbsp;&nbsp;&nbsp;', $level); //Use 3 spaces for intendation
if (empty($choice->getIsoCode())) {
$tmp .= htmlspecialchars($choice->getName());
} else {

View file

@ -191,7 +191,7 @@ class StructuralEntityType extends AbstractType
*
* @throws TransformationFailedException when the transformation fails
*/
public function transform($value, $options)
public function transform($value, array $options)
{
return $value;
}
@ -223,7 +223,7 @@ class StructuralEntityType extends AbstractType
*
* @throws TransformationFailedException when the transformation fails
*/
public function reverseTransform($value, $options)
public function reverseTransform($value, array $options)
{
/* This step is important in combination with the caching!
The elements deserialized from cache, are not known to Doctrinte ORM any more, so doctrine thinks,
@ -272,7 +272,7 @@ class StructuralEntityType extends AbstractType
$level -= $parent->getLevel() - 1;
}
$tmp = str_repeat('&nbsp;&nbsp;&nbsp;', $choice->getLevel()); //Use 3 spaces for intendation
$tmp = str_repeat('&nbsp;&nbsp;&nbsp;', $level); //Use 3 spaces for intendation
$tmp .= htmlspecialchars($choice->getName());
return $tmp;

View file

@ -244,6 +244,7 @@ class UserAdminForm extends AbstractType
'allow_add' => true,
'allow_delete' => true,
'label' => false,
'reindex_enable' => true,
'entry_options' => [
'data_class' => $options['attachment_class'],
],

View file

@ -46,11 +46,6 @@ use JsonSerializable;
final class TreeViewNodeState implements JsonSerializable
{
/**
* @var bool|null
*/
private $checked = null;
/**
* @var bool|null
*/

View file

@ -41,7 +41,7 @@ final class Version1 extends AbstractMigration
try {
//Check if we can use this migration method:
$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($version > 0, 'Old Part-DB Database detected! Continue with upgrade...');
} catch (DBALException $dBALException) {
//when the table was not found, we can proceed, because we have an empty DB!
}

View file

@ -44,12 +44,13 @@ class DBElementRepository extends EntityRepository
->setParameter(1, $element->getID())
->getQuery();
$p = $q->execute();
//Do the renaming
$q->execute();
$this->setField($element, 'id', $new_id);
}
protected function setField(AbstractDBElement $element, string $field, $new_value): void
protected function setField(AbstractDBElement $element, string $field, int $new_value): void
{
$reflection = new \ReflectionClass(get_class($element));
$property = $reflection->getProperty($field);

View file

@ -142,7 +142,6 @@ class ElementPermissionListener
return;
}
$em = $eventArgs->getEntityManager();
$unitOfWork = $eventArgs->getEntityManager()->getUnitOfWork();
$reflectionClass = new ReflectionClass($element);

View file

@ -43,6 +43,7 @@ declare(strict_types=1);
namespace App\Security\Voter;
use App\Entity\UserSystem\User;
use App\Repository\UserRepository;
use App\Services\PermissionResolver;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@ -76,6 +77,7 @@ abstract class ExtendedVoter extends Voter
// if the user is anonymous, we use the anonymous user.
if (! $user instanceof User) {
/** @var UserRepository $repo */
$repo = $this->entityManager->getRepository(User::class);
$user = $repo->getAnonymousUser();
if (null === $user) {

View file

@ -62,6 +62,7 @@ class AmountFormatter
/**
* Formats the given value using the measurement unit and options.
*
* @param float|string|int $value
* @param MeasurementUnit|null $unit The measurement unit, whose unit symbol should be used for formatting.
* If set to null, it is assumed that the part amount is measured in pieces.
*

View file

@ -130,7 +130,7 @@ class AttachmentURLGenerator
throw new InvalidArgumentException('Thumbnail creation only works for picture attachments!');
}
if ($attachment->isExternal()) {
if ($attachment->isExternal() && !empty($attachment->getURL())) {
return $attachment->getURL();
}

View file

@ -43,10 +43,10 @@ declare(strict_types=1);
namespace App\Services\Attachments;
use App\Entity\Attachments\Attachment;
use Psr\Cache\InvalidArgumentException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Cache\CacheInterface;
use Psr\Cache\InvalidArgumentException;
/**
* This service is used to find builtin attachment ressources.

View file

@ -174,7 +174,7 @@ class FileTypeFilterTools
$extensions = array_merge($extensions, static::IMAGE_EXTS);
} elseif ('audio/*' === $element) {
$extensions = array_merge($extensions, static::AUDIO_EXTS);
} elseif ('image/*' === $element) {
} elseif ('video/*' === $element) {
$extensions = array_merge($extensions, static::VIDEO_EXTS);
} elseif (preg_match('#^[-\w.]+\/[-\w.*]+#', $element)) {
$extensions = array_merge($extensions, $this->mimeTypes->getExtensions($element));

View file

@ -61,7 +61,9 @@ class PartPreviewGenerator
*
* @param Part $part the part for which the attachments should be determined
*
* @return Attachment[]
* @return (Attachment|null)[]
*
* @psalm-return list<Attachment|null>
*/
public function getPreviewAttachments(Part $part): array
{

View file

@ -102,7 +102,7 @@ class ElementTypeNameGenerator
* Useful when the type should be shown to user.
* Throws an exception if the class is not supported.
*
* @param AbstractDBElement|string $entity The element or class for which the label should be generated
* @param object|string $entity The element or class for which the label should be generated
*
* @return string the localized label for the entity type
*

View file

@ -80,6 +80,7 @@ class EntityExporter
* Exports an Entity or an array of entities to multiple file formats.
*
* @param Request $request the request that should be used for option resolving
* @param AbstractNamedDBElement|object[] $entity
*
* @return Response the generated response containing the exported data
*

View file

@ -94,12 +94,12 @@ class EntityURLGenerator
* @param mixed $entity The element for which the page should be generated
* @param string $type The page type. Currently supported: 'info', 'edit', 'create', 'clone', 'list'/'list_parts'
*
* @return string the link to the desired page
* @return null|string the link to the desired page
*
* @throws EntityNotSupportedException thrown if the entity is not supported for the given type
* @throws InvalidArgumentException thrown if the givent type is not existing
*/
public function getURL($entity, string $type)
public function getURL($entity, string $type): ?string
{
switch ($type) {
case 'info':
@ -187,7 +187,7 @@ class EntityURLGenerator
throw new EntityNotSupportedException('The given entity is not supported yet!');
}
public function viewURL($entity): string
public function viewURL(Attachment $entity): ?string
{
if ($entity instanceof Attachment) {
if ($entity->isExternal()) { //For external attachments, return the link to external path
@ -201,7 +201,7 @@ class EntityURLGenerator
throw new EntityNotSupportedException('The given entity is not supported yet!');
}
public function downloadURL($entity): string
public function downloadURL($entity): ?string
{
if ($entity instanceof Attachment) {
if ($entity->isExternal()) { //For external attachments, return the link to external path
@ -383,7 +383,7 @@ class EntityURLGenerator
//Check if we have an direct mapping for the given class
if (! array_key_exists($class, $map)) {
//Check if we need to check inheritance by looping through our map
foreach ($map as $key => $value) {
foreach (array_keys($map) as $key) {
if (is_a($entity, $key)) {
return $map[$key];
}

View file

@ -60,10 +60,14 @@ class GitVersionInfo
*/
public function getGitBranchName()
{
if (file_exists($this->project_dir.'/.git/HEAD')) {
if (is_file($this->project_dir.'/.git/HEAD')) {
$git = file($this->project_dir.'/.git/HEAD');
$head = explode('/', $git[0], 3);
if (! isset($head[2])) {
return null;
}
return trim($head[2]);
}
@ -82,8 +86,13 @@ class GitVersionInfo
public function getGitCommitHash(int $length = 7)
{
$filename = $this->project_dir.'/.git/refs/remotes/origin/'.$this->getGitBranchName();
if (file_exists($filename)) {
if (is_file($filename)) {
$head = file($filename);
if (! isset($head[0])) {
return null;
}
$hash = $head[0];
return substr($hash, 0, $length);

View file

@ -31,7 +31,7 @@ class EventCommentHelper
public function __construct()
{
$message = null;
$this->message = null;
}
/**

View file

@ -37,7 +37,7 @@ class EventUndoHelper
public function __construct()
{
$undone_event = null;
$this->undone_event = null;
$this->mode = self::MODE_UNDO;
}

View file

@ -39,6 +39,8 @@ class HistoryHelper
* The returned array contains the given element.
*
* @return array
*
* @psalm-return array<\App\Entity\Parameters\AbstractParameter|array-key, mixed>
*/
public function getAssociatedElements(AbstractDBElement $element): array
{

View file

@ -209,6 +209,9 @@ class TimeTravel
return $property->getValue($element);
}
/**
* @param \DateTime|int|null $new_value
*/
protected function setField(AbstractDBElement $element, string $field, $new_value): void
{
$reflection = new \ReflectionClass(get_class($element));

View file

@ -1,4 +1,7 @@
<?php
declare(strict_types=1);
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
@ -20,21 +23,19 @@
namespace App\Services\Parameters;
use App\Entity\Parameters\AbstractParameter;
use App\Entity\Parameters\PartParameter;
class ParameterExtractor
{
protected const ALLOWED_PARAM_SEPARATORS = [", ", "\n"];
protected const ALLOWED_PARAM_SEPARATORS = [', ', "\n"];
protected const CHAR_LIMIT = 1000;
/**
* Tries to extract parameters from the given string.
* Useful for extraction from part description and comment.
* @param string $input
* @param string $class
*
* @return AbstractParameter[]
*/
public function extractParameters(string $input, string $class = PartParameter::class): array
@ -52,7 +53,7 @@ class ParameterExtractor
$split = $this->splitString($input);
foreach ($split as $param_string) {
$tmp = $this->stringToParam($param_string, $class);
if ($tmp !== null) {
if (null !== $tmp) {
$parameters[] = $tmp;
}
}
@ -67,9 +68,8 @@ class ParameterExtractor
$matches = [];
\preg_match($regex, $input, $matches);
dump($matches);
if (! empty($matches)) {
[$raw, $name, $value] = $matches;
[, $name, $value] = $matches;
$value = trim($value);
//Dont allow empty names or values (these are a sign of an invalid extracted string)
@ -91,7 +91,8 @@ class ParameterExtractor
protected function splitString(string $input): array
{
//Allow comma as limiter (include space, to prevent splitting in german style numbers)
$input = str_replace(static::ALLOWED_PARAM_SEPARATORS, ";", $input);
return explode(";", $input);
$input = str_replace(static::ALLOWED_PARAM_SEPARATORS, ';', $input);
return explode(';', $input);
}
}

View file

@ -62,12 +62,12 @@ class PermissionResolver
/**
* PermissionResolver constructor.
*/
public function __construct(ContainerInterface $container)
public function __construct(bool $kernel_debug, string $kernel_cache_dir)
{
$cache_dir = $container->getParameter('kernel.cache_dir');
$cache_dir = $kernel_cache_dir;
//Here the cached structure will be saved.
$this->cache_file = $cache_dir.'/permissions.php.cache';
$this->is_debug = $container->getParameter('kernel.debug');
$this->is_debug = $kernel_debug;
$this->permission_structure = $this->generatePermissionStructure();
@ -127,7 +127,7 @@ class PermissionResolver
return $allowed;
}
/** @var HasPermissionsInterface $parent */
/** @var Group $parent */
$parent = $user->getGroup();
while (null !== $parent) { //The top group, has parent == null
//Check if our current element gives a info about disallow/allow

View file

@ -30,12 +30,10 @@ use Twig\TwigFunction;
class LastUserExtension extends AbstractExtension
{
private $em;
private $repo;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
$this->repo = $em->getRepository(AbstractLogEntry::class);
}

View file

@ -42,7 +42,9 @@
</span>
</h6>
{% endif %}
{% if attach.picture %}
{% if attach.secure and not is_granted('show_private', attach) %}
{# Leave blank #}
{% elseif attach.picture %}
<a href="{{ attach | entityURL('file_view') }}" target="_blank" rel="noopener" data-no-ajax>
<img class="img-fluid img-thumbnail thumbnail-sm" src="{{ attachment_thumbnail(attach, 'thumbnail_md') }}" alt="{% trans %}attachment.preview.alt{% endtrans %}" />
</a>
@ -60,7 +62,7 @@
{% if attach.secure %}
<h6>
<span class="badge badge-primary">
<span class="badge badge-success">
<i class="fas fa-fw fa-shield-alt"></i> {% trans %}attachment.secure{% endtrans %}
</span>
</h6>
@ -90,7 +92,7 @@
//Determine the table, so we can determine, how many entries there are already.
$holder = $("#attachments_table");
var index = $holder.find(":input").length;
var index = $holder.children("tbody").children("tr").length;
var newForm = $holder.data("prototype");
//Increase the index

View file

@ -39,7 +39,7 @@
//Determine the table, so we can determine, how many entries there are already.
$holder = $(btn).siblings("table");
var index = $holder.find(":input").length;
var index = $holder.children("tbody").children("tr").length;
var newForm = $holder.data("prototype");
//Increase the index

View file

@ -40,7 +40,9 @@
</h6>
{% endif %}
{% if attach.picture %}
{% if attach.secure and not is_granted('show_private', attach) %}
{# Leave blank #}
{% elseif attach.picture %}
<a href="{{ attach | entityURL('file_view') }}" rel="noopener" target="_blank" data-no-ajax>
<img class="img-fluid img-thumbnail thumbnail-sm" src="{{ attachment_thumbnail(attach, 'thumbnail_md') }}" alt="{% trans %}attachment.preview.alt{% endtrans %}" />
</a>
@ -58,7 +60,7 @@
{% if attach.secure %}
<h6>
<span class="badge badge-primary">
<span class="badge badge-success">
<i class="fas fa-fw fa-shield-alt"></i> {% trans %}attachment.secure{% endtrans %}
</span>
</h6>
@ -88,7 +90,7 @@
//Determine the table, so we can determine, how many entries there are already.
$holder = $("#attachments_table");
var index = $holder.find(":input").length;
var index = $holder.children("tbody").children("tr").length;
var newForm = $holder.data("prototype");
//Increase the index

View file

@ -41,7 +41,7 @@
//Determine the table, so we can determine, how many entries there are already.
$holder = $("#lots_table");
var index = $holder.find(":input").length;
var index = $holder.children("tbody").children("tr").length;
var newForm = $holder.data("prototype");
//Increase the index

Some files were not shown because too many files have changed in this diff Show more