Use enum for undo mode

This commit is contained in:
Jan Böhmer 2023-06-18 21:26:28 +02:00
parent 218b0adb8f
commit 8a20584e27
14 changed files with 140 additions and 180 deletions

View file

@ -34,6 +34,7 @@ use App\Entity\LogSystem\ElementEditedLogEntry;
use App\Form\Filters\LogFilterType;
use App\Repository\DBElementRepository;
use App\Services\LogSystem\EventUndoHelper;
use App\Services\LogSystem\EventUndoMode;
use App\Services\LogSystem\LogEntryExtraFormatter;
use App\Services\LogSystem\LogLevelHelper;
use App\Services\LogSystem\LogTargetHelper;
@ -128,13 +129,17 @@ class LogController extends AbstractController
#[Route(path: '/undo', name: 'log_undo', methods: ['POST'])]
public function undoRevertLog(Request $request, EventUndoHelper $eventUndoHelper): RedirectResponse
{
$mode = EventUndoHelper::MODE_UNDO;
$id = $request->request->get('undo');
$mode = EventUndoMode::UNDO;
$id = $request->request->getInt('undo');
//If no undo value was set check if a revert was set
if (null === $id) {
$id = $request->get('revert');
$mode = EventUndoHelper::MODE_REVERT;
if (0 === $id) {
$id = $request->request->getInt('revert');
$mode = EventUndoMode::REVERT;
}
if (0 === $id) {
throw new InvalidArgumentException('No log entry ID was given!');
}
$log_element = $this->entityManager->find(AbstractLogEntry::class, $id);
@ -147,9 +152,9 @@ class LogController extends AbstractController
$eventUndoHelper->setMode($mode);
$eventUndoHelper->setUndoneEvent($log_element);
if (EventUndoHelper::MODE_UNDO === $mode) {
if (EventUndoMode::UNDO === $mode) {
$this->undoLog($log_element);
} elseif (EventUndoHelper::MODE_REVERT === $mode) {
} elseif (EventUndoMode::REVERT === $mode) {
$this->revertLog($log_element);
}

View file

@ -67,8 +67,6 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement
{
use ParametersTrait;
final public const ID_ROOT_ELEMENT = 0;
/**
* This is a not standard character, so build a const, so a dev can easily use it.
*/

View file

@ -42,6 +42,7 @@ declare(strict_types=1);
namespace App\Entity\Contracts;
use App\Entity\LogSystem\AbstractLogEntry;
use App\Services\LogSystem\EventUndoMode;
interface LogWithEventUndoInterface
{
@ -60,12 +61,12 @@ interface LogWithEventUndoInterface
*
* @return $this
*/
public function setUndoneEvent(AbstractLogEntry $event, string $mode = 'undo'): self;
public function setUndoneEvent(AbstractLogEntry $event, EventUndoMode $mode = EventUndoMode::UNDO): self;
/**
* Returns the mode how the event was undone:
* "undo" = Only a single event was applied to element
* "revert" = Element was reverted to the state it was to the timestamp of the log.
*/
public function getUndoMode(): string;
public function getUndoMode(): EventUndoMode;
}

View file

@ -87,10 +87,10 @@ use InvalidArgumentException;
#[ORM\Entity]
class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventUndoInterface
{
use LogWithEventUndoTrait;
protected string $typeString = 'collection_element_deleted';
public function __construct(AbstractDBElement $changed_element, string $collection_name, AbstractDBElement $deletedElement)
{
parent::__construct();
@ -218,39 +218,4 @@ class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventU
{
return $this->extra['i'];
}
public function isUndoEvent(): bool
{
return isset($this->extra['u']);
}
public function getUndoEventID(): ?int
{
return $this->extra['u'] ?? null;
}
public function setUndoneEvent(AbstractLogEntry $event, string $mode = 'undo'): LogWithEventUndoInterface
{
$this->extra['u'] = $event->getID();
if ('undo' === $mode) {
$this->extra['um'] = 1;
} elseif ('revert' === $mode) {
$this->extra['um'] = 2;
} else {
throw new InvalidArgumentException('Passed invalid $mode!');
}
return $this;
}
public function getUndoMode(): string
{
$mode_int = $this->extra['um'] ?? 1;
if (1 === $mode_int) {
return 'undo';
}
return 'revert';
}
}

View file

@ -27,12 +27,15 @@ use App\Entity\Contracts\LogWithCommentInterface;
use App\Entity\Contracts\LogWithEventUndoInterface;
use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Services\LogSystem\EventUndoMode;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
#[ORM\Entity]
class ElementCreatedLogEntry extends AbstractLogEntry implements LogWithCommentInterface, LogWithEventUndoInterface
{
use LogWithEventUndoTrait;
protected string $typeString = 'element_created';
public function __construct(AbstractDBElement $new_element)
@ -79,39 +82,4 @@ class ElementCreatedLogEntry extends AbstractLogEntry implements LogWithCommentI
return $this;
}
public function isUndoEvent(): bool
{
return isset($this->extra['u']);
}
public function getUndoEventID(): ?int
{
return $this->extra['u'] ?? null;
}
public function setUndoneEvent(AbstractLogEntry $event, string $mode = 'undo'): LogWithEventUndoInterface
{
$this->extra['u'] = $event->getID();
if ('undo' === $mode) {
$this->extra['um'] = 1;
} elseif ('revert' === $mode) {
$this->extra['um'] = 2;
} else {
throw new InvalidArgumentException('Passed invalid $mode!');
}
return $this;
}
public function getUndoMode(): string
{
$mode_int = $this->extra['um'] ?? 1;
if (1 === $mode_int) {
return 'undo';
}
return 'revert';
}
}

View file

@ -29,6 +29,7 @@ use App\Entity\Contracts\NamedElementInterface;
use App\Entity\Contracts\TimeTravelInterface;
use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Services\LogSystem\EventUndoMode;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
@ -37,6 +38,8 @@ class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInter
{
protected string $typeString = 'element_deleted';
use LogWithEventUndoTrait;
public function __construct(AbstractDBElement $deleted_element)
{
parent::__construct();
@ -112,39 +115,4 @@ class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInter
return $this;
}
public function isUndoEvent(): bool
{
return isset($this->extra['u']);
}
public function getUndoEventID(): ?int
{
return $this->extra['u'] ?? null;
}
public function setUndoneEvent(AbstractLogEntry $event, string $mode = 'undo'): LogWithEventUndoInterface
{
$this->extra['u'] = $event->getID();
if ('undo' === $mode) {
$this->extra['um'] = 1;
} elseif ('revert' === $mode) {
$this->extra['um'] = 2;
} else {
throw new InvalidArgumentException('Passed invalid $mode!');
}
return $this;
}
public function getUndoMode(): string
{
$mode_int = $this->extra['um'] ?? 1;
if (1 === $mode_int) {
return 'undo';
}
return 'revert';
}
}

View file

@ -33,6 +33,8 @@ use InvalidArgumentException;
#[ORM\Entity]
class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface, LogWithEventUndoInterface, LogWithNewDataInterface
{
use LogWithEventUndoTrait;
protected string $typeString = 'element_edited';
public function __construct(AbstractDBElement $changed_element)
@ -139,39 +141,4 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
return $this;
}
public function isUndoEvent(): bool
{
return isset($this->extra['u']);
}
public function getUndoEventID(): ?int
{
return $this->extra['u'] ?? null;
}
public function setUndoneEvent(AbstractLogEntry $event, string $mode = 'undo'): LogWithEventUndoInterface
{
$this->extra['u'] = $event->getID();
if ('undo' === $mode) {
$this->extra['um'] = 1;
} elseif ('revert' === $mode) {
$this->extra['um'] = 2;
} else {
throw new InvalidArgumentException('Passed invalid $mode!');
}
return $this;
}
public function getUndoMode(): string
{
$mode_int = $this->extra['um'] ?? 1;
if (1 === $mode_int) {
return 'undo';
}
return 'revert';
}
}

View file

@ -0,0 +1,51 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 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\LogSystem;
use App\Entity\Contracts\LogWithEventUndoInterface;
use App\Services\LogSystem\EventUndoMode;
trait LogWithEventUndoTrait
{
public function isUndoEvent(): bool
{
return isset($this->extra['u']);
}
public function getUndoEventID(): ?int
{
return $this->extra['u'] ?? null;
}
public function setUndoneEvent(AbstractLogEntry $event, EventUndoMode $mode = EventUndoMode::UNDO): LogWithEventUndoInterface
{
$this->extra['u'] = $event->getID();
$this->extra['um'] = $mode->toExtraInt();
return $this;
}
public function getUndoMode(): EventUndoMode
{
$mode_int = $this->extra['um'] ?? 1;
return EventUndoMode::fromExtraInt($mode_int);
}
}

View file

@ -28,10 +28,6 @@ use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class PartStockChangedLogEntry extends AbstractLogEntry
{
final public const TYPE_ADD = "add";
final public const TYPE_WITHDRAW = "withdraw";
final public const TYPE_MOVE = "move";
protected string $typeString = 'part_stock_changed';
protected const COMMENT_MAX_LENGTH = 300;

View file

@ -46,27 +46,19 @@ use InvalidArgumentException;
class EventUndoHelper
{
final public const MODE_UNDO = 'undo';
final public const MODE_REVERT = 'revert';
protected const ALLOWED_MODES = [self::MODE_REVERT, self::MODE_UNDO];
protected ?AbstractLogEntry $undone_event = null;
protected string $mode = self::MODE_UNDO;
protected EventUndoMode $mode = EventUndoMode::UNDO;
public function __construct()
{
}
public function setMode(string $mode): void
public function setMode(EventUndoMode $mode): void
{
if (!in_array($mode, self::ALLOWED_MODES, true)) {
throw new InvalidArgumentException('Invalid mode passed!');
}
$this->mode = $mode;
}
public function getMode(): string
public function getMode(): EventUndoMode
{
return $this->mode;
}

View file

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 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;
use InvalidArgumentException;
enum EventUndoMode: string
{
case UNDO = 'undo';
case REVERT = 'revert';
public function toExtraInt(): int
{
return match ($this) {
self::UNDO => 1,
self::REVERT => 2,
};
}
public static function fromExtraInt(int $int): self
{
return match ($int) {
1 => self::UNDO,
2 => self::REVERT,
default => throw new InvalidArgumentException('Invalid int ' . (string) $int . ' for EventUndoMode'),
};
}
}

View file

@ -127,9 +127,9 @@ class LogEntryExtraFormatter
}
if (($context instanceof LogWithEventUndoInterface) && $context->isUndoEvent()) {
if ('undo' === $context->getUndoMode()) {
if (EventUndoMode::UNDO === $context->getUndoMode()) {
$array['log.undo_mode.undo'] = '#' . $context->getUndoEventID();
} elseif ('revert' === $context->getUndoMode()) {
} elseif (EventUndoMode::REVERT === $context->getUndoMode()) {
$array['log.undo_mode.revert'] = '#' . $context->getUndoEventID();
}
}

View file

@ -19,8 +19,8 @@
<form method="post" action="{{ path("log_undo") }}"
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
<input type="hidden" name="redirect_back" value="{{ app.request.requestUri }}">
@ -32,15 +32,18 @@
<i class="fas fa-fw fa-backward" title="{% trans %}log.undo.revert{% endtrans %}"></i> {{ 'log.undo.revert.short' | trans }}
</button>
{% set url = timetravel_url(target_element, entry.timestamp) %}
{# View button #}
{% if target_element and ((attribute(entry, 'oldDataInformation') is defined and entry.oldDataInformation)
or entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted'))
and url is not null %}
<a class="btn btn-outline-secondary" href="{{ url }}"><i class="fas fa-fw fa-eye"></i>
{% trans %}log.view_version{% endtrans %}
</a>
%}
{% set url = timetravel_url(target_element, entry.timestamp) %}
{% if url %}
<a class="btn btn-outline-secondary" href="{{ url }}"><i class="fas fa-fw fa-eye"></i>
{% trans %}log.view_version{% endtrans %}
</a>
{% endif %}
{% endif %}
</div>
</form>

View file

@ -26,11 +26,11 @@
<td>
{{ ('log.type.' ~ log_entry.type) | trans }}
{% if log_entry.type == 'part_stock_changed' %}
({{ ('log.part_stock_changed.' ~ log_entry.instockChangeType)|trans }})
({{ ('log.part_stock_changed.' ~ log_entry.instockChangeType.value)|trans }})
{% endif %}
{% if log_entry is instanceof('App\\Entity\\Contracts\\LogWithEventUndoInterface') and log_entry.undoEvent %}
<b>({{ ('log.undo_mode.' ~ log_entry.undoMode)|trans }}: <a href="{{ path('log_details', {"id": log_entry.UndoEventID}) }}">#{{ log_entry.UndoEventID }}</a>)</b>
<b>({{ ('log.undo_mode.' ~ log_entry.undoMode.value)|trans }}: <a href="{{ path('log_details', {"id": log_entry.UndoEventID}) }}">#{{ log_entry.UndoEventID }}</a>)</b>
{% endif %}
</td>
</tr>