From 09b94de32705edb97072d7a514ca3f26f4105619 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 25 Jun 2025 10:42:31 +0300 Subject: [PATCH] ref --- .../Email/StringDataLoader.php | 16 ++++---- .../RecordHooks/Email/CheckFromAddress.php | 13 +++---- .../Email/Where/ItemConverters/InFolder.php | 4 +- .../Espo/Core/Action/Actions/Merge/Merger.php | 5 ++- .../FieldProcessing/EmailAddress/Saver.php | 9 +++-- .../Account/GroupAccount/Hooks/AfterFetch.php | 5 ++- .../Espo/Core/Mail/ConfigDataProvider.php | 5 +++ application/Espo/Core/Name/Link.php | 38 +++++++++++++++++++ application/Espo/Tools/App/AppService.php | 9 ++--- .../Espo/Tools/App/SettingsService.php | 5 ++- application/Espo/Tools/Email/SendService.php | 7 +++- .../Tools/EmailNotification/Processor.php | 3 +- 12 files changed, 84 insertions(+), 35 deletions(-) create mode 100644 application/Espo/Core/Name/Link.php diff --git a/application/Espo/Classes/FieldProcessing/Email/StringDataLoader.php b/application/Espo/Classes/FieldProcessing/Email/StringDataLoader.php index 6cfef34af9..eb04addce1 100644 --- a/application/Espo/Classes/FieldProcessing/Email/StringDataLoader.php +++ b/application/Espo/Classes/FieldProcessing/Email/StringDataLoader.php @@ -30,6 +30,7 @@ namespace Espo\Classes\FieldProcessing\Email; use Espo\Core\Name\Field; +use Espo\Core\Name\Link; use Espo\ORM\Entity; use Espo\ORM\Name\Attribute; use Espo\Repositories\EmailAddress as EmailAddressRepository; @@ -44,17 +45,15 @@ use Espo\Entities\User; */ class StringDataLoader implements Loader { - private EntityManager $entityManager; - private User $user; + private const LINK_EMAIL_ADDRESSES = Link::EMAIL_ADDRESSES; /** @var array */ private $fromEmailAddressNameCache = []; - public function __construct(EntityManager $entityManager, User $user) - { - $this->entityManager = $entityManager; - $this->user = $user; - } + public function __construct( + private EntityManager $entityManager, + private User $user + ) {} public function process(Entity $entity, Params $params): void { @@ -63,8 +62,7 @@ class StringDataLoader implements Loader $userEmailAddressIdList = []; $emailAddressCollection = $this->entityManager - ->getRDBRepository(User::ENTITY_TYPE) - ->getRelation($this->user, 'emailAddresses') + ->getRelation($this->user, self::LINK_EMAIL_ADDRESSES) ->select([Attribute::ID]) ->find(); diff --git a/application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php b/application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php index ff6ca7b53e..bf73c71a5c 100644 --- a/application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php +++ b/application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php @@ -33,8 +33,8 @@ use Espo\Core\Acl; use Espo\Core\Exceptions\BadRequest; use Espo\Core\Exceptions\Forbidden; use Espo\Core\Mail\Account\SendingAccountProvider; +use Espo\Core\Mail\ConfigDataProvider; use Espo\Core\Record\Hook\SaveHook; -use Espo\Core\Utils\Config; use Espo\Entities\Email; use Espo\Entities\User; use Espo\ORM\Entity; @@ -47,8 +47,8 @@ class CheckFromAddress implements SaveHook public function __construct( private User $user, private SendingAccountProvider $sendingAccountProvider, - private Config $config, private Acl $acl, + private ConfigDataProvider $configDataProvider, ) {} public function process(Entity $entity): void @@ -88,12 +88,11 @@ class CheckFromAddress implements SaveHook if ( $system && - $this->config->get('outboundEmailIsShared') && - $system->getEmailAddress() + $this->configDataProvider->isOutboundEmailShared() && + $system->getEmailAddress() && + $fromAddress === strtolower($system->getEmailAddress()) ) { - if ($fromAddress === strtolower($system->getEmailAddress())) { - return; - } + return; } throw new Forbidden("Not allowed 'from' address."); diff --git a/application/Espo/Classes/Select/Email/Where/ItemConverters/InFolder.php b/application/Espo/Classes/Select/Email/Where/ItemConverters/InFolder.php index 4f0e1b8db0..3e1fa1f0fa 100644 --- a/application/Espo/Classes/Select/Email/Where/ItemConverters/InFolder.php +++ b/application/Espo/Classes/Select/Email/Where/ItemConverters/InFolder.php @@ -29,6 +29,7 @@ namespace Espo\Classes\Select\Email\Where\ItemConverters; +use Espo\Core\Name\Link; use Espo\Core\Select\Where\ItemConverter; use Espo\Core\Select\Where\Item; @@ -237,8 +238,7 @@ class InFolder implements ItemConverter protected function getEmailAddressIdList(): array { $emailAddressList = $this->entityManager - ->getRDBRepository(User::ENTITY_TYPE) - ->getRelation($this->user, 'emailAddresses') + ->getRelation($this->user, Link::EMAIL_ADDRESSES) ->select([Attribute::ID]) ->find(); diff --git a/application/Espo/Core/Action/Actions/Merge/Merger.php b/application/Espo/Core/Action/Actions/Merge/Merger.php index f779920cac..b44e09d5e6 100644 --- a/application/Espo/Core/Action/Actions/Merge/Merger.php +++ b/application/Espo/Core/Action/Actions/Merge/Merger.php @@ -35,6 +35,7 @@ use Espo\Core\Action\Params; use Espo\Core\Exceptions\Forbidden; use Espo\Core\Exceptions\NotFound; use Espo\Core\Name\Field; +use Espo\Core\Name\Link; use Espo\Core\ORM\EntityManager; use Espo\Core\ORM\Type\FieldType; use Espo\Core\Record\ActionHistory\Action; @@ -218,7 +219,7 @@ class Merger /** @var iterable $collection */ $collection = $this->entityManager - ->getRelation($entity, 'emailAddresses') + ->getRelation($entity, Link::EMAIL_ADDRESSES) ->find(); foreach ($collection as $entity) { @@ -287,7 +288,7 @@ class Merger $entityDefs = $this->entityManager->getDefs()->getEntity($entityType); $ignoreList = [ - 'emailAddresses', + Link::EMAIL_ADDRESSES, 'phoneNumbers', ]; diff --git a/application/Espo/Core/FieldProcessing/EmailAddress/Saver.php b/application/Espo/Core/FieldProcessing/EmailAddress/Saver.php index ab53000765..59af1c6f7c 100644 --- a/application/Espo/Core/FieldProcessing/EmailAddress/Saver.php +++ b/application/Espo/Core/FieldProcessing/EmailAddress/Saver.php @@ -29,6 +29,7 @@ namespace Espo\Core\FieldProcessing\EmailAddress; +use Espo\Core\Name\Link; use Espo\Core\ORM\Repository\Option\SaveOption; use Espo\Core\ORM\Type\FieldType; use Espo\Entities\EmailAddress; @@ -50,6 +51,8 @@ class Saver implements SaverInterface private const ATTR_EMAIL_ADDRESS_IS_OPTED_OUT = 'emailAddressIsOptedOut'; private const ATTR_EMAIL_ADDRESS_IS_INVALID = 'emailAddressIsInvalid'; + private const LINK_EMAIL_ADDRESSES = Link::EMAIL_ADDRESSES; + public function __construct( private EntityManager $entityManager, private ApplicationState $applicationState, @@ -421,7 +424,7 @@ class Saver implements SaverInterface if ($emailAddressOld) { $this->entityManager - ->getRelation($entity, 'emailAddresses') + ->getRelation($entity, self::LINK_EMAIL_ADDRESSES) ->unrelate($emailAddressOld, [SaveOption::SKIP_HOOKS => true]); } } @@ -493,13 +496,13 @@ class Saver implements SaverInterface if ($emailAddressOld) { $entityRepository - ->getRelation($entity, 'emailAddresses') + ->getRelation($entity, self::LINK_EMAIL_ADDRESSES) ->unrelate($emailAddressOld, [SaveOption::SKIP_HOOKS => true]); } } $entityRepository - ->getRelation($entity, 'emailAddresses') + ->getRelation($entity, self::LINK_EMAIL_ADDRESSES) ->relate($emailAddressNew, null, [SaveOption::SKIP_HOOKS => true]); if ($entity->has(self::ATTR_EMAIL_ADDRESS_IS_OPTED_OUT)) { diff --git a/application/Espo/Core/Mail/Account/GroupAccount/Hooks/AfterFetch.php b/application/Espo/Core/Mail/Account/GroupAccount/Hooks/AfterFetch.php index e356db7d06..95f2dce0d7 100644 --- a/application/Espo/Core/Mail/Account/GroupAccount/Hooks/AfterFetch.php +++ b/application/Espo/Core/Mail/Account/GroupAccount/Hooks/AfterFetch.php @@ -30,6 +30,7 @@ namespace Espo\Core\Mail\Account\GroupAccount\Hooks; use Espo\Core\Name\Field; +use Espo\Core\Name\Link; use Laminas\Mail\Message; use Espo\Core\Mail\Account\GroupAccount\AccountFactory as GroupAccountFactory; @@ -543,7 +544,7 @@ class AfterFetch implements AfterFetchInterface $contact = $this->entityManager ->getRDBRepository(Contact::ENTITY_TYPE) - ->join('emailAddresses', 'emailAddressesMultiple') + ->join(Link::EMAIL_ADDRESSES, 'emailAddressesMultiple') ->where([ 'emailAddressesMultiple.id' => $email->get('fromEmailAddressId'), ]) @@ -555,7 +556,7 @@ class AfterFetch implements AfterFetchInterface if (!$case->get('accountId')) { $lead = $this->entityManager ->getRDBRepository(Lead::ENTITY_TYPE) - ->join('emailAddresses', 'emailAddressesMultiple') + ->join(Link::EMAIL_ADDRESSES, 'emailAddressesMultiple') ->where([ 'emailAddressesMultiple.id' => $email->get('fromEmailAddressId') ]) diff --git a/application/Espo/Core/Mail/ConfigDataProvider.php b/application/Espo/Core/Mail/ConfigDataProvider.php index cabe9b30cb..b6c3b6f1c8 100644 --- a/application/Espo/Core/Mail/ConfigDataProvider.php +++ b/application/Espo/Core/Mail/ConfigDataProvider.php @@ -41,4 +41,9 @@ class ConfigDataProvider { return $this->config->get('outboundEmailFromAddress'); } + + public function isOutboundEmailShared(): bool + { + return (bool) $this->config->get('outboundEmailIsShared'); + } } diff --git a/application/Espo/Core/Name/Link.php b/application/Espo/Core/Name/Link.php new file mode 100644 index 0000000000..71b9022b22 --- /dev/null +++ b/application/Espo/Core/Name/Link.php @@ -0,0 +1,38 @@ +. + * + * 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\Core\Name; + +/** + * @since 9.2.0 + */ +class Link +{ + public const EMAIL_ADDRESSES = 'emailAddresses'; +} diff --git a/application/Espo/Tools/App/AppService.php b/application/Espo/Tools/App/AppService.php index e9075ca893..b88f60c618 100644 --- a/application/Espo/Tools/App/AppService.php +++ b/application/Espo/Tools/App/AppService.php @@ -32,6 +32,7 @@ namespace Espo\Tools\App; use Espo\Core\Authentication\Util\MethodProvider as AuthenticationMethodProvider; use Espo\Core\Mail\ConfigDataProvider as EmailConfigDataProvider; use Espo\Core\Name\Field; +use Espo\Core\Name\Link; use Espo\Core\Utils\SystemUser; use Espo\Entities\DashboardTemplate; use Espo\Entities\Email; @@ -51,7 +52,6 @@ use Espo\Core\Utils\Log; use Espo\Core\Utils\Metadata; use Espo\Entities\User; use Espo\Entities\Preferences; -use Espo\ORM\Collection; use Espo\ORM\EntityManager; use stdClass; use Throwable; @@ -281,16 +281,15 @@ class AppService { $user = $this->user; - $outboundEmailIsShared = $this->config->get('outboundEmailIsShared'); + $outboundEmailIsShared = $this->emailConfigDataProvider->isOutboundEmailShared(); $outboundEmailFromAddress = $this->emailConfigDataProvider->getSystemOutboundAddress(); $emailAddressList = []; $userEmailAddressList = []; - /** @var Collection $emailAddressCollection */ + /** @var iterable $emailAddressCollection */ $emailAddressCollection = $this->entityManager - ->getRDBRepositoryByClass(User::class) - ->getRelation($user, 'emailAddresses') + ->getRelation($user, Link::EMAIL_ADDRESSES) ->find(); foreach ($emailAddressCollection as $emailAddress) { diff --git a/application/Espo/Tools/App/SettingsService.php b/application/Espo/Tools/App/SettingsService.php index 26c01dde88..c297517cee 100644 --- a/application/Espo/Tools/App/SettingsService.php +++ b/application/Espo/Tools/App/SettingsService.php @@ -31,6 +31,7 @@ namespace Espo\Tools\App; use Espo\Core\Mail\ConfigDataProvider as EmailConfigDataProvider; use Espo\Core\Utils\ThemeManager; +use Espo\Entities\Email; use Espo\Entities\Settings; use Espo\ORM\Entity; use Espo\ORM\EntityManager; @@ -368,8 +369,8 @@ class SettingsService } if ( - !$this->acl->checkScope('Email', 'create') || - !$this->config->get('outboundEmailIsShared') + !$this->acl->checkScope(Email::ENTITY_TYPE, Acl\Table::ACTION_CREATE) || + !$this->emailConfigDataProvider->isOutboundEmailShared() ) { unset($data->outboundEmailFromAddress); unset($data->outboundEmailFromName); diff --git a/application/Espo/Tools/Email/SendService.php b/application/Espo/Tools/Email/SendService.php index 9e48f421bc..099e0466dd 100644 --- a/application/Espo/Tools/Email/SendService.php +++ b/application/Espo/Tools/Email/SendService.php @@ -52,6 +52,7 @@ use Espo\Core\Mail\Sender; use Espo\Core\Mail\SenderParams; use Espo\Core\Mail\Smtp\HandlerProcessor; use Espo\Core\Mail\SmtpParams; +use Espo\Core\Name\Link; use Espo\Core\ORM\Repository\Option\SaveOption; use Espo\Core\Utils\Config; use Espo\Core\Utils\Json; @@ -77,6 +78,8 @@ use const FILTER_VALIDATE_EMAIL; */ class SendService { + private const LINK_EMAIL_ADDRESSES = Link::EMAIL_ADDRESSES; + /** @var string[] */ private array $notAllowedStatusList = [ Email::STATUS_ARCHIVED, @@ -127,7 +130,7 @@ class SendService throw new BadRequest("Empty To address."); } - $systemIsShared = $this->config->get('outboundEmailIsShared'); + $systemIsShared = $this->configDataProvider->isOutboundEmailShared(); $systemFromName = $this->config->get('outboundEmailFromName'); $systemFromAddress = $this->configDataProvider->getSystemOutboundAddress(); @@ -139,7 +142,7 @@ class SendService // @todo Use getEmailAddressGroup. /** @var Collection $emailAddressCollection */ $emailAddressCollection = $this->entityManager - ->getRelation($user, 'emailAddresses') + ->getRelation($user, self::LINK_EMAIL_ADDRESSES) ->find(); foreach ($emailAddressCollection as $ea) { diff --git a/application/Espo/Tools/EmailNotification/Processor.php b/application/Espo/Tools/EmailNotification/Processor.php index fb216aeb8a..b8305a2cd5 100644 --- a/application/Espo/Tools/EmailNotification/Processor.php +++ b/application/Espo/Tools/EmailNotification/Processor.php @@ -31,6 +31,7 @@ namespace Espo\Tools\EmailNotification; use Espo\Core\Field\LinkParent; use Espo\Core\Name\Field; +use Espo\Core\Name\Link; use Espo\Core\Notification\EmailNotificationHandler; use Espo\Core\Mail\SenderParams; use Espo\Core\Utils\Config\ApplicationConfig; @@ -766,7 +767,7 @@ class Processor } $emailAddresses = $this->entityManager - ->getRelation($user, 'emailAddresses') + ->getRelation($user, Link::EMAIL_ADDRESSES) ->find(); foreach ($emailAddresses as $ea) {