mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 09:35:49 +02:00
Allow to add a comment when editing/creating/deleting an element.
This commit is contained in:
parent
c14d6d91ff
commit
b6f95ebe48
19 changed files with 421 additions and 47 deletions
|
@ -52,6 +52,7 @@ use App\Services\Attachments\AttachmentManager;
|
||||||
use App\Services\Attachments\AttachmentSubmitHandler;
|
use App\Services\Attachments\AttachmentSubmitHandler;
|
||||||
use App\Services\EntityExporter;
|
use App\Services\EntityExporter;
|
||||||
use App\Services\EntityImporter;
|
use App\Services\EntityImporter;
|
||||||
|
use App\Services\LogSystem\EventCommentHelper;
|
||||||
use App\Services\StructuralElementRecursionHelper;
|
use App\Services\StructuralElementRecursionHelper;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
@ -77,9 +78,11 @@ abstract class BaseAdminController extends AbstractController
|
||||||
protected $translator;
|
protected $translator;
|
||||||
protected $attachmentHelper;
|
protected $attachmentHelper;
|
||||||
protected $attachmentSubmitHandler;
|
protected $attachmentSubmitHandler;
|
||||||
|
protected $commentHelper;
|
||||||
|
|
||||||
public function __construct(TranslatorInterface $translator, UserPasswordEncoderInterface $passwordEncoder,
|
public function __construct(TranslatorInterface $translator, UserPasswordEncoderInterface $passwordEncoder,
|
||||||
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler)
|
AttachmentManager $attachmentHelper, AttachmentSubmitHandler $attachmentSubmitHandler,
|
||||||
|
EventCommentHelper $commentHelper)
|
||||||
{
|
{
|
||||||
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!');
|
||||||
|
@ -93,6 +96,7 @@ abstract class BaseAdminController extends AbstractController
|
||||||
$this->passwordEncoder = $passwordEncoder;
|
$this->passwordEncoder = $passwordEncoder;
|
||||||
$this->attachmentHelper = $attachmentHelper;
|
$this->attachmentHelper = $attachmentHelper;
|
||||||
$this->attachmentSubmitHandler = $attachmentSubmitHandler;
|
$this->attachmentSubmitHandler = $attachmentSubmitHandler;
|
||||||
|
$this->commentHelper = $commentHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -131,6 +135,8 @@ abstract class BaseAdminController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->commentHelper->setMessage($form['log_comment']->getData());
|
||||||
|
|
||||||
$em->persist($entity);
|
$em->persist($entity);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$this->addFlash('success', 'entity.edit_flash');
|
$this->addFlash('success', 'entity.edit_flash');
|
||||||
|
@ -188,6 +194,8 @@ abstract class BaseAdminController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->commentHelper->setMessage($form['log_comment']->getData());
|
||||||
|
|
||||||
$em->persist($new_entity);
|
$em->persist($new_entity);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$this->addFlash('success', 'entity.created_flash');
|
$this->addFlash('success', 'entity.created_flash');
|
||||||
|
@ -215,6 +223,10 @@ abstract class BaseAdminController extends AbstractController
|
||||||
'csv_separator' => $data['csv_separator'],
|
'csv_separator' => $data['csv_separator'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$this->commentHelper->setMessage('Import ' . $file->getClientOriginalName());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$errors = $importer->fileToDBEntities($file, $this->entity_class, $options);
|
$errors = $importer->fileToDBEntities($file, $this->entity_class, $options);
|
||||||
|
|
||||||
foreach ($errors as $name => $error) {
|
foreach ($errors as $name => $error) {
|
||||||
|
@ -280,6 +292,8 @@ abstract class BaseAdminController extends AbstractController
|
||||||
$entityManager->remove($entity);
|
$entityManager->remove($entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->commentHelper->setMessage($request->request->get('log_comment', null));
|
||||||
|
|
||||||
//Flush changes
|
//Flush changes
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ use App\Form\Part\PartBaseType;
|
||||||
use App\Services\Attachments\AttachmentManager;
|
use App\Services\Attachments\AttachmentManager;
|
||||||
use App\Services\Attachments\AttachmentSubmitHandler;
|
use App\Services\Attachments\AttachmentSubmitHandler;
|
||||||
use App\Services\Attachments\PartPreviewGenerator;
|
use App\Services\Attachments\PartPreviewGenerator;
|
||||||
|
use App\Services\LogSystem\EventCommentHelper;
|
||||||
use App\Services\LogSystem\HistoryHelper;
|
use App\Services\LogSystem\HistoryHelper;
|
||||||
use App\Services\LogSystem\TimeTravel;
|
use App\Services\LogSystem\TimeTravel;
|
||||||
use App\Services\PricedetailHelper;
|
use App\Services\PricedetailHelper;
|
||||||
|
@ -71,12 +72,15 @@ class PartController extends AbstractController
|
||||||
protected $attachmentManager;
|
protected $attachmentManager;
|
||||||
protected $pricedetailHelper;
|
protected $pricedetailHelper;
|
||||||
protected $partPreviewGenerator;
|
protected $partPreviewGenerator;
|
||||||
|
protected $commentHelper;
|
||||||
|
|
||||||
public function __construct(AttachmentManager $attachmentManager, PricedetailHelper $pricedetailHelper, PartPreviewGenerator $partPreviewGenerator)
|
public function __construct(AttachmentManager $attachmentManager, PricedetailHelper $pricedetailHelper,
|
||||||
|
PartPreviewGenerator $partPreviewGenerator, EventCommentHelper $commentHelper)
|
||||||
{
|
{
|
||||||
$this->attachmentManager = $attachmentManager;
|
$this->attachmentManager = $attachmentManager;
|
||||||
$this->pricedetailHelper = $pricedetailHelper;
|
$this->pricedetailHelper = $pricedetailHelper;
|
||||||
$this->partPreviewGenerator = $partPreviewGenerator;
|
$this->partPreviewGenerator = $partPreviewGenerator;
|
||||||
|
$this->commentHelper = $commentHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,6 +170,8 @@ class PartController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->commentHelper->setMessage($form['log_comment']->getData());
|
||||||
|
|
||||||
$em->persist($part);
|
$em->persist($part);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$this->addFlash('info', 'part.edited_flash');
|
$this->addFlash('info', 'part.edited_flash');
|
||||||
|
@ -197,6 +203,8 @@ class PartController extends AbstractController
|
||||||
if ($this->isCsrfTokenValid('delete'.$part->getId(), $request->request->get('_token'))) {
|
if ($this->isCsrfTokenValid('delete'.$part->getId(), $request->request->get('_token'))) {
|
||||||
$entityManager = $this->getDoctrine()->getManager();
|
$entityManager = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$this->commentHelper->setMessage($request->request->get('log_comment', null));
|
||||||
|
|
||||||
//Remove part
|
//Remove part
|
||||||
$entityManager->remove($part);
|
$entityManager->remove($part);
|
||||||
|
|
||||||
|
@ -257,6 +265,8 @@ class PartController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->commentHelper->setMessage($form['log_comment']->getData());
|
||||||
|
|
||||||
$em->persist($new_part);
|
$em->persist($new_part);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$this->addFlash('success', 'part.created_flash');
|
$this->addFlash('success', 'part.created_flash');
|
||||||
|
|
45
src/Entity/Contracts/LogWithCommentInterface.php
Normal file
45
src/Entity/Contracts/LogWithCommentInterface.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?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\Entity\Contracts;
|
||||||
|
|
||||||
|
|
||||||
|
interface LogWithCommentInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks if this log entry has a user provided comment.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasComment(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user provided comment associated with this log entry.
|
||||||
|
* Returns null if not comment was set.
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getComment(): ?string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the user provided comment associated with this log entry.
|
||||||
|
* @param string|null $new_comment
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setComment(?string $new_comment): self;
|
||||||
|
}
|
|
@ -43,12 +43,13 @@ declare(strict_types=1);
|
||||||
namespace App\Entity\LogSystem;
|
namespace App\Entity\LogSystem;
|
||||||
|
|
||||||
use App\Entity\Base\AbstractDBElement;
|
use App\Entity\Base\AbstractDBElement;
|
||||||
|
use App\Entity\Contracts\LogWithCommentInterface;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity()
|
||||||
*/
|
*/
|
||||||
class ElementCreatedLogEntry extends AbstractLogEntry
|
class ElementCreatedLogEntry extends AbstractLogEntry implements LogWithCommentInterface
|
||||||
{
|
{
|
||||||
protected $typeString = 'element_created';
|
protected $typeString = 'element_created';
|
||||||
|
|
||||||
|
@ -78,4 +79,29 @@ class ElementCreatedLogEntry extends AbstractLogEntry
|
||||||
{
|
{
|
||||||
return null !== $this->getCreationInstockValue();
|
return null !== $this->getCreationInstockValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function hasComment(): bool
|
||||||
|
{
|
||||||
|
return isset($this->extra['m']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getComment(): ?string
|
||||||
|
{
|
||||||
|
return $this->extra['m'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function setComment(?string $new_comment): LogWithCommentInterface
|
||||||
|
{
|
||||||
|
$this->extra['m'] = $new_comment;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ declare(strict_types=1);
|
||||||
namespace App\Entity\LogSystem;
|
namespace App\Entity\LogSystem;
|
||||||
|
|
||||||
use App\Entity\Base\AbstractDBElement;
|
use App\Entity\Base\AbstractDBElement;
|
||||||
|
use App\Entity\Contracts\LogWithCommentInterface;
|
||||||
use App\Entity\Contracts\NamedElementInterface;
|
use App\Entity\Contracts\NamedElementInterface;
|
||||||
use App\Entity\Contracts\TimeTravelInterface;
|
use App\Entity\Contracts\TimeTravelInterface;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
@ -50,7 +51,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity()
|
||||||
*/
|
*/
|
||||||
class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInterface
|
class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface
|
||||||
{
|
{
|
||||||
protected $typeString = 'element_deleted';
|
protected $typeString = 'element_deleted';
|
||||||
|
|
||||||
|
@ -111,4 +112,29 @@ class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInter
|
||||||
{
|
{
|
||||||
return $this->extra['d'] ?? [];
|
return $this->extra['d'] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function hasComment(): bool
|
||||||
|
{
|
||||||
|
return isset($this->extra['m']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getComment(): ?string
|
||||||
|
{
|
||||||
|
return $this->extra['m'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function setComment(?string $new_comment): LogWithCommentInterface
|
||||||
|
{
|
||||||
|
$this->extra['m'] = $new_comment;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,13 +43,14 @@ declare(strict_types=1);
|
||||||
namespace App\Entity\LogSystem;
|
namespace App\Entity\LogSystem;
|
||||||
|
|
||||||
use App\Entity\Base\AbstractDBElement;
|
use App\Entity\Base\AbstractDBElement;
|
||||||
|
use App\Entity\Contracts\LogWithCommentInterface;
|
||||||
use App\Entity\Contracts\TimeTravelInterface;
|
use App\Entity\Contracts\TimeTravelInterface;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity()
|
||||||
*/
|
*/
|
||||||
class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface
|
class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface
|
||||||
{
|
{
|
||||||
protected $typeString = 'element_edited';
|
protected $typeString = 'element_edited';
|
||||||
|
|
||||||
|
@ -72,16 +73,6 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the message associated with this edit change.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getMessage(): string
|
|
||||||
{
|
|
||||||
return $this->extra['m'] ?? '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
@ -97,4 +88,29 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
|
||||||
{
|
{
|
||||||
return $this->extra['d'] ?? [];
|
return $this->extra['d'] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function hasComment(): bool
|
||||||
|
{
|
||||||
|
return isset($this->extra['m']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getComment(): ?string
|
||||||
|
{
|
||||||
|
return $this->extra['m'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function setComment(?string $new_comment): LogWithCommentInterface
|
||||||
|
{
|
||||||
|
$this->extra['m'] = $new_comment;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ use App\Entity\LogSystem\AbstractLogEntry;
|
||||||
use App\Entity\LogSystem\ElementCreatedLogEntry;
|
use App\Entity\LogSystem\ElementCreatedLogEntry;
|
||||||
use App\Entity\LogSystem\ElementDeletedLogEntry;
|
use App\Entity\LogSystem\ElementDeletedLogEntry;
|
||||||
use App\Entity\LogSystem\ElementEditedLogEntry;
|
use App\Entity\LogSystem\ElementEditedLogEntry;
|
||||||
|
use App\Services\LogSystem\EventCommentHelper;
|
||||||
use App\Services\LogSystem\EventLogger;
|
use App\Services\LogSystem\EventLogger;
|
||||||
use Doctrine\Common\EventSubscriber;
|
use Doctrine\Common\EventSubscriber;
|
||||||
use Doctrine\ORM\Event\OnFlushEventArgs;
|
use Doctrine\ORM\Event\OnFlushEventArgs;
|
||||||
|
@ -38,11 +39,13 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||||
{
|
{
|
||||||
protected $logger;
|
protected $logger;
|
||||||
protected $serializer;
|
protected $serializer;
|
||||||
|
protected $eventCommentHelper;
|
||||||
|
|
||||||
public function __construct(EventLogger $logger, SerializerInterface $serializer)
|
public function __construct(EventLogger $logger, SerializerInterface $serializer, EventCommentHelper $commentHelper)
|
||||||
{
|
{
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->serializer = $serializer;
|
$this->serializer = $serializer;
|
||||||
|
$this->eventCommentHelper = $commentHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onFlush(OnFlushEventArgs $eventArgs)
|
public function onFlush(OnFlushEventArgs $eventArgs)
|
||||||
|
@ -59,6 +62,10 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||||
if ($this->validEntity($entity)) {
|
if ($this->validEntity($entity)) {
|
||||||
$log = new ElementEditedLogEntry($entity);
|
$log = new ElementEditedLogEntry($entity);
|
||||||
$this->saveChangeSet($entity, $log, $uow);
|
$this->saveChangeSet($entity, $log, $uow);
|
||||||
|
//Add user comment to log entry
|
||||||
|
if ($this->eventCommentHelper->isMessageSet()) {
|
||||||
|
$log->setComment($this->eventCommentHelper->getMessage());
|
||||||
|
}
|
||||||
$this->logger->log($log);
|
$this->logger->log($log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +73,10 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||||
foreach ($uow->getScheduledEntityDeletions() as $entity) {
|
foreach ($uow->getScheduledEntityDeletions() as $entity) {
|
||||||
if ($this->validEntity($entity)) {
|
if ($this->validEntity($entity)) {
|
||||||
$log = new ElementDeletedLogEntry($entity);
|
$log = new ElementDeletedLogEntry($entity);
|
||||||
|
//Add user comment to log entry
|
||||||
|
if ($this->eventCommentHelper->isMessageSet()) {
|
||||||
|
$log->setComment($this->eventCommentHelper->getMessage());
|
||||||
|
}
|
||||||
$this->saveChangeSet($entity, $log, $uow);
|
$this->saveChangeSet($entity, $log, $uow);
|
||||||
$this->logger->log($log);
|
$this->logger->log($log);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +93,6 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||||
}
|
}
|
||||||
|
|
||||||
$changeSet = $uow->getEntityChangeSet($entity);
|
$changeSet = $uow->getEntityChangeSet($entity);
|
||||||
dump($changeSet);
|
|
||||||
$old_data = array_diff(array_combine(array_keys($changeSet), array_column($changeSet, 0)), [null]);
|
$old_data = array_diff(array_combine(array_keys($changeSet), array_column($changeSet, 0)), [null]);
|
||||||
$logEntry->setOldData($old_data);
|
$logEntry->setOldData($old_data);
|
||||||
}
|
}
|
||||||
|
@ -95,6 +105,10 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||||
$entity = $args->getObject();
|
$entity = $args->getObject();
|
||||||
if ($this->validEntity($entity)) {
|
if ($this->validEntity($entity)) {
|
||||||
$log = new ElementCreatedLogEntry($entity);
|
$log = new ElementCreatedLogEntry($entity);
|
||||||
|
//Add user comment to log entry
|
||||||
|
if ($this->eventCommentHelper->isMessageSet()) {
|
||||||
|
$log->setComment($this->eventCommentHelper->getMessage());
|
||||||
|
}
|
||||||
$this->logger->log($log);
|
$this->logger->log($log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +121,9 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||||
if ($uow->hasPendingInsertions()) {
|
if ($uow->hasPendingInsertions()) {
|
||||||
$em->flush();
|
$em->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Clear the message provided by user.
|
||||||
|
$this->eventCommentHelper->clearMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -144,6 +144,13 @@ class BaseEntityAdminForm extends AbstractType
|
||||||
'entity' => $entity,
|
'entity' => $entity,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$builder->add('log_comment', TextType::class, [
|
||||||
|
'label' => 'edit.log_comment',
|
||||||
|
'mapped' => false,
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
//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',
|
||||||
|
|
|
@ -264,6 +264,13 @@ class PartBaseType extends AbstractType
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$builder->add('log_comment', TextType::class, [
|
||||||
|
'label' => 'edit.log_comment',
|
||||||
|
'mapped' => false,
|
||||||
|
'required' => false,
|
||||||
|
'empty_data' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
//Buttons
|
//Buttons
|
||||||
->add('save', SubmitType::class, ['label' => 'part.edit.save'])
|
->add('save', SubmitType::class, ['label' => 'part.edit.save'])
|
||||||
|
|
|
@ -90,7 +90,7 @@ class LogEntryRepository extends EntityRepository
|
||||||
->where('log INSTANCE OF ' . ElementEditedLogEntry::class)
|
->where('log INSTANCE OF ' . ElementEditedLogEntry::class)
|
||||||
->andWhere('log.target_type = :target_type')
|
->andWhere('log.target_type = :target_type')
|
||||||
->andWhere('log.target_id = :target_id')
|
->andWhere('log.target_id = :target_id')
|
||||||
->andWhere('log.timestamp > :until')
|
->andWhere('log.timestamp >= :until')
|
||||||
->orderBy('log.timestamp', 'DESC');
|
->orderBy('log.timestamp', 'DESC');
|
||||||
|
|
||||||
$qb->setParameters([
|
$qb->setParameters([
|
||||||
|
|
|
@ -151,7 +151,8 @@ class EntityExporter
|
||||||
// Create the disposition of the file
|
// Create the disposition of the file
|
||||||
$disposition = $response->headers->makeDisposition(
|
$disposition = $response->headers->makeDisposition(
|
||||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||||
$filename
|
$filename,
|
||||||
|
$string = preg_replace('![^'.preg_quote('-').'a-z0-_9\s]+!', '', strtolower($filename))
|
||||||
);
|
);
|
||||||
// Set the content disposition
|
// Set the content disposition
|
||||||
$response->headers->set('Content-Disposition', $disposition);
|
$response->headers->set('Content-Disposition', $disposition);
|
||||||
|
|
72
src/Services/LogSystem/EventCommentHelper.php
Normal file
72
src/Services/LogSystem/EventCommentHelper.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?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\Services\LogSystem;
|
||||||
|
|
||||||
|
|
||||||
|
class EventCommentHelper
|
||||||
|
{
|
||||||
|
protected const MAX_MESSAGE_LENGTH = 255;
|
||||||
|
|
||||||
|
protected $message;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$message = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the message that will be saved for all ElementEdited/Created/Deleted messages during the next flush.
|
||||||
|
* Set to null if no message should be shown.
|
||||||
|
* After the flush this message is cleared.
|
||||||
|
* @param string|null $message
|
||||||
|
*/
|
||||||
|
public function setMessage(?string $message): void
|
||||||
|
{
|
||||||
|
//Restrict the length of the string
|
||||||
|
$this->message = mb_strimwidth($message, 0, self::MAX_MESSAGE_LENGTH, '...');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently set message, or null if no message is set yet.
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getMessage(): ?string
|
||||||
|
{
|
||||||
|
return $this->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the currently set message.
|
||||||
|
*/
|
||||||
|
public function clearMessage(): void
|
||||||
|
{
|
||||||
|
$this->message = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a message is currently set.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isMessageSet(): bool
|
||||||
|
{
|
||||||
|
return is_string($this->message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -116,24 +116,38 @@ class LogEntryExtraFormatter
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($context instanceof ElementCreatedLogEntry && $context->hasCreationInstockValue()) {
|
if ($context instanceof ElementCreatedLogEntry ) {
|
||||||
return sprintf(
|
$comment = '';
|
||||||
|
if ($context->hasComment()) {
|
||||||
|
$comment = htmlspecialchars($context->getComment()) . '; ';
|
||||||
|
}
|
||||||
|
if($context->hasCreationInstockValue()) {
|
||||||
|
return $comment . sprintf(
|
||||||
'<i>%s</i>: %s',
|
'<i>%s</i>: %s',
|
||||||
$this->translator->trans('log.element_created.original_instock'),
|
$this->translator->trans('log.element_created.original_instock'),
|
||||||
$context->getCreationInstockValue()
|
$context->getCreationInstockValue()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
|
||||||
if ($context instanceof ElementDeletedLogEntry) {
|
if ($context instanceof ElementDeletedLogEntry) {
|
||||||
return sprintf(
|
$comment = '';
|
||||||
|
if ($context->hasComment()) {
|
||||||
|
$comment = htmlspecialchars($context->getComment()) . '; ';
|
||||||
|
}
|
||||||
|
return $comment . sprintf(
|
||||||
'<i>%s</i>: %s',
|
'<i>%s</i>: %s',
|
||||||
$this->translator->trans('log.element_deleted.old_name'),
|
$this->translator->trans('log.element_deleted.old_name'),
|
||||||
$context->getOldName() ?? $this->translator->trans('log.element_deleted.old_name.unknown')
|
$context->getOldName() ?? $this->translator->trans('log.element_deleted.old_name.unknown')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($context instanceof ElementEditedLogEntry && ! empty($context->getMessage())) {
|
if ($context instanceof ElementEditedLogEntry) {
|
||||||
return htmlspecialchars($context->getMessage());
|
if ($context->hasComment()) {
|
||||||
|
return htmlspecialchars($context->getComment());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($context instanceof InstockChangedLogEntry) {
|
if ($context instanceof InstockChangedLogEntry) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
{% extends "main_card.html.twig" %}
|
{% extends "main_card.html.twig" %}
|
||||||
|
|
||||||
|
{% form_theme form.log_comment 'bootstrap_4_layout.html.twig' %}
|
||||||
|
|
||||||
{% block card_content %}
|
{% block card_content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
|
@ -96,7 +98,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ form_row(form.save) }}
|
<div class="form-group row">
|
||||||
|
<div class="col-sm-9 offset-sm-3">
|
||||||
|
<div class="btn-group">
|
||||||
|
{{ form_widget(form.save) }}
|
||||||
|
<button type="button" class="btn {% if entity.id is not null %}btn-primary{% else %}btn-success{% endif %} dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu p-2">
|
||||||
|
{{ form_row(form.log_comment)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{ form_row(form.reset) }}
|
{{ form_row(form.reset) }}
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,17 @@
|
||||||
<div class=""></div>
|
<div class=""></div>
|
||||||
<div class="col-sm offset-sm-3 pl-2">
|
<div class="col-sm offset-sm-3 pl-2">
|
||||||
{% set delete_disabled = (not is_granted("delete", entity)) or (entity.group is defined and entity.id == 1) %}
|
{% set delete_disabled = (not is_granted("delete", entity)) or (entity.group is defined and entity.id == 1) %}
|
||||||
|
<div class="btn-group">
|
||||||
<button class="btn btn-danger" {% if delete_disabled %}disabled{% endif %}>{% trans %}entity.delete{% endtrans %}</button>
|
<button class="btn btn-danger" {% if delete_disabled %}disabled{% endif %}>{% trans %}entity.delete{% endtrans %}</button>
|
||||||
|
<button type="button" class="btn btn-danger dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu p-2">
|
||||||
|
<div class="form-group"><label for="delete_log_comment">{% trans %}edit.log_comment{% endtrans %}</label>
|
||||||
|
<input type="text" id="delete_log_comment" name="log_comment" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% if entity.parent is defined %}
|
{% if entity.parent is defined %}
|
||||||
<div class="ml-2 custom-control custom-checkbox custom-control-inline">
|
<div class="ml-2 custom-control custom-checkbox custom-control-inline">
|
||||||
<input type="checkbox" class="custom-control-input" id="recursive" name="delete_recursive">
|
<input type="checkbox" class="custom-control-input" id="recursive" name="delete_recursive">
|
||||||
|
|
|
@ -84,11 +84,23 @@
|
||||||
<div class="tab-pane fade p-2" id="comment" role="tabpanel">
|
<div class="tab-pane fade p-2" id="comment" role="tabpanel">
|
||||||
{{ form_widget(form.comment)}}
|
{{ form_widget(form.comment)}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-sm-9 offset-sm-3">
|
||||||
|
<div class="btn-group">
|
||||||
|
{{ form_widget(form.save) }}
|
||||||
|
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu p-2">
|
||||||
|
{{ form_row(form.log_comment)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{ form_row(form.save) }}
|
</div>
|
||||||
|
|
||||||
{{ form_row(form.reset) }}
|
{{ form_row(form.reset) }}
|
||||||
{{ form_errors(form) }}
|
{{ form_errors(form) }}
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
|
|
@ -31,9 +31,19 @@
|
||||||
<input type="hidden" name="_method" value="DELETE">
|
<input type="hidden" name="_method" value="DELETE">
|
||||||
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ part.id) }}">
|
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ part.id) }}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<div class="btn-group">
|
||||||
<button class="btn btn-danger" {% if not is_granted("delete", part) %}disabled{% endif %}>
|
<button class="btn btn-danger" {% if not is_granted("delete", part) %}disabled{% endif %}>
|
||||||
<i class="fa fa-trash fa-fw"></i>
|
<i class="fa fa-trash fa-fw"></i>
|
||||||
{% trans %}part.delete{% endtrans %}
|
{% trans %}part.delete{% endtrans %}
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="btn btn-danger dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu p-2">
|
||||||
|
<div class="form-group"><label for="delete_log_comment">{% trans %}edit.log_comment{% endtrans %}</label>
|
||||||
|
<input type="text" id="delete_log_comment" name="log_comment" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
71
tests/Services/LogSystem/EventCommentHelperTest.php
Normal file
71
tests/Services/LogSystem/EventCommentHelperTest.php
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
<?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\Tests\Services\LogSystem;
|
||||||
|
|
||||||
|
use App\Services\LogSystem\EventCommentHelper;
|
||||||
|
use App\Services\LogSystem\EventLogger;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
class EventCommentHelperTest extends WebTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var EventCommentHelper
|
||||||
|
*/
|
||||||
|
protected $service;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp(); // TODO: Change the autogenerated stub
|
||||||
|
|
||||||
|
//Get an service instance.
|
||||||
|
self::bootKernel();
|
||||||
|
$this->service = self::$container->get(EventCommentHelper::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInitialState()
|
||||||
|
{
|
||||||
|
$this->assertNull($this->service->getMessage());
|
||||||
|
$this->assertFalse($this->service->isMessageSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testClearMessage()
|
||||||
|
{
|
||||||
|
$this->service->setMessage('Test');
|
||||||
|
$this->assertTrue($this->service->isMessageSet());
|
||||||
|
$this->service->clearMessage();
|
||||||
|
$this->assertFalse($this->service->isMessageSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetSetMessage()
|
||||||
|
{
|
||||||
|
$this->service->setMessage('Test');
|
||||||
|
$this->assertSame('Test', $this->service->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsMessageSet()
|
||||||
|
{
|
||||||
|
$this->service->setMessage('Test');
|
||||||
|
$this->assertTrue($this->service->isMessageSet());
|
||||||
|
$this->service->clearMessage();
|
||||||
|
$this->assertFalse($this->service->isMessageSet());
|
||||||
|
}
|
||||||
|
}
|
|
@ -6376,7 +6376,7 @@ Element 3</target>
|
||||||
<unit id="tagdXMa" name="part.info.timetravel_hint">
|
<unit id="tagdXMa" name="part.info.timetravel_hint">
|
||||||
<segment>
|
<segment>
|
||||||
<source>part.info.timetravel_hint</source>
|
<source>part.info.timetravel_hint</source>
|
||||||
<target><![CDATA[This is how the part appeared on %timestamp%. <i>Please note that this feature is experimental, so the infos are maybe not correct.</i>]]></target>
|
<target><![CDATA[This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the infos are maybe not correct.</i>]]></target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue