From 025cdf246ae1bb0c7730a9850abe7ff461e91a8a Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 25 Jul 2023 14:25:19 +0300 Subject: [PATCH] ActionHistory interface --- application/Espo/Binding.php | 5 ++ .../Espo/Core/Action/Actions/Merge/Merger.php | 6 +- .../Core/MassAction/Actions/MassDelete.php | 3 +- .../Espo/Core/Record/ActionHistory/Action.php | 38 +++++++++++ .../Record/ActionHistory/ActionLogger.php | 45 +++++++++++++ .../ActionHistory/DefaultActionLogger.php | 64 +++++++++++++++++++ application/Espo/Core/Record/Service.php | 35 +++++----- .../Espo/Entities/ActionHistoryRecord.php | 11 ++-- .../Espo/Tools/ActionHistory/Service.php | 24 ++----- application/Espo/Tools/Import/Service.php | 12 ++-- .../Espo/Tools/MassUpdate/Processor.php | 3 +- 11 files changed, 195 insertions(+), 51 deletions(-) create mode 100644 application/Espo/Core/Record/ActionHistory/Action.php create mode 100644 application/Espo/Core/Record/ActionHistory/ActionLogger.php create mode 100644 application/Espo/Core/Record/ActionHistory/DefaultActionLogger.php diff --git a/application/Espo/Binding.php b/application/Espo/Binding.php index 7f68110e61..7e1fbdcbb8 100644 --- a/application/Espo/Binding.php +++ b/application/Espo/Binding.php @@ -292,6 +292,11 @@ class Binding implements BindingProcessor 'Espo\\Tools\\Api\\Cors\\Helper', 'Espo\\Tools\\Api\\Cors\\DefaultHelper' ); + + $binder->bindImplementation( + 'Espo\\Core\\Record\\ActionHistory\\ActionLogger', + 'Espo\\Core\\Record\\ActionHistory\\DefaultActionLogger' + ); } private function bindAcl(Binder $binder): void diff --git a/application/Espo/Core/Action/Actions/Merge/Merger.php b/application/Espo/Core/Action/Actions/Merge/Merger.php index 560e704dcb..91e34f3981 100644 --- a/application/Espo/Core/Action/Actions/Merge/Merger.php +++ b/application/Espo/Core/Action/Actions/Merge/Merger.php @@ -35,10 +35,10 @@ use Espo\Core\Action\Params; use Espo\Core\Exceptions\Forbidden; use Espo\Core\Exceptions\NotFound; use Espo\Core\ORM\EntityManager; +use Espo\Core\Record\ActionHistory\Action; use Espo\Core\Record\ServiceContainer; use Espo\Core\Utils\Metadata; use Espo\Core\Utils\ObjectUtil; -use Espo\Entities\ActionHistoryRecord; use Espo\ORM\Entity; use Espo\Entities\EmailAddress; use Espo\Entities\PhoneNumber; @@ -137,7 +137,7 @@ class Merger foreach ($sourceEntityList as $sourceEntity) { $this->entityManager->removeEntity($sourceEntity); - $service->processActionHistoryRecord(ActionHistoryRecord::ACTION_DELETE, $sourceEntity); + $service->processActionHistoryRecord(Action::DELETE, $sourceEntity); } if ($hasPhoneNumber) { @@ -152,7 +152,7 @@ class Merger $this->entityManager->saveEntity($entity); - $service->processActionHistoryRecord(ActionHistoryRecord::ACTION_UPDATE, $entity); + $service->processActionHistoryRecord(Action::UPDATE, $entity); } /** diff --git a/application/Espo/Core/MassAction/Actions/MassDelete.php b/application/Espo/Core/MassAction/Actions/MassDelete.php index 2113cfe7f4..db1148640d 100644 --- a/application/Espo/Core/MassAction/Actions/MassDelete.php +++ b/application/Espo/Core/MassAction/Actions/MassDelete.php @@ -29,6 +29,7 @@ namespace Espo\Core\MassAction\Actions; +use Espo\Core\Record\ActionHistory\Action; use Espo\Entities\ActionHistoryRecord; use Espo\Entities\User; use Espo\Core\Acl; @@ -97,7 +98,7 @@ class MassDelete implements MassAction $count++; - $service->processActionHistoryRecord(ActionHistoryRecord::ACTION_DELETE, $entity); + $service->processActionHistoryRecord(Action::DELETE, $entity); } $result = [ diff --git a/application/Espo/Core/Record/ActionHistory/Action.php b/application/Espo/Core/Record/ActionHistory/Action.php new file mode 100644 index 0000000000..febe308075 --- /dev/null +++ b/application/Espo/Core/Record/ActionHistory/Action.php @@ -0,0 +1,38 @@ +entityManager + ->getRepositoryByClass(ActionHistoryRecord::class) + ->getNew(); + + $historyRecord + ->setAction($action) + ->setUserId($this->user->getId()) + ->setAuthTokenId($this->user->get('authTokenId')) + ->setAuthLogRecordId($this->user->get('authLogRecordId')) + ->setIpAddress($this->user->get('ipAddress')) + ->setTarget(LinkParent::createFromEntity($entity)); + + $this->entityManager->saveEntity($historyRecord); + } +} diff --git a/application/Espo/Core/Record/Service.php b/application/Espo/Core/Record/Service.php index 0447269e00..d329b1b2f4 100644 --- a/application/Espo/Core/Record/Service.php +++ b/application/Espo/Core/Record/Service.php @@ -40,9 +40,10 @@ use Espo\Core\Exceptions\Forbidden; use Espo\Core\Exceptions\ForbiddenSilent; use Espo\Core\Exceptions\NotFound; use Espo\Core\Exceptions\NotFoundSilent; -use Espo\Core\Field\LinkParent; use Espo\Core\ORM\Entity as CoreEntity; use Espo\Core\Record\Access\LinkCheck; +use Espo\Core\Record\ActionHistory\Action; +use Espo\Core\Record\ActionHistory\ActionLogger; use Espo\Core\Record\Formula\Processor as FormulaProcessor; use Espo\Core\Utils\Json; use Espo\Core\Acl; @@ -66,8 +67,7 @@ use Espo\ORM\EntityManager; use Espo\ORM\Query\Part\WhereClause; use Espo\Tools\Stream\Service as StreamService; use Espo\Entities\User; -use Espo\Entities\ActionHistoryRecord; -use Hoa\Ustring\Search; + use stdClass; use InvalidArgumentException; use LogicException; @@ -189,6 +189,7 @@ class Service implements Crud, private ?ListLoadProcessor $listLoadProcessor = null; private ?DuplicateFinder $duplicateFinder = null; private ?LinkCheck $linkCheck = null; + private ?ActionLogger $actionLogger = null; protected const MAX_SELECT_TEXT_ATTRIBUTE_LENGTH = 10000; @@ -208,7 +209,7 @@ class Service implements Crud, /** * Add an action-history record. * - * @param ActionHistoryRecord::ACTION_* $action + * @param Action::* $action */ public function processActionHistoryRecord(string $action, Entity $entity): void { @@ -220,18 +221,16 @@ class Service implements Crud, return; } - /** @var ActionHistoryRecord $historyRecord */ - $historyRecord = $this->entityManager->getNewEntity(ActionHistoryRecord::ENTITY_TYPE); + $this->getActionLogger()->log($action, $entity); + } - $historyRecord - ->setAction($action) - ->setUserId($this->user->getId()) - ->setAuthTokenId($this->user->get('authTokenId')) - ->setAuthLogRecordId($this->user->get('authLogRecordId')) - ->setIpAddress($this->user->get('ipAddress')) - ->setTarget(LinkParent::createFromEntity($entity)); + private function getActionLogger(): ActionLogger + { + if (!$this->actionLogger) { + $this->actionLogger = $this->injectableFactory->createResolved(ActionLogger::class); + } - $this->entityManager->saveEntity($historyRecord); + return $this->actionLogger; } /** @@ -259,7 +258,7 @@ class Service implements Crud, } $this->recordHookManager->processBeforeRead($entity, $params); - $this->processActionHistoryRecord(ActionHistoryRecord::ACTION_READ, $entity); + $this->processActionHistoryRecord(Action::READ, $entity); return $entity; } @@ -709,7 +708,7 @@ class Service implements Crud, $this->afterCreateProcessDuplicating($entity, $params); $this->loadAdditionalFields($entity); $this->prepareEntityForOutput($entity); - $this->processActionHistoryRecord(ActionHistoryRecord::ACTION_CREATE, $entity); + $this->processActionHistoryRecord(Action::CREATE, $entity); return $entity; } @@ -777,7 +776,7 @@ class Service implements Crud, $this->afterUpdateEntity($entity, $data); $this->prepareEntityForOutput($entity); - $this->processActionHistoryRecord(ActionHistoryRecord::ACTION_UPDATE, $entity); + $this->processActionHistoryRecord(Action::UPDATE, $entity); return $entity; } @@ -813,7 +812,7 @@ class Service implements Crud, $this->beforeDeleteEntity($entity); $this->getRepository()->remove($entity); $this->afterDeleteEntity($entity); - $this->processActionHistoryRecord(ActionHistoryRecord::ACTION_DELETE, $entity); + $this->processActionHistoryRecord(Action::DELETE, $entity); } /** diff --git a/application/Espo/Entities/ActionHistoryRecord.php b/application/Espo/Entities/ActionHistoryRecord.php index 4210ad40aa..59949cad76 100644 --- a/application/Espo/Entities/ActionHistoryRecord.php +++ b/application/Espo/Entities/ActionHistoryRecord.php @@ -31,18 +31,19 @@ namespace Espo\Entities; use Espo\Core\Field\LinkParent; use Espo\Core\ORM\Entity; +use Espo\Core\Record\ActionHistory\Action; class ActionHistoryRecord extends Entity { public const ENTITY_TYPE = 'ActionHistoryRecord'; - public const ACTION_READ = 'read'; - public const ACTION_UPDATE = 'update'; - public const ACTION_CREATE = 'create'; - public const ACTION_DELETE = 'delete'; + public const ACTION_CREATE = Action::CREATE; + public const ACTION_READ = Action::READ; + public const ACTION_UPDATE = Action::UPDATE; + public const ACTION_DELETE = Action::DELETE; /** - * @param self::ACTION_* $action + * @param Action::* $action */ public function setAction(string $action): self { diff --git a/application/Espo/Tools/ActionHistory/Service.php b/application/Espo/Tools/ActionHistory/Service.php index 821a2e4ab9..1d97585a1a 100644 --- a/application/Espo/Tools/ActionHistory/Service.php +++ b/application/Espo/Tools/ActionHistory/Service.php @@ -29,33 +29,23 @@ namespace Espo\Tools\ActionHistory; +use Espo\Core\Record\ActionHistory\Action; use Espo\Core\Record\Collection as RecordCollection; use Espo\Entities\ActionHistoryRecord; use Espo\Core\FieldProcessing\ListLoadProcessor; use Espo\Core\ORM\EntityManager; use Espo\Core\Utils\Metadata; use Espo\Core\Utils\Util; - use Espo\Entities\User; class Service { - private Metadata $metadata; - private EntityManager $entityManager; - private User $user; - private ListLoadProcessor $listLoadProcessor; - public function __construct( - Metadata $metadata, - EntityManager $entityManager, - User $user, - ListLoadProcessor $listLoadProcessor - ) { - $this->metadata = $metadata; - $this->entityManager = $entityManager; - $this->user = $user; - $this->listLoadProcessor = $listLoadProcessor; - } + private Metadata $metadata, + private EntityManager $entityManager, + private User $user, + private ListLoadProcessor $listLoadProcessor + ) {} /** * @return RecordCollection @@ -78,7 +68,7 @@ class Service ->getRDBRepositoryByClass(ActionHistoryRecord::class) ->where([ 'userId' => $this->user->getId(), - 'action' => ActionHistoryRecord::ACTION_READ, + 'action' => Action::READ, 'targetType' => $targetTypeList, ]) ->order('MAX:createdAt', 'DESC') diff --git a/application/Espo/Tools/Import/Service.php b/application/Espo/Tools/Import/Service.php index 1770b3d38f..dc1d0d98e2 100644 --- a/application/Espo/Tools/Import/Service.php +++ b/application/Espo/Tools/Import/Service.php @@ -29,12 +29,12 @@ namespace Espo\Tools\Import; -use Espo\Entities\ActionHistoryRecord; +use GuzzleHttp\Psr7\Utils as Psr7Utils; + +use Espo\Core\Record\ActionHistory\Action; use Espo\ORM\Entity; use Espo\ORM\Query\DeleteBuilder; use Espo\ORM\Type\RelationType; -use GuzzleHttp\Psr7\Utils as Psr7Utils; - use Espo\Core\ORM\Repository\Option\SaveOption; use Espo\Entities\ImportEntity as ImportEntityEntity; use Espo\Core\Exceptions\Error; @@ -98,12 +98,12 @@ class Service $id = $result->getId(); if ($id) { - $import = $this->entityManager->getEntity(ImportEntity::ENTITY_TYPE, $id); + $import = $this->entityManager->getEntityById(ImportEntity::ENTITY_TYPE, $id); if ($import) { $this->recordServiceContainer ->get(ImportEntity::ENTITY_TYPE) - ->processActionHistoryRecord(ActionHistoryRecord::ACTION_CREATE, $import); + ->processActionHistoryRecord(Action::CREATE, $import); } } @@ -283,7 +283,7 @@ class Service $this->recordServiceContainer ->get(ImportEntity::ENTITY_TYPE) - ->processActionHistoryRecord(ActionHistoryRecord::ACTION_DELETE, $import); + ->processActionHistoryRecord(Action::DELETE, $import); } private function deleteRelations(Entity $entity): void diff --git a/application/Espo/Tools/MassUpdate/Processor.php b/application/Espo/Tools/MassUpdate/Processor.php index f389a44593..7294ab3ca0 100644 --- a/application/Espo/Tools/MassUpdate/Processor.php +++ b/application/Espo/Tools/MassUpdate/Processor.php @@ -40,6 +40,7 @@ use Espo\Core\MassAction\Result; use Espo\Core\Acl; use Espo\Core\Acl\Table; use Espo\Core\Record\Access\LinkCheck; +use Espo\Core\Record\ActionHistory\Action as RecordAction; use Espo\Core\Record\ServiceFactory; use Espo\Core\Record\Service; @@ -198,7 +199,7 @@ class Processor 'modifiedById' => $this->user->getId(), ]); - $service->processActionHistoryRecord(ActionHistoryRecord::ACTION_UPDATE, $entity); + $service->processActionHistoryRecord(RecordAction::UPDATE, $entity); return true; }