diff --git a/application/Espo/Classes/RecordHooks/Email/AfterUpdate.php b/application/Espo/Classes/RecordHooks/Email/AfterUpdate.php new file mode 100644 index 0000000000..33b57d2d6f --- /dev/null +++ b/application/Espo/Classes/RecordHooks/Email/AfterUpdate.php @@ -0,0 +1,64 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Classes\RecordHooks\Email; + +use Espo\Core\Exceptions\BadRequest; +use Espo\Core\Exceptions\Error; +use Espo\Core\Mail\Exceptions\NoSmtp; +use Espo\Core\Mail\Exceptions\SendingError; +use Espo\Core\Record\Hook\SaveHook; +use Espo\Entities\Email; +use Espo\Entities\User; +use Espo\ORM\Entity; +use Espo\Tools\Email\SendService; + +/** + * @implements SaveHook + */ +class AfterUpdate implements SaveHook +{ + public function __construct( + private User $user, + private SendService $sendService + ) {} + + /** + * @throws BadRequest + * @throws Error + * @throws NoSmtp + * @throws SendingError + */ + public function process(Entity $entity): void + { + if ($entity->getStatus() === Email::STATUS_SENDING) { + $this->sendService->send($entity, $this->user); + } + } +} diff --git a/application/Espo/Classes/RecordHooks/Email/BeforeCreate.php b/application/Espo/Classes/RecordHooks/Email/BeforeCreate.php new file mode 100644 index 0000000000..b7016864c2 --- /dev/null +++ b/application/Espo/Classes/RecordHooks/Email/BeforeCreate.php @@ -0,0 +1,50 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Classes\RecordHooks\Email; + +use Espo\Core\Mail\Sender; +use Espo\Core\Record\Hook\SaveHook; +use Espo\Entities\Email; +use Espo\ORM\Entity; + +/** + * @implements SaveHook + */ +class BeforeCreate implements SaveHook +{ + public function process(Entity $entity): void + { + if ($entity->getStatus() === Email::STATUS_SENDING) { + $messageId = Sender::generateMessageId($entity); + + $entity->setMessageId('<' . $messageId . '>'); + } + } +} diff --git a/application/Espo/Classes/RecordHooks/Email/BeforeUpdate.php b/application/Espo/Classes/RecordHooks/Email/BeforeUpdate.php new file mode 100644 index 0000000000..e7627a6373 --- /dev/null +++ b/application/Espo/Classes/RecordHooks/Email/BeforeUpdate.php @@ -0,0 +1,151 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Classes\RecordHooks\Email; + +use Espo\Core\Mail\Sender; +use Espo\Core\Record\Hook\SaveHook; +use Espo\Core\Utils\FieldUtil; +use Espo\Core\Utils\SystemUser; +use Espo\Entities\Email; +use Espo\Entities\User; +use Espo\ORM\Entity; +use Espo\ORM\EntityManager; + +/** + * @implements SaveHook + */ +class BeforeUpdate implements SaveHook +{ + /** @var string[] */ + private $allowedForUpdateFieldList = [ + 'parent', + 'teams', + 'assignedUser', + ]; + + public function __construct( + private User $user, + private EntityManager $entityManager, + private FieldUtil $fieldUtil + ) {} + + public function process(Entity $entity): void + { + $skipFilter = false; + + if ($this->user->isAdmin()) { + $skipFilter = true; + } + + if ($this->isEmailManuallyArchived($entity)) { + $skipFilter = true; + } + else if ($entity->isAttributeChanged('dateSent')) { + $entity->set('dateSent', $entity->getFetched('dateSent')); + } + + if ($entity->getStatus() === Email::STATUS_DRAFT) { + $skipFilter = true; + } + + if ( + $entity->getStatus() === Email::STATUS_SENDING && + $entity->getFetched('status') === Email::STATUS_DRAFT + ) { + $skipFilter = true; + } + + if ( + $entity->isAttributeChanged('status') && + $entity->getFetched('status') === Email::STATUS_ARCHIVED + ) { + $entity->setStatus(Email::STATUS_ARCHIVED); + } + + if (!$skipFilter) { + $this->clearEntityForUpdate($entity); + } + + if ($entity->getStatus() == Email::STATUS_SENDING) { + $messageId = Sender::generateMessageId($entity); + + $entity->setMessageId('<' . $messageId . '>'); + } + } + + private function isEmailManuallyArchived(Email $email): bool + { + if ($email->getStatus() !== Email::STATUS_ARCHIVED) { + return false; + } + + $userId = $email->getCreatedBy()?->getId(); + + if (!$userId) { + return false; + } + + $user = $this->entityManager + ->getRDBRepositoryByClass(User::class) + ->getById($userId); + + if (!$user) { + return true; + } + + return $user->getUserName() !== SystemUser::NAME; + } + + private function clearEntityForUpdate(Email $email): void + { + $fieldDefsList = $this->entityManager + ->getDefs() + ->getEntity(Email::ENTITY_TYPE) + ->getFieldList(); + + foreach ($fieldDefsList as $fieldDefs) { + $field = $fieldDefs->getName(); + + if ($fieldDefs->getParam('isCustom')) { + continue; + } + + if (in_array($field, $this->allowedForUpdateFieldList)) { + continue; + } + + $attributeList = $this->fieldUtil->getAttributeList(Email::ENTITY_TYPE, $field); + + foreach ($attributeList as $attribute) { + $email->clear($attribute); + } + } + } +} diff --git a/application/Espo/Core/Mail/Sender.php b/application/Espo/Core/Mail/Sender.php index f7faab9260..e4b1cc1bb2 100644 --- a/application/Espo/Core/Mail/Sender.php +++ b/application/Espo/Core/Mail/Sender.php @@ -579,7 +579,7 @@ class Sender ) { $messageId = $this->generateMessageId($email); - $email->set('messageId', '<' . $messageId . '>'); + $email->setMessageId('<' . $messageId . '>'); if ($email->hasId()) { $this->entityManager->saveEntity($email, [SaveOption::SILENT => true]); diff --git a/application/Espo/Resources/metadata/recordDefs/Email.json b/application/Espo/Resources/metadata/recordDefs/Email.json index 8a7e6da071..1b8d9fe633 100644 --- a/application/Espo/Resources/metadata/recordDefs/Email.json +++ b/application/Espo/Resources/metadata/recordDefs/Email.json @@ -1,4 +1,5 @@ { + "loadAdditionalFieldsAfterUpdate": true, "readLoaderClassNameList": [ "Espo\\Classes\\FieldProcessing\\Email\\AddressDataLoader", "Espo\\Classes\\FieldProcessing\\Email\\UserColumnsLoader", @@ -14,5 +15,14 @@ "moveToFolder": { "implementationClassName": "Espo\\Classes\\MassAction\\Email\\MoveToFolder" } - } + }, + "beforeCreateHookClassNameList": [ + "Espo\\Classes\\RecordHooks\\Email\\BeforeCreate" + ], + "beforeUpdateHookClassNameList": [ + "Espo\\Classes\\RecordHooks\\Email\\BeforeUpdate" + ], + "afterUpdateHookClassNameList": [ + "Espo\\Classes\\RecordHooks\\Email\\AfterUpdate" + ] } diff --git a/application/Espo/Services/Email.php b/application/Espo/Services/Email.php index 992063b9ae..a87cacd2e4 100644 --- a/application/Espo/Services/Email.php +++ b/application/Espo/Services/Email.php @@ -29,7 +29,6 @@ namespace Espo\Services; -use Espo\Core\Utils\SystemUser; use Espo\Tools\Email\SendService; use Espo\ORM\Entity; use Espo\Entities\User; @@ -40,7 +39,6 @@ use Espo\Core\Exceptions\Conflict; use Espo\Core\Exceptions\Forbidden; use Espo\Core\Exceptions\BadRequest; use Espo\Core\Mail\Exceptions\SendingError; -use Espo\Core\Mail\Sender; use Espo\Core\Mail\SmtpParams; use Espo\Core\Record\CreateParams; @@ -52,16 +50,8 @@ use stdClass; */ class Email extends Record { - protected $getEntityBeforeUpdate = true; - /** @var string[] */ - protected $allowedForUpdateFieldList = [ - 'parent', - 'teams', - 'assignedUser', - ]; - protected $mandatorySelectAttributeList = [ 'name', 'createdById', @@ -134,39 +124,6 @@ class Email extends Record return $entity; } - protected function beforeCreateEntity(Entity $entity, $data) - { - /** @var EmailEntity $entity */ - - if ($entity->getStatus() === EmailEntity::STATUS_SENDING) { - $messageId = Sender::generateMessageId($entity); - - $entity->set('messageId', '<' . $messageId . '>'); - } - } - - /** - * @throws BadRequest - * @throws Error - * @throws SendingError - */ - protected function afterUpdateEntity(Entity $entity, $data) - { - /** @var EmailEntity $entity */ - - if ($entity->getStatus() === EmailEntity::STATUS_SENDING) { - $this->getSendService()->send($entity, $this->user); - } - - $this->loadAdditionalFields($entity); - - if (!isset($data->from) && !isset($data->to) && !isset($data->cc)) { - $entity->clear('nameHash'); - $entity->clear('idHash'); - $entity->clear('typeHash'); - } - } - public function getEntity(string $id): ?Entity { /** @var ?EmailEntity $entity */ @@ -201,100 +158,4 @@ class Email extends Record { return Util::parseFromAddress($string); } - - protected function beforeUpdateEntity(Entity $entity, $data) - { - /** @var EmailEntity $entity */ - - $skipFilter = false; - - if ($this->user->isAdmin()) { - $skipFilter = true; - } - - if ($this->isEmailManuallyArchived($entity)) { - $skipFilter = true; - } - else if ($entity->isAttributeChanged('dateSent')) { - $entity->set('dateSent', $entity->getFetched('dateSent')); - } - - if ($entity->getStatus() === EmailEntity::STATUS_DRAFT) { - $skipFilter = true; - } - - if ( - $entity->getStatus() === EmailEntity::STATUS_SENDING && - $entity->getFetched('status') === EmailEntity::STATUS_DRAFT - ) { - $skipFilter = true; - } - - if ( - $entity->isAttributeChanged('status') && - $entity->getFetched('status') === EmailEntity::STATUS_ARCHIVED - ) { - $entity->set('status', EmailEntity::STATUS_ARCHIVED); - } - - if (!$skipFilter) { - $this->clearEntityForUpdate($entity); - } - - if ($entity->getStatus() == EmailEntity::STATUS_SENDING) { - $messageId = Sender::generateMessageId($entity); - - $entity->set('messageId', '<' . $messageId . '>'); - } - } - - private function isEmailManuallyArchived(EmailEntity $email): bool - { - if ($email->getStatus() !== EmailEntity::STATUS_ARCHIVED) { - return false; - } - - $userId = $email->getCreatedBy()?->getId(); - - if (!$userId) { - return false; - } - - /** @var ?User $user */ - $user = $this->entityManager - ->getRDBRepositoryByClass(User::class) - ->getById($userId); - - if (!$user) { - return true; - } - - return $user->getUserName() !== SystemUser::NAME; - } - - private function clearEntityForUpdate(EmailEntity $email): void - { - $fieldDefsList = $this->entityManager - ->getDefs() - ->getEntity(EmailEntity::ENTITY_TYPE) - ->getFieldList(); - - foreach ($fieldDefsList as $fieldDefs) { - $field = $fieldDefs->getName(); - - if ($fieldDefs->getParam('isCustom')) { - continue; - } - - if (in_array($field, $this->allowedForUpdateFieldList)) { - continue; - } - - $attributeList = $this->fieldUtil->getAttributeList(EmailEntity::ENTITY_TYPE, $field); - - foreach ($attributeList as $attribute) { - $email->clear($attribute); - } - } - } }