From 4a2aa91b6d5047d0c770be8d07cf74fff4d63d68 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 23 Feb 2021 13:13:24 +0200 Subject: [PATCH] email notification refactoring --- .../Espo/Jobs/SendEmailNotifications.php | 16 +- .../EmailNotificationHandlers/CaseObj.php | 24 +- .../metadata/app/emailNotifications.json | 2 +- .../Espo/Services/EmailNotification.php | 908 +----------------- .../EmailNotification/AssignmentProcessor.php | 231 +++++ .../Tools/EmailNotification/Processor.php | 820 ++++++++++++++++ 6 files changed, 1082 insertions(+), 919 deletions(-) rename application/Espo/Modules/Crm/{Business => Classes}/EmailNotificationHandlers/CaseObj.php (77%) create mode 100644 application/Espo/Tools/EmailNotification/AssignmentProcessor.php create mode 100644 application/Espo/Tools/EmailNotification/Processor.php diff --git a/application/Espo/Jobs/SendEmailNotifications.php b/application/Espo/Jobs/SendEmailNotifications.php index 412b3123c4..42f3f1bd90 100644 --- a/application/Espo/Jobs/SendEmailNotifications.php +++ b/application/Espo/Jobs/SendEmailNotifications.php @@ -29,23 +29,21 @@ namespace Espo\Jobs; -use Espo\Core\{ - ServiceFactory, - Jobs\Job, -}; +use Espo\Core\Jobs\Job; + +use Espo\Tools\EmailNotification\Processor; class SendEmailNotifications implements Job { - protected $serviceFactory; + private $processor; - public function __construct(ServiceFactory $serviceFactory) + public function __construct(Processor $processor) { - $this->serviceFactory = $serviceFactory; + $this->processor = $processor; } public function run() { - $service = $this->serviceFactory->create('EmailNotification'); - $service->process(); + $this->processor->process(); } } diff --git a/application/Espo/Modules/Crm/Business/EmailNotificationHandlers/CaseObj.php b/application/Espo/Modules/Crm/Classes/EmailNotificationHandlers/CaseObj.php similarity index 77% rename from application/Espo/Modules/Crm/Business/EmailNotificationHandlers/CaseObj.php rename to application/Espo/Modules/Crm/Classes/EmailNotificationHandlers/CaseObj.php index 8f3f257ecd..678c6cf59a 100644 --- a/application/Espo/Modules/Crm/Business/EmailNotificationHandlers/CaseObj.php +++ b/application/Espo/Modules/Crm/Classes/EmailNotificationHandlers/CaseObj.php @@ -27,33 +27,45 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -namespace Espo\Modules\Crm\Business\EmailNotificationHandlers; +namespace Espo\Modules\Crm\Classes\EmailNotificationHandlers; use Espo\Core\Di; +use Espo\{ + ORM\Entity, + Entities\User, +}; + class CaseObj implements Di\EntityManagerAware { use Di\EntityManagerSetter; protected $inboundEmailEntityHash = []; - public function getSmtpParams($type, $case, $user = null) : ?array + public function getSmtpParams(string $type, Entity $case, User $user = null) : ?array { $inboundEmailId = $case->get('inboundEmailId'); - if (!$inboundEmailId) return null; + if (!$inboundEmailId) { + return null; + } if (!array_key_exists($inboundEmailId, $this->inboundEmailEntityHash)) { - $this->inboundEmailEntityHash[$inboundEmailId] = $this->entityManager->getEntity('InboundEmail', $inboundEmailId); + $this->inboundEmailEntityHash[$inboundEmailId] = + $this->entityManager->getEntity('InboundEmail', $inboundEmailId); } $inboundEmail = $this->inboundEmailEntityHash[$inboundEmailId]; - if (!$inboundEmail) return null; + if (!$inboundEmail) { + return null; + } $emailAddress = $inboundEmail->get('emailAddress'); - if (!$emailAddress) return null; + if (!$emailAddress) { + return null; + } return [ 'replyToAddress' => $emailAddress, diff --git a/application/Espo/Resources/metadata/app/emailNotifications.json b/application/Espo/Resources/metadata/app/emailNotifications.json index cfef85a6af..09915a00f4 100644 --- a/application/Espo/Resources/metadata/app/emailNotifications.json +++ b/application/Espo/Resources/metadata/app/emailNotifications.json @@ -1,5 +1,5 @@ { "handlerClassNameMap": { - "Case": "\\Espo\\Modules\\Crm\\Business\\EmailNotificationHandlers\\CaseObj" + "Case": "Espo\\Modules\\Crm\\Classes\\EmailNotificationHandlers\\CaseObj" } } diff --git a/application/Espo/Services/EmailNotification.php b/application/Espo/Services/EmailNotification.php index a28c47e6e7..636f6eb5a9 100644 --- a/application/Espo/Services/EmailNotification.php +++ b/application/Espo/Services/EmailNotification.php @@ -30,920 +30,22 @@ namespace Espo\Services; use Espo\{ - ORM\Entity, - ORM\EntityManager, - ORM\QueryParams\SelectBuilder as SelectBuilder, - Entities\User as UserEntity, + Tools\EmailNotification\AssignmentProcessor, }; -use Espo\Core\{ - Exceptions\Error, - Htmlizer\Factory as HtmlizerFactory, - Htmlizer\Htmlizer, - Utils\Config, - Utils\Metadata, - Utils\Language, - Select\SelectBuilderFactory, - InjectableFactory, - Utils\TemplateFileManager, - Mail\EmailSender as EmailSender, - Utils\Util, -}; - -use Michelf\Markdown; - -use Exception; -use DateTime; use StdClass; class EmailNotification { - const HOURS_THERSHOLD = 5; + protected $assignmentProcessor; - const PROCESS_MAX_COUNT = 200; - - protected $htmlizer; - - protected $entityManager; - protected $htmlizerFactory; - protected $emailSender; - protected $config; - protected $selectBuilderFactory; - protected $injectableFactory; - protected $templateFileManager; - protected $metadata; - - public function __construct( - EntityManager $entityManager, - HtmlizerFactory $htmlizerFactory, - EmailSender $emailSender, - Config $config, - SelectBuilderFactory $selectBuilderFactory, - InjectableFactory $injectableFactory, - TemplateFileManager $templateFileManager, - Metadata $metadata, - Language $language - ) { - $this->entityManager = $entityManager; - $this->htmlizerFactory = $htmlizerFactory; - $this->emailSender = $emailSender; - $this->config = $config; - $this->selectBuilderFactory = $selectBuilderFactory; - $this->injectableFactory = $injectableFactory; - $this->templateFileManager = $templateFileManager; - $this->metadata = $metadata; - $this->language = $language; - } - - protected $emailNotificationEntityHandlerHash = []; - - protected function getHtmlizer() : Htmlizer + public function __construct(AssignmentProcessor $assignmentProcessor) { - if (!$this->htmlizer) { - $this->htmlizer = $this->htmlizerFactory->create(true); - } - - return $this->htmlizer; + $this->assignmentProcessor = $assignmentProcessor; } - protected $userIdPortalCacheMap = []; - public function notifyAboutAssignmentJob(StdClass $data) : void { - $userId = $data->userId ?? null; - $assignerUserId = $data->assignerUserId ?? null; - $entityId = $data->entityId ?? null; - $entityType = $data->entityType ?? null; - - if ( - !$userId || - !$assignerUserId || - !$entityId || - !$entityType - ) { - throw new Error(); - } - - $user = $this->entityManager->getEntity('User', $userId); - - if (!$user) { - return; - } - - if ($user->isPortal()) { - return; - } - - $preferences = $this->entityManager->getEntity('Preferences', $userId); - - if (!$preferences) { - return; - } - - if (!$preferences->get('receiveAssignmentEmailNotifications')) { - return; - } - - $ignoreList = $preferences->get('assignmentEmailNotificationsIgnoreEntityTypeList') ?? []; - - if (in_array($entityType, $ignoreList)) { - return; - } - - $assignerUser = $this->entityManager->getEntity('User', $assignerUserId); - - $entity = $this->entityManager->getEntity($entityType, $entityId); - - if (!$entity) { - return; - } - - if (!$assignerUser) { - return; - } - - $this->loadParentNameFields($entity); - - if (!$entity->hasLinkMultipleField('assignedUsers')) { - if ($entity->get('assignedUserId') !== $userId) { - return; - } - } - - $emailAddress = $user->get('emailAddress'); - - if (!$emailAddress) { - return; - } - - $email = $this->entityManager->getEntity('Email'); - - $subjectTpl = $this->templateFileManager->getTemplate('assignment', 'subject', $entity->getEntityType()); - - $bodyTpl = $this->templateFileManager->getTemplate('assignment', 'body', $entity->getEntityType()); - - $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); - - $recordUrl = rtrim($this->config->get('siteUrl'), '/') . - '/#' . $entity->getEntityType() . '/view/' . $entity->id; - - $templateData = [ - 'userName' => $user->get('name'), - 'assignerUserName' => $assignerUser->get('name'), - 'recordUrl' => $recordUrl, - 'entityType' => $this->language->translate($entity->getEntityType(), 'scopeNames'), - ]; - - $templateData['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($templateData['entityType']); - - $subject = $this->getHtmlizer()->render( - $entity, - $subjectTpl, - 'assignment-email-subject-' . $entity->getEntityType(), - $templateData, - true - ); - - $body = $this->getHtmlizer()->render( - $entity, - $bodyTpl, - 'assignment-email-body-' . $entity->getEntityType(), - $templateData, - true - ); - - $email->set([ - 'subject' => $subject, - 'body' => $body, - 'isHtml' => true, - 'to' => $emailAddress, - 'isSystem' => true, - 'parentId' => $entity->id, - 'parentType' => $entity->getEntityType(), - ]); - - try { - $this->emailSender->send($email); - } - catch (Exception $e) { - $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); - } - } - - public function process() : void - { - $mentionEmailNotifications = $this->config->get('mentionEmailNotifications'); - - $streamEmailNotifications = $this->config->get('streamEmailNotifications'); - $portalStreamEmailNotifications = $this->config->get('portalStreamEmailNotifications'); - - $typeList = []; - - if ($mentionEmailNotifications) { - $typeList[] = 'MentionInPost'; - } - - if ($streamEmailNotifications || $portalStreamEmailNotifications) { - $typeList[] = 'Note'; - } - - if (empty($typeList)) { - return; - } - - $fromDt = new DateTime(); - - $fromDt->modify('-' . self::HOURS_THERSHOLD . ' hours'); - - $where = [ - 'createdAt>' => $fromDt->format('Y-m-d H:i:s'), - 'read' => false, - 'emailIsProcessed' => false, - ]; - - $delay = $this->config->get('emailNotificationsDelay'); - - if ($delay) { - $delayDt = new DateTime(); - - $delayDt->modify('-' . $delay . ' seconds'); - - $where[] = ['createdAt<' => $delayDt->format('Y-m-d H:i:s')]; - } - - $queryList = []; - - foreach ($typeList as $type) { - $methodName = 'getNotificationQueryBuilder' . $type; - - $itemBuilder = $this->$methodName(); - - $itemBuilder->where($where); - - $queryList[] = $itemBuilder->build(); - } - - $builder = $this->entityManager->getQueryBuilder() - ->union() - ->order('number') - ->limit(0, self::PROCESS_MAX_COUNT); - - foreach ($queryList as $query) { - $builder->query($query); - } - - $unionQuery = $builder->build(); - - $sql = $this->entityManager->getQueryComposer()->compose($unionQuery); - - $notificationList = $this->entityManager->getRepository('Notification')->findBySql($sql); - - foreach ($notificationList as $notification) { - $notification->set('emailIsProcessed', true); - - $type = $notification->get('type'); - - $methodName = 'processNotification' . ucfirst($type); - - if (method_exists($this, $methodName)) { - $this->$methodName($notification); - } - - $this->entityManager->saveEntity($notification); - } - } - - protected function getNotificationQueryBuilderMentionInPost() : SelectBuilder - { - return $this->entityManager - ->getQueryBuilder() - ->select() - ->from('Notification') - ->where([ - 'type' => 'MentionInPost', - ]); - } - - protected function getNotificationQueryBuilderNote() : SelectBuilder - { - $noteNotificationTypeList = $this->config->get('streamEmailNotificationsTypeList', []); - - $builder = $this->entityManager - ->getQueryBuilder() - ->select() - ->from('Notification') - ->join('Note', 'note', ['note.id:' => 'relatedId']) - ->where([ - 'type' => 'Note', - 'relatedType' => 'Note', - 'note.type' => $noteNotificationTypeList, - ]); - - $entityList = $this->config->get('streamEmailNotificationsEntityList'); - - if (empty($entityList)) { - $builder->where([ - 'relatedParentType' => null, - ]); - } - else { - $builder->where([ - 'OR' => [ - [ - 'relatedParentType' => $entityList, - ], - [ - 'relatedParentType' => null, - ], - ], - ]); - } - - $forInternal = $this->config->get('streamEmailNotifications'); - $forPortal = $this->config->get('portalStreamEmailNotifications'); - - if ($forInternal && !$forPortal) { - //$selectParams['whereClause']['user.type!='] = 'portal'; - - $builder->where([ - 'user.type!=' => 'portal', - ]); - } - else if (!$forInternal && $forPortal) { - //$selectParams['whereClause']['user.type'] = 'portal'; - - $builder->where([ - 'user.type' => 'portal', - ]); - } - - return $builder; - } - - protected function processNotificationMentionInPost(Entity $notification) : void - { - if (!$notification->get('userId')) { - return; - } - - $userId = $notification->get('userId'); - - $user = $this->entityManager->getEntity('User', $userId); - - if (!$user) { - return; - } - - $emailAddress = $user->get('emailAddress'); - - if (!$emailAddress) { - return; - } - - $preferences = $this->entityManager->getEntity('Preferences', $userId); - - if (!$preferences) { - return; - } - - if (!$preferences->get('receiveMentionEmailNotifications')) { - return; - } - - if ($notification->get('relatedType') !== 'Note' || !$notification->get('relatedId')) { - return; - } - - $note = $this->entityManager->getEntity('Note', $notification->get('relatedId')); - - if (!$note) { - return; - } - - $parentId = $note->get('parentId'); - $parentType = $note->get('parentType'); - - $data = []; - - if ($parentId && $parentType) { - $parent = $this->entityManager->getEntity($parentType, $parentId); - - if (!$parent) { - return; - } - - $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; - $data['parentName'] = $parent->get('name'); - $data['parentType'] = $parentType; - $data['parentId'] = $parentId; - } - else { - $data['url'] = $this->getSiteUrl($user) . '/#Notification'; - } - - $data['userName'] = $note->get('createdByName'); - - $post = $note->get('post') ?? '' - ; - $post = Markdown::defaultTransform($post); - - $data['post'] = $post; - - $subjectTpl = $this->templateFileManager->getTemplate('mention', 'subject'); - - $bodyTpl = $this->templateFileManager->getTemplate('mention', 'body'); - - $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); - - $subject = $this->getHtmlizer()->render($note, $subjectTpl, 'mention-email-subject', $data, true); - - $body = $this->getHtmlizer()->render($note, $bodyTpl, 'mention-email-body', $data, true); - - $email = $this->entityManager->getEntity('Email'); - - $email->set([ - 'subject' => $subject, - 'body' => $body, - 'isHtml' => true, - 'to' => $emailAddress, - 'isSystem' => true, - ]); - - if ($parentId && $parentType) { - $email->set([ - 'parentId' => $parentId, - 'parentType' => $parentType - ]); - } - - try { - $this->emailSender->send($email); - } - catch (Exception $e) { - $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); - } - } - - protected function processNotificationNote(Entity $notification) : void - { - if ($notification->get('relatedType') !== 'Note') { - return; - } - - if (!$notification->get('relatedId')) { - return; - } - - $note = $this->entityManager->getEntity('Note', $notification->get('relatedId')); - - if (!$note) { - return; - } - - $noteNotificationTypeList = $this->config->get('streamEmailNotificationsTypeList', []); - - if (!in_array($note->get('type'), $noteNotificationTypeList)) { - return; - } - - if (!$notification->get('userId')) { - return; - } - - $userId = $notification->get('userId'); - $user = $this->entityManager->getEntity('User', $userId); - - if (!$user) { - return; - } - - $emailAddress = $user->get('emailAddress'); - - if (!$emailAddress) { - return; - } - - $preferences = $this->entityManager->getEntity('Preferences', $userId); - - if (!$preferences) { - return; - } - - if (!$preferences->get('receiveStreamEmailNotifications')) { - return; - } - - $methodName = 'processNotificationNote' . $note->get('type'); - - if (!method_exists($this, $methodName)) { - return; - } - - $this->$methodName($note, $user); - } - - protected function getEmailNotificationEntityHandler(string $entityType) : ?string - { - if (!array_key_exists($entityType, $this->emailNotificationEntityHandlerHash)) { - $this->emailNotificationEntityHandlerHash[$entityType] = null; - - $className = $this->metadata->get(['app', 'emailNotifications', 'handlerClassNameMap', $entityType]); - - if ($className && class_exists($className)) { - $handler = $this->injectableFactory->create($className); - - if ($handler) { - $this->emailNotificationEntityHandlerHash[$entityType] = $handler; - } - } - } - - return $this->emailNotificationEntityHandlerHash[$entityType]; - } - - protected function processNotificationNotePost($note, $user) - { - $parentId = $note->get('parentId'); - $parentType = $note->get('parentType'); - - $emailAddress = $user->get('emailAddress'); - - if (!$emailAddress) { - return; - } - - $data = []; - - $data['userName'] = $note->get('createdByName'); - - $post = $note->get('post') ?? '' - ; - $post = Markdown::defaultTransform($post); - - $data['post'] = $post; - - if ($parentId && $parentType) { - $parent = $this->entityManager->getEntity($parentType, $parentId); - - if (!$parent) { - return; - } - - $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; - $data['parentName'] = $parent->get('name'); - $data['parentType'] = $parentType; - $data['parentId'] = $parentId; - - $data['name'] = $data['parentName']; - - $data['entityType'] = $this->language->translate($data['parentType'], 'scopeNames'); - $data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']); - - $subjectTpl = $this->templateFileManager->getTemplate('notePost', 'subject', $parentType); - - $bodyTpl = $this->templateFileManager->getTemplate('notePost', 'body', $parentType); - - $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); - - $subject = $this->getHtmlizer()->render( - $note, - $subjectTpl, - 'note-post-email-subject-' . $parentType, - $data, - true - ); - - $body = $this->getHtmlizer()->render( - $note, - $bodyTpl, - 'note-post-email-body-' . $parentType, - $data, - true - ); - } - else { - $data['url'] = $this->getSiteUrl($user) . '/#Notification'; - - $subjectTpl = $this->templateFileManager->getTemplate('notePostNoParent', 'subject'); - - $bodyTpl = $this->templateFileManager->getTemplate('notePostNoParent', 'body'); - - $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); - - $subject = $this->getHtmlizer()->render($note, $subjectTpl, 'note-post-email-subject', $data, true); - - $body = $this->getHtmlizer()->render($note, $bodyTpl, 'note-post-email-body', $data, true); - } - - $email = $this->entityManager->getEntity('Email'); - - $email->set([ - 'subject' => $subject, - 'body' => $body, - 'isHtml' => true, - 'to' => $emailAddress, - 'isSystem' => true, - ]); - - if ($parentId && $parentType) { - $email->set([ - 'parentId' => $parentId, - 'parentType' => $parentType, - ]); - } - - $smtpParams = null; - - if ($parentId && $parentType && !empty($parent)) { - $handler = $this->getEmailNotificationEntityHandler($parentType); - - if ($handler) { - $prepareEmailMethodName = 'prepareEmail'; - - if (method_exists($handler, $prepareEmailMethodName)) { - $handler->$prepareEmailMethodName('notePost', $parent, $email, $user); - } - - $getSmtpParamsMethodName = 'getSmtpParams'; - - if (method_exists($handler, $getSmtpParamsMethodName)) { - $smtpParams = $handler->$getSmtpParamsMethodName('notePost', $parent, $user); - } - } - } - - $sender = $this->emailSender->create(); - - try { - if ($smtpParams) { - $sender->withSmtpParams($smtpParams); - } - - $sender->send($email); - } - catch (Exception $e) { - $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); - } - } - - protected function getSiteUrl(UserEntity $user) : string - { - if ($user->isPortal()) { - if (!array_key_exists($user->id, $this->userIdPortalCacheMap)) { - $this->userIdPortalCacheMap[$user->id] = null; - - $portalIdList = $user->getLinkMultipleIdList('portals'); - - $defaultPortalId = $this->config->get('defaultPortalId'); - - $portalId = null; - - if (in_array($defaultPortalId, $portalIdList)) { - $portalId = $defaultPortalId; - } - else if (count($portalIdList)) { - $portalId = $portalIdList[0]; - } - - if ($portalId) { - $portal = $this->entityManager->getEntity('Portal', $portalId); - - $this->entityManager->getRepository('Portal')->loadUrlField($portal); - - $this->userIdPortalCacheMap[$user->id] = $portal; - } - } - else { - $portal = $this->userIdPortalCacheMap[$user->id]; - } - - if ($portal) { - $url = $portal->get('url'); - - $url = rtrim($url, '/'); - - return $url; - } - } - - return $this->config->getSiteUrl(); - } - - protected function processNotificationNoteStatus($note, $user) - { - $parentId = $note->get('parentId'); - $parentType = $note->get('parentType'); - - $emailAddress = $user->get('emailAddress'); - - if (!$emailAddress) { - return; - } - - $data = []; - - if (!$parentId || !$parentType) { - return; - } - - $parent = $this->entityManager->getEntity($parentType, $parentId); - - if (!$parent) { - return; - } - - $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; - $data['parentName'] = $parent->get('name'); - $data['parentType'] = $parentType; - $data['parentId'] = $parentId; - - $data['name'] = $data['parentName']; - - $data['entityType'] = $this->language->translate($data['parentType'], 'scopeNames'); - $data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']); - - $noteData = $note->get('data'); - - if (empty($noteData)) { - return; - } - - $data['value'] = $noteData->value; - $data['field'] = $noteData->field; - $data['valueTranslated'] = $this->language->translateOption($data['value'], $data['field'], $parentType); - $data['fieldTranslated'] = $this->language->translate($data['field'], 'fields', $parentType); - $data['fieldTranslatedLowerCase'] = Util::mbLowerCaseFirst($data['fieldTranslated']); - - $data['userName'] = $note->get('createdByName'); - - $subjectTpl = $this->templateFileManager->getTemplate('noteStatus', 'subject', $parentType); - - $bodyTpl = $this->templateFileManager->getTemplate('noteStatus', 'body', $parentType); - - $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); - - $subject = $this->getHtmlizer()->render( - $note, $subjectTpl, 'note-status-email-subject', $data, true - ); - - $body = $this->getHtmlizer()->render( - $note, $bodyTpl, 'note-status-email-body', $data, true - ); - - $email = $this->entityManager->getEntity('Email'); - - $email->set([ - 'subject' => $subject, - 'body' => $body, - 'isHtml' => true, - 'to' => $emailAddress, - 'isSystem' => true, - 'parentId' => $parentId, - 'parentType' => $parentType, - ]); - - try { - $this->emailSender->send($email); - } - catch (Exception $e) { - $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); - } - } - - protected function processNotificationNoteEmailReceived($note, $user) - { - $parentId = $note->get('parentId'); - $parentType = $note->get('parentType'); - - $allowedEntityTypeList = $this->config->get('streamEmailNotificationsEmailReceivedEntityTypeList'); - - if ( - is_array($allowedEntityTypeList) - && - !in_array($parentType, $allowedEntityTypeList) - ) { - return; - } - - $emailAddress = $user->get('emailAddress'); - - if (!$emailAddress) { - return; - } - - $noteData = $note->get('data'); - - if (!($noteData instanceof StdClass)) { - return; - } - - if (!isset($noteData->emailId)) { - return; - } - - $email = $this->entityManager->getEntity('Email', $noteData->emailId); - - if (!$email) { - return; - } - - $emailRepository = $this->entityManager->getRepository('Email'); - $eaList = $user->get('emailAddresses'); - - foreach ($eaList as $ea) { - if ( - $emailRepository->isRelated($email, 'toEmailAddresses', $ea) - || - $emailRepository->isRelated($email, 'ccEmailAddresses', $ea) - ) { - return; - } - } - - $data = []; - - $data['fromName'] = ''; - - if (isset($noteData->personEntityName)) { - $data['fromName'] = $noteData->personEntityName; - } - else if (isset($noteData->fromString)) { - $data['fromName'] = $noteData->fromString; - } - - $data['subject'] = ''; - - if (isset($noteData->emailName)) { - $data['subject'] = $noteData->emailName; - } - - $data['post'] = nl2br($note->get('post')); - - if (!$parentId || !$parentType) { - return; - } - - $parent = $this->entityManager->getEntity($parentType, $parentId); - - if (!$parent) { - return; - } - - $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; - $data['parentName'] = $parent->get('name'); - $data['parentType'] = $parentType; - $data['parentId'] = $parentId; - - $data['name'] = $data['parentName']; - - $data['entityType'] = $this->language->translate($data['parentType'], 'scopeNames'); - $data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']); - - $subjectTpl = $this->templateFileManager->getTemplate('noteEmailReceived', 'subject', $parentType); - - $bodyTpl = $this->templateFileManager->getTemplate('noteEmailReceived', 'body', $parentType); - - $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); - - $subject = $this->getHtmlizer()->render( - $note, $subjectTpl, 'note-email-received-email-subject-' . $parentType, $data, true - ); - - $body = $this->getHtmlizer()->render( - $note, $bodyTpl, 'note-email-received-email-body-' . $parentType, $data, true - ); - - $email = $this->entityManager->getEntity('Email'); - - $email->set([ - 'subject' => $subject, - 'body' => $body, - 'isHtml' => true, - 'to' => $emailAddress, - 'isSystem' => true, - ]); - - $email->set([ - 'parentId' => $parentId, - 'parentType' => $parentType - ]); - - try { - $this->emailSender->send($email); - } - catch (Exception $e) { - $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); - } - } - - protected function loadParentNameFields(Entity $entity) : void - { - $fieldDefs = $this->metadata->get(['entityDefs', $entity->getEntityType(), 'fields'], []); - - foreach ($fieldDefs as $field => $defs) { - if (isset($defs['type']) && $defs['type'] == 'linkParent') { - $entity->loadParentNameField($field); - } - } + $this->assignmentProcessor->process($data); } } diff --git a/application/Espo/Tools/EmailNotification/AssignmentProcessor.php b/application/Espo/Tools/EmailNotification/AssignmentProcessor.php new file mode 100644 index 0000000000..f879e46b46 --- /dev/null +++ b/application/Espo/Tools/EmailNotification/AssignmentProcessor.php @@ -0,0 +1,231 @@ +entityManager = $entityManager; + $this->htmlizerFactory = $htmlizerFactory; + $this->emailSender = $emailSender; + $this->config = $config; + $this->templateFileManager = $templateFileManager; + $this->metadata = $metadata; + $this->language = $language; + } + + public function process(StdClass $data) : void + { + $userId = $data->userId ?? null; + $assignerUserId = $data->assignerUserId ?? null; + $entityId = $data->entityId ?? null; + $entityType = $data->entityType ?? null; + + if ( + !$userId || + !$assignerUserId || + !$entityId || + !$entityType + ) { + throw new Error(); + } + + $user = $this->entityManager->getEntity('User', $userId); + + if (!$user) { + return; + } + + if ($user->isPortal()) { + return; + } + + $preferences = $this->entityManager->getEntity('Preferences', $userId); + + if (!$preferences) { + return; + } + + if (!$preferences->get('receiveAssignmentEmailNotifications')) { + return; + } + + $ignoreList = $preferences->get('assignmentEmailNotificationsIgnoreEntityTypeList') ?? []; + + if (in_array($entityType, $ignoreList)) { + return; + } + + $assignerUser = $this->entityManager->getEntity('User', $assignerUserId); + + $entity = $this->entityManager->getEntity($entityType, $entityId); + + if (!$entity) { + return; + } + + if (!$assignerUser) { + return; + } + + $this->loadParentNameFields($entity); + + if (!$entity->hasLinkMultipleField('assignedUsers')) { + if ($entity->get('assignedUserId') !== $userId) { + return; + } + } + + $emailAddress = $user->get('emailAddress'); + + if (!$emailAddress) { + return; + } + + $email = $this->entityManager->getEntity('Email'); + + $subjectTpl = $this->templateFileManager->getTemplate('assignment', 'subject', $entity->getEntityType()); + + $bodyTpl = $this->templateFileManager->getTemplate('assignment', 'body', $entity->getEntityType()); + + $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); + + $recordUrl = rtrim($this->config->get('siteUrl'), '/') . + '/#' . $entity->getEntityType() . '/view/' . $entity->id; + + $templateData = [ + 'userName' => $user->get('name'), + 'assignerUserName' => $assignerUser->get('name'), + 'recordUrl' => $recordUrl, + 'entityType' => $this->language->translate($entity->getEntityType(), 'scopeNames'), + ]; + + $templateData['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($templateData['entityType']); + + $subject = $this->getHtmlizer()->render( + $entity, + $subjectTpl, + 'assignment-email-subject-' . $entity->getEntityType(), + $templateData, + true + ); + + $body = $this->getHtmlizer()->render( + $entity, + $bodyTpl, + 'assignment-email-body-' . $entity->getEntityType(), + $templateData, + true + ); + + $email->set([ + 'subject' => $subject, + 'body' => $body, + 'isHtml' => true, + 'to' => $emailAddress, + 'isSystem' => true, + 'parentId' => $entity->id, + 'parentType' => $entity->getEntityType(), + ]); + + try { + $this->emailSender->send($email); + } + catch (Exception $e) { + $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); + } + } + + protected function getHtmlizer() : Htmlizer + { + if (!$this->htmlizer) { + $this->htmlizer = $this->htmlizerFactory->create(true); + } + + return $this->htmlizer; + } + + protected function loadParentNameFields(Entity $entity) : void + { + $fieldDefs = $this->metadata->get(['entityDefs', $entity->getEntityType(), 'fields'], []); + + foreach ($fieldDefs as $field => $defs) { + if (isset($defs['type']) && $defs['type'] == 'linkParent') { + $entity->loadParentNameField($field); + } + } + } +} diff --git a/application/Espo/Tools/EmailNotification/Processor.php b/application/Espo/Tools/EmailNotification/Processor.php new file mode 100644 index 0000000000..22357dd674 --- /dev/null +++ b/application/Espo/Tools/EmailNotification/Processor.php @@ -0,0 +1,820 @@ +entityManager = $entityManager; + $this->htmlizerFactory = $htmlizerFactory; + $this->emailSender = $emailSender; + $this->config = $config; + $this->selectBuilderFactory = $selectBuilderFactory; + $this->injectableFactory = $injectableFactory; + $this->templateFileManager = $templateFileManager; + $this->metadata = $metadata; + $this->language = $language; + } + + protected $emailNotificationEntityHandlerHash = []; + + protected $userIdPortalCacheMap = []; + + public function process() : void + { + $mentionEmailNotifications = $this->config->get('mentionEmailNotifications'); + + $streamEmailNotifications = $this->config->get('streamEmailNotifications'); + $portalStreamEmailNotifications = $this->config->get('portalStreamEmailNotifications'); + + $typeList = []; + + if ($mentionEmailNotifications) { + $typeList[] = 'MentionInPost'; + } + + if ($streamEmailNotifications || $portalStreamEmailNotifications) { + $typeList[] = 'Note'; + } + + if (empty($typeList)) { + return; + } + + $fromDt = new DateTime(); + + $fromDt->modify('-' . self::HOURS_THERSHOLD . ' hours'); + + $where = [ + 'createdAt>' => $fromDt->format('Y-m-d H:i:s'), + 'read' => false, + 'emailIsProcessed' => false, + ]; + + $delay = $this->config->get('emailNotificationsDelay'); + + if ($delay) { + $delayDt = new DateTime(); + + $delayDt->modify('-' . $delay . ' seconds'); + + $where[] = ['createdAt<' => $delayDt->format('Y-m-d H:i:s')]; + } + + $queryList = []; + + foreach ($typeList as $type) { + $methodName = 'getNotificationQueryBuilder' . $type; + + $itemBuilder = $this->$methodName(); + + $itemBuilder->where($where); + + $queryList[] = $itemBuilder->build(); + } + + $builder = $this->entityManager->getQueryBuilder() + ->union() + ->order('number') + ->limit(0, self::PROCESS_MAX_COUNT); + + foreach ($queryList as $query) { + $builder->query($query); + } + + $unionQuery = $builder->build(); + + $sql = $this->entityManager->getQueryComposer()->compose($unionQuery); + + $notificationList = $this->entityManager->getRepository('Notification')->findBySql($sql); + + foreach ($notificationList as $notification) { + $notification->set('emailIsProcessed', true); + + $type = $notification->get('type'); + + $methodName = 'processNotification' . ucfirst($type); + + if (method_exists($this, $methodName)) { + $this->$methodName($notification); + } + + $this->entityManager->saveEntity($notification); + } + } + + protected function getNotificationQueryBuilderMentionInPost() : SelectBuilder + { + return $this->entityManager + ->getQueryBuilder() + ->select() + ->from('Notification') + ->where([ + 'type' => 'MentionInPost', + ]); + } + + protected function getNotificationQueryBuilderNote() : SelectBuilder + { + $noteNotificationTypeList = $this->config->get('streamEmailNotificationsTypeList', []); + + $builder = $this->entityManager + ->getQueryBuilder() + ->select() + ->from('Notification') + ->join('Note', 'note', ['note.id:' => 'relatedId']) + ->where([ + 'type' => 'Note', + 'relatedType' => 'Note', + 'note.type' => $noteNotificationTypeList, + ]); + + $entityList = $this->config->get('streamEmailNotificationsEntityList'); + + if (empty($entityList)) { + $builder->where([ + 'relatedParentType' => null, + ]); + } + else { + $builder->where([ + 'OR' => [ + [ + 'relatedParentType' => $entityList, + ], + [ + 'relatedParentType' => null, + ], + ], + ]); + } + + $forInternal = $this->config->get('streamEmailNotifications'); + $forPortal = $this->config->get('portalStreamEmailNotifications'); + + if ($forInternal && !$forPortal) { + $builder->where([ + 'user.type!=' => 'portal', + ]); + } + else if (!$forInternal && $forPortal) { + $builder->where([ + 'user.type' => 'portal', + ]); + } + + return $builder; + } + + protected function processNotificationMentionInPost(Entity $notification) : void + { + if (!$notification->get('userId')) { + return; + } + + $userId = $notification->get('userId'); + + $user = $this->entityManager->getEntity('User', $userId); + + if (!$user) { + return; + } + + $emailAddress = $user->get('emailAddress'); + + if (!$emailAddress) { + return; + } + + $preferences = $this->entityManager->getEntity('Preferences', $userId); + + if (!$preferences) { + return; + } + + if (!$preferences->get('receiveMentionEmailNotifications')) { + return; + } + + if ($notification->get('relatedType') !== 'Note' || !$notification->get('relatedId')) { + return; + } + + $note = $this->entityManager->getEntity('Note', $notification->get('relatedId')); + + if (!$note) { + return; + } + + $parentId = $note->get('parentId'); + $parentType = $note->get('parentType'); + + $data = []; + + if ($parentId && $parentType) { + $parent = $this->entityManager->getEntity($parentType, $parentId); + + if (!$parent) { + return; + } + + $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; + $data['parentName'] = $parent->get('name'); + $data['parentType'] = $parentType; + $data['parentId'] = $parentId; + } + else { + $data['url'] = $this->getSiteUrl($user) . '/#Notification'; + } + + $data['userName'] = $note->get('createdByName'); + + $post = $note->get('post') ?? '' + ; + $post = Markdown::defaultTransform($post); + + $data['post'] = $post; + + $subjectTpl = $this->templateFileManager->getTemplate('mention', 'subject'); + + $bodyTpl = $this->templateFileManager->getTemplate('mention', 'body'); + + $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); + + $subject = $this->getHtmlizer()->render($note, $subjectTpl, 'mention-email-subject', $data, true); + + $body = $this->getHtmlizer()->render($note, $bodyTpl, 'mention-email-body', $data, true); + + $email = $this->entityManager->getEntity('Email'); + + $email->set([ + 'subject' => $subject, + 'body' => $body, + 'isHtml' => true, + 'to' => $emailAddress, + 'isSystem' => true, + ]); + + if ($parentId && $parentType) { + $email->set([ + 'parentId' => $parentId, + 'parentType' => $parentType + ]); + } + + try { + $this->emailSender->send($email); + } + catch (Exception $e) { + $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); + } + } + + protected function processNotificationNote(Entity $notification) : void + { + if ($notification->get('relatedType') !== 'Note') { + return; + } + + if (!$notification->get('relatedId')) { + return; + } + + $note = $this->entityManager->getEntity('Note', $notification->get('relatedId')); + + if (!$note) { + return; + } + + $noteNotificationTypeList = $this->config->get('streamEmailNotificationsTypeList', []); + + if (!in_array($note->get('type'), $noteNotificationTypeList)) { + return; + } + + if (!$notification->get('userId')) { + return; + } + + $userId = $notification->get('userId'); + $user = $this->entityManager->getEntity('User', $userId); + + if (!$user) { + return; + } + + $emailAddress = $user->get('emailAddress'); + + if (!$emailAddress) { + return; + } + + $preferences = $this->entityManager->getEntity('Preferences', $userId); + + if (!$preferences) { + return; + } + + if (!$preferences->get('receiveStreamEmailNotifications')) { + return; + } + + $methodName = 'processNotificationNote' . $note->get('type'); + + if (!method_exists($this, $methodName)) { + return; + } + + $this->$methodName($note, $user); + } + + protected function getEmailNotificationEntityHandler(string $entityType) : ?object + { + if (!array_key_exists($entityType, $this->emailNotificationEntityHandlerHash)) { + $this->emailNotificationEntityHandlerHash[$entityType] = null; + + $className = $this->metadata->get(['app', 'emailNotifications', 'handlerClassNameMap', $entityType]); + + if ($className && class_exists($className)) { + $handler = $this->injectableFactory->create($className); + + if ($handler) { + $this->emailNotificationEntityHandlerHash[$entityType] = $handler; + } + } + } + + return $this->emailNotificationEntityHandlerHash[$entityType]; + } + + protected function processNotificationNotePost($note, $user) : void + { + $parentId = $note->get('parentId'); + $parentType = $note->get('parentType'); + + $emailAddress = $user->get('emailAddress'); + + if (!$emailAddress) { + return; + } + + $data = []; + + $data['userName'] = $note->get('createdByName'); + + $post = $note->get('post') ?? ''; + + $post = Markdown::defaultTransform($post); + + $data['post'] = $post; + + if ($parentId && $parentType) { + $parent = $this->entityManager->getEntity($parentType, $parentId); + + if (!$parent) { + return; + } + + $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; + $data['parentName'] = $parent->get('name'); + $data['parentType'] = $parentType; + $data['parentId'] = $parentId; + + $data['name'] = $data['parentName']; + + $data['entityType'] = $this->language->translate($data['parentType'], 'scopeNames'); + $data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']); + + $subjectTpl = $this->templateFileManager->getTemplate('notePost', 'subject', $parentType); + + $bodyTpl = $this->templateFileManager->getTemplate('notePost', 'body', $parentType); + + $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); + + $subject = $this->getHtmlizer()->render( + $note, + $subjectTpl, + 'note-post-email-subject-' . $parentType, + $data, + true + ); + + $body = $this->getHtmlizer()->render( + $note, + $bodyTpl, + 'note-post-email-body-' . $parentType, + $data, + true + ); + } + else { + $data['url'] = $this->getSiteUrl($user) . '/#Notification'; + + $subjectTpl = $this->templateFileManager->getTemplate('notePostNoParent', 'subject'); + + $bodyTpl = $this->templateFileManager->getTemplate('notePostNoParent', 'body'); + + $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); + + $subject = $this->getHtmlizer()->render($note, $subjectTpl, 'note-post-email-subject', $data, true); + + $body = $this->getHtmlizer()->render($note, $bodyTpl, 'note-post-email-body', $data, true); + } + + $email = $this->entityManager->getEntity('Email'); + + $email->set([ + 'subject' => $subject, + 'body' => $body, + 'isHtml' => true, + 'to' => $emailAddress, + 'isSystem' => true, + ]); + + if ($parentId && $parentType) { + $email->set([ + 'parentId' => $parentId, + 'parentType' => $parentType, + ]); + } + + $smtpParams = null; + + if ($parentId && $parentType && !empty($parent)) { + $handler = $this->getEmailNotificationEntityHandler($parentType); + + if ($handler) { + $prepareEmailMethodName = 'prepareEmail'; + + if (method_exists($handler, $prepareEmailMethodName)) { + $handler->$prepareEmailMethodName('notePost', $parent, $email, $user); + } + + $getSmtpParamsMethodName = 'getSmtpParams'; + + if (method_exists($handler, $getSmtpParamsMethodName)) { + $smtpParams = $handler->$getSmtpParamsMethodName('notePost', $parent, $user); + } + } + } + + $sender = $this->emailSender->create(); + + try { + if ($smtpParams) { + $sender->withSmtpParams($smtpParams); + } + + $sender->send($email); + } + catch (Exception $e) { + $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); + } + } + + protected function getSiteUrl(UserEntity $user) : string + { + $portal = null; + + if ($user->isPortal()) { + if (!array_key_exists($user->id, $this->userIdPortalCacheMap)) { + $this->userIdPortalCacheMap[$user->id] = null; + + $portalIdList = $user->getLinkMultipleIdList('portals'); + + $defaultPortalId = $this->config->get('defaultPortalId'); + + $portalId = null; + + if (in_array($defaultPortalId, $portalIdList)) { + $portalId = $defaultPortalId; + } + else if (count($portalIdList)) { + $portalId = $portalIdList[0]; + } + + if ($portalId) { + $portal = $this->entityManager->getEntity('Portal', $portalId); + + $this->entityManager->getRepository('Portal')->loadUrlField($portal); + + $this->userIdPortalCacheMap[$user->id] = $portal; + } + } + else { + $portal = $this->userIdPortalCacheMap[$user->id]; + } + + if ($portal) { + $url = $portal->get('url'); + + $url = rtrim($url, '/'); + + return $url; + } + } + + return $this->config->getSiteUrl(); + } + + protected function processNotificationNoteStatus($note, $user) : void + { + $parentId = $note->get('parentId'); + $parentType = $note->get('parentType'); + + $emailAddress = $user->get('emailAddress'); + + if (!$emailAddress) { + return; + } + + $data = []; + + if (!$parentId || !$parentType) { + return; + } + + $parent = $this->entityManager->getEntity($parentType, $parentId); + + if (!$parent) { + return; + } + + $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; + $data['parentName'] = $parent->get('name'); + $data['parentType'] = $parentType; + $data['parentId'] = $parentId; + + $data['name'] = $data['parentName']; + + $data['entityType'] = $this->language->translate($data['parentType'], 'scopeNames'); + $data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']); + + $noteData = $note->get('data'); + + if (empty($noteData)) { + return; + } + + $data['value'] = $noteData->value; + $data['field'] = $noteData->field; + $data['valueTranslated'] = $this->language->translateOption($data['value'], $data['field'], $parentType); + $data['fieldTranslated'] = $this->language->translate($data['field'], 'fields', $parentType); + $data['fieldTranslatedLowerCase'] = Util::mbLowerCaseFirst($data['fieldTranslated']); + + $data['userName'] = $note->get('createdByName'); + + $subjectTpl = $this->templateFileManager->getTemplate('noteStatus', 'subject', $parentType); + + $bodyTpl = $this->templateFileManager->getTemplate('noteStatus', 'body', $parentType); + + $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); + + $subject = $this->getHtmlizer()->render( + $note, $subjectTpl, 'note-status-email-subject', $data, true + ); + + $body = $this->getHtmlizer()->render( + $note, $bodyTpl, 'note-status-email-body', $data, true + ); + + $email = $this->entityManager->getEntity('Email'); + + $email->set([ + 'subject' => $subject, + 'body' => $body, + 'isHtml' => true, + 'to' => $emailAddress, + 'isSystem' => true, + 'parentId' => $parentId, + 'parentType' => $parentType, + ]); + + try { + $this->emailSender->send($email); + } + catch (Exception $e) { + $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); + } + } + + protected function processNotificationNoteEmailReceived($note, $user) : void + { + $parentId = $note->get('parentId'); + $parentType = $note->get('parentType'); + + $allowedEntityTypeList = $this->config->get('streamEmailNotificationsEmailReceivedEntityTypeList'); + + if ( + is_array($allowedEntityTypeList) + && + !in_array($parentType, $allowedEntityTypeList) + ) { + return; + } + + $emailAddress = $user->get('emailAddress'); + + if (!$emailAddress) { + return; + } + + $noteData = $note->get('data'); + + if (!($noteData instanceof StdClass)) { + return; + } + + if (!isset($noteData->emailId)) { + return; + } + + $email = $this->entityManager->getEntity('Email', $noteData->emailId); + + if (!$email) { + return; + } + + $emailRepository = $this->entityManager->getRepository('Email'); + $eaList = $user->get('emailAddresses'); + + foreach ($eaList as $ea) { + if ( + $emailRepository->isRelated($email, 'toEmailAddresses', $ea) + || + $emailRepository->isRelated($email, 'ccEmailAddresses', $ea) + ) { + return; + } + } + + $data = []; + + $data['fromName'] = ''; + + if (isset($noteData->personEntityName)) { + $data['fromName'] = $noteData->personEntityName; + } + else if (isset($noteData->fromString)) { + $data['fromName'] = $noteData->fromString; + } + + $data['subject'] = ''; + + if (isset($noteData->emailName)) { + $data['subject'] = $noteData->emailName; + } + + $data['post'] = nl2br($note->get('post')); + + if (!$parentId || !$parentType) { + return; + } + + $parent = $this->entityManager->getEntity($parentType, $parentId); + + if (!$parent) { + return; + } + + $data['url'] = $this->getSiteUrl($user) . '/#' . $parentType . '/view/' . $parentId; + $data['parentName'] = $parent->get('name'); + $data['parentType'] = $parentType; + $data['parentId'] = $parentId; + + $data['name'] = $data['parentName']; + + $data['entityType'] = $this->language->translate($data['parentType'], 'scopeNames'); + $data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']); + + $subjectTpl = $this->templateFileManager->getTemplate('noteEmailReceived', 'subject', $parentType); + + $bodyTpl = $this->templateFileManager->getTemplate('noteEmailReceived', 'body', $parentType); + + $subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl); + + $subject = $this->getHtmlizer()->render( + $note, $subjectTpl, 'note-email-received-email-subject-' . $parentType, $data, true + ); + + $body = $this->getHtmlizer()->render( + $note, $bodyTpl, 'note-email-received-email-body-' . $parentType, $data, true + ); + + $email = $this->entityManager->getEntity('Email'); + + $email->set([ + 'subject' => $subject, + 'body' => $body, + 'isHtml' => true, + 'to' => $emailAddress, + 'isSystem' => true, + ]); + + $email->set([ + 'parentId' => $parentId, + 'parentType' => $parentType + ]); + + try { + $this->emailSender->send($email); + } + catch (Exception $e) { + $GLOBALS['log']->error('EmailNotification: [' . $e->getCode() . '] ' .$e->getMessage()); + } + } + + protected function getHtmlizer() : Htmlizer + { + if (!$this->htmlizer) { + $this->htmlizer = $this->htmlizerFactory->create(true); + } + + return $this->htmlizer; + } +}