diff --git a/src/DataTables/Column/LogEntryExtraColumn.php b/src/DataTables/Column/LogEntryExtraColumn.php new file mode 100644 index 00000000..42cf7d49 --- /dev/null +++ b/src/DataTables/Column/LogEntryExtraColumn.php @@ -0,0 +1,121 @@ +translator = $translator; + } + + /** + * @inheritDoc + */ + public function normalize($value) + { + return $value; + } + + public function render($value, $context) + { + if ($context instanceof UserLoginLogEntry || $context instanceof UserLogoutLogEntry) { + return sprintf( + "%s: %s", + $this->translator->trans('log.user_login.ip'), + htmlspecialchars($context->getIPAddress()) + ); + } + + if ($context instanceof ExceptionLogEntry) { + return sprintf( + '%s %s:%d : %s', + htmlspecialchars($context->getExceptionClass()), + htmlspecialchars($context->getFile()), + $context->getLine(), + htmlspecialchars($context->getMessage()) + ); + } + + if ($context instanceof DatabaseUpdatedLogEntry) { + return sprintf( + '%s %s %s', + $this->translator->trans($context->isSuccessful() ? 'log.database_updated.success' : 'log.database_updated.failure'), + $context->getOldVersion(), + $context->getNewVersion() + ); + } + + if ($context instanceof ElementCreatedLogEntry && $context->hasCreationInstockValue()) { + return sprintf( + '%s: %s', + $this->translator->trans('log.element_created.original_instock'), + $context->getCreationInstockValue() + ); + } + + if ($context instanceof ElementDeletedLogEntry) { + return sprintf( + '%s: %s', + $this->translator->trans('log.element_deleted.old_name'), + $context->getOldName() + ); + } + + if ($context instanceof ElementEditedLogEntry && !empty($context->getMessage())) { + return htmlspecialchars($context->getMessage()); + } + + if ($context instanceof InstockChangedLogEntry) { + return sprintf( + '%s; %s %s (%s); %s: %s', + $this->translator->trans($context->isWithdrawal() ? 'log.instock_changed.withdrawal' : 'log.instock_changed.added'), + $context->getOldInstock(), + $context->getNewInstock(), + (!$context->isWithdrawal() ? '+' : '-') . $context->getDifference(true), + $this->translator->trans('log.instock_changed.comment'), + htmlspecialchars($context->getComment()) + ); + } + + if ($context instanceof UserNotAllowedLogEntry) { + return htmlspecialchars($context->getMessage()); + } + + return ""; + } +} \ No newline at end of file diff --git a/src/DataTables/LogDataTable.php b/src/DataTables/LogDataTable.php index a3ba86e1..d6c0306a 100644 --- a/src/DataTables/LogDataTable.php +++ b/src/DataTables/LogDataTable.php @@ -24,6 +24,7 @@ namespace App\DataTables; use App\DataTables\Column\EntityColumn; use App\DataTables\Column\LocaleDateTimeColumn; +use App\DataTables\Column\LogEntryExtraColumn; use App\DataTables\Column\LogEntryTargetColumn; use App\Entity\Attachments\Attachment; use App\Entity\LogSystem\AbstractLogEntry; @@ -150,6 +151,10 @@ class LogDataTable implements DataTableTypeInterface 'label' => $this->translator->trans('log.target') ]); + $dataTable->add('extra', LogEntryExtraColumn::class, [ + 'label' => $this->translator->trans('log.extra') + ]); + $dataTable->addOrderBy('timestamp', DataTable::SORT_DESCENDING); $dataTable->createAdapter(ORMAdapter::class, [ diff --git a/src/Entity/LogSystem/AbstractLogEntry.php b/src/Entity/LogSystem/AbstractLogEntry.php index 21d8b3ae..fe5474dc 100644 --- a/src/Entity/LogSystem/AbstractLogEntry.php +++ b/src/Entity/LogSystem/AbstractLogEntry.php @@ -56,7 +56,8 @@ use Psr\Log\LogLevel; * 6 = "ElementCreatedLogEntry", * 7 = "ElementEditedLogEntry", * 8 = "ConfigChangedLogEntry", - * 9 = "DatabaseUpdatedLogEntry" + * 9 = "InstockChangedLogEntry", + * 10 = "DatabaseUpdatedLogEntry" * }) */ abstract class AbstractLogEntry extends DBElement @@ -144,6 +145,11 @@ abstract class AbstractLogEntry extends DBElement */ protected $typeString = "unknown"; + /** @var array The extra data in raw (short form) saved in the DB + * @ORM\Column(name="extra", type="json") + */ + protected $extra = []; + /** * Get the user that caused the event associated with this log entry. * @return User @@ -305,6 +311,11 @@ abstract class AbstractLogEntry extends DBElement return $this; } + public function getExtraData(): array + { + return $this->extra; + } + /** * This function converts the internal numeric log level into an PSR3 compatible level string. * @param int $level The numerical log level diff --git a/src/Entity/LogSystem/DatabaseUpdatedLogEntry.php b/src/Entity/LogSystem/DatabaseUpdatedLogEntry.php index f142d666..a51af69c 100644 --- a/src/Entity/LogSystem/DatabaseUpdatedLogEntry.php +++ b/src/Entity/LogSystem/DatabaseUpdatedLogEntry.php @@ -36,4 +36,31 @@ class DatabaseUpdatedLogEntry extends AbstractLogEntry throw new LogEntryObsoleteException(); } + /** + * Checks if the database update was successful. + * @return bool + */ + public function isSuccessful(): bool + { + return $this->extra['s']; + } + + /** + * Gets the database version before update. + * @return int + */ + public function getOldVersion(): int + { + return $this->extra['o']; + } + + /** + * Gets the (target) database version after update. + * @return int + */ + public function getNewVersion(): int + { + return $this->extra['n']; + } + } \ No newline at end of file diff --git a/src/Entity/LogSystem/ElementCreatedLogEntry.php b/src/Entity/LogSystem/ElementCreatedLogEntry.php index c95a9ea4..97d6f6c0 100644 --- a/src/Entity/LogSystem/ElementCreatedLogEntry.php +++ b/src/Entity/LogSystem/ElementCreatedLogEntry.php @@ -31,4 +31,22 @@ use Doctrine\ORM\Mapping as ORM; class ElementCreatedLogEntry extends AbstractLogEntry { protected $typeString = "element_created"; + + /** + * Gets the instock when the part was created + * @return int|null + */ + public function getCreationInstockValue(): ?int + { + return $this->extra['i'] ?? null; + } + + /** + * Checks if a creation instock value was saved with this entry. + * @return bool + */ + public function hasCreationInstockValue(): bool + { + return $this->getCreationInstockValue() !== null; + } } \ No newline at end of file diff --git a/src/Entity/LogSystem/ElementDeletedLogEntry.php b/src/Entity/LogSystem/ElementDeletedLogEntry.php index 2b05e117..5756d2a0 100644 --- a/src/Entity/LogSystem/ElementDeletedLogEntry.php +++ b/src/Entity/LogSystem/ElementDeletedLogEntry.php @@ -30,4 +30,9 @@ use Doctrine\ORM\Mapping as ORM; class ElementDeletedLogEntry extends AbstractLogEntry { protected $typeString = "element_deleted"; + + public function getOldName(): string + { + return $this->extra['n']; + } } \ No newline at end of file diff --git a/src/Entity/LogSystem/ElementEditedLogEntry.php b/src/Entity/LogSystem/ElementEditedLogEntry.php index 36f32954..87855cea 100644 --- a/src/Entity/LogSystem/ElementEditedLogEntry.php +++ b/src/Entity/LogSystem/ElementEditedLogEntry.php @@ -30,4 +30,13 @@ use Doctrine\ORM\Mapping as ORM; class ElementEditedLogEntry extends AbstractLogEntry { protected $typeString = "element_edited"; + + /** + * Returns the message associated with this edit change + * @return string + */ + public function getMessage() : string + { + return $this->extra['m'] ?? ''; + } } \ No newline at end of file diff --git a/src/Entity/LogSystem/ExceptionLogEntry.php b/src/Entity/LogSystem/ExceptionLogEntry.php index 20099ce0..abf1935f 100644 --- a/src/Entity/LogSystem/ExceptionLogEntry.php +++ b/src/Entity/LogSystem/ExceptionLogEntry.php @@ -37,4 +37,41 @@ class ExceptionLogEntry extends AbstractLogEntry { throw new LogEntryObsoleteException(); } + + /** + * The class name of the exception that caused this log entry. + * @return string + */ + public function getExceptionClass(): string + { + return $this->extra['t'] ?? "Unknown Class"; + } + + /** + * Returns the file where the exception happened. + * @return string + */ + public function getFile(): string + { + return $this->extra['f']; + } + + /** + * Returns the line where the exception happened + * @return int + */ + public function getLine(): int + { + return $this->extra['l']; + } + + /** + * Return the message of the exception. + * @return string + */ + public function getMessage(): string + { + return $this->extra['m']; + } + } \ No newline at end of file diff --git a/src/Entity/LogSystem/InstockChangedLogEntry.php b/src/Entity/LogSystem/InstockChangedLogEntry.php index c1111f90..079bb62b 100644 --- a/src/Entity/LogSystem/InstockChangedLogEntry.php +++ b/src/Entity/LogSystem/InstockChangedLogEntry.php @@ -22,6 +22,7 @@ namespace App\Entity\LogSystem; +use App\Entity\Parts\Part; use Doctrine\ORM\Mapping as ORM; /** @@ -31,4 +32,74 @@ use Doctrine\ORM\Mapping as ORM; class InstockChangedLogEntry extends AbstractLogEntry { protected $typeString = "instock_changed"; + + /** + * Get the old instock + * @return int + */ + public function getOldInstock(): int + { + return $this->extra['o']; + } + + /** + * Get the new instock + * @return int + */ + public function getNewInstock(): int + { + return $this->extra['n']; + } + + /** + * Gets the comment associated with the instock change + * @return string + */ + public function getComment(): string + { + return $this->extra['c']; + } + + /** + * Returns the price that has to be payed for the change (in the base currency). + * @param $absolute bool Set this to true, if you want only get the absolute value of the price (without minus) + * @return float + */ + public function getPrice(bool $absolute = false): float + { + if ($absolute) { + return abs($this->extra['p']); + } + return $this->extra['p']; + } + + /** + * Returns the difference value of the change ($new_instock - $old_instock). + * @param $absolute bool Set this to true if you want only the absolute value of the difference. + * @return int Difference is positive if instock has increased, negative if decreased. + */ + public function getDifference(bool $absolute = false): int + { + // Check if one of the instock values is unknown + if ($this->getNewInstock() == -2 || $this->getOldInstock() == -2) { + return 0; + } + + $difference = $this->getNewInstock() - $this->getOldInstock(); + if ($absolute) { + return abs($difference); + } + + return $difference; + } + + /** + * Checks if the Change was an withdrawal of parts. + * @return bool True if the change was an withdrawal, false if not. + */ + public function isWithdrawal(): bool + { + return $this->getNewInstock() < $this->getOldInstock(); + } + } \ No newline at end of file diff --git a/src/Entity/LogSystem/UserLoginLogEntry.php b/src/Entity/LogSystem/UserLoginLogEntry.php index 5c186b92..876260c1 100644 --- a/src/Entity/LogSystem/UserLoginLogEntry.php +++ b/src/Entity/LogSystem/UserLoginLogEntry.php @@ -31,4 +31,24 @@ use Doctrine\ORM\Mapping as ORM; class UserLoginLogEntry extends AbstractLogEntry { protected $typeString = "user_login"; + + /** + * Return the (anonymized) IP address used to login the user. + * @return string + */ + public function getIPAddress(): string + { + return $this->extra['i']; + } + + /** + * Sets the IP address used to login the user + * @param string $ip The IP address used to login the user. + * @return $this + */ + public function setIPAddress(string $ip): self + { + $this->extra['i'] = $ip; + return $this; + } } \ No newline at end of file diff --git a/src/Entity/LogSystem/UserLogoutLogEntry.php b/src/Entity/LogSystem/UserLogoutLogEntry.php index a6857305..5bb463e8 100644 --- a/src/Entity/LogSystem/UserLogoutLogEntry.php +++ b/src/Entity/LogSystem/UserLogoutLogEntry.php @@ -31,4 +31,24 @@ use Doctrine\ORM\Mapping as ORM; class UserLogoutLogEntry extends AbstractLogEntry { protected $typeString = "user_logout"; + + /** + * Return the (anonymized) IP address used to login the user. + * @return string + */ + public function getIPAddress(): string + { + return $this->extra['i']; + } + + /** + * Sets the IP address used to login the user + * @param string $ip The IP address used to login the user. + * @return $this + */ + public function setIPAddress(string $ip): self + { + $this->extra['i'] = $ip; + return $this; + } } \ No newline at end of file diff --git a/src/Entity/LogSystem/UserNotAllowedLogEntry.php b/src/Entity/LogSystem/UserNotAllowedLogEntry.php index b95199d8..71aaf626 100644 --- a/src/Entity/LogSystem/UserNotAllowedLogEntry.php +++ b/src/Entity/LogSystem/UserNotAllowedLogEntry.php @@ -31,11 +31,16 @@ use Doctrine\ORM\Mapping as ORM; */ class UserNotAllowedLogEntry extends AbstractLogEntry { - protected $type = 'user_not_allowed'; + protected $typeString = 'user_not_allowed'; public function __construct() { //Obsolete, use server log now. throw new LogEntryObsoleteException(); } + + public function getMessage(): string + { + return $this->extra['p'] ?? ''; + } } \ No newline at end of file