This commit is contained in:
Yuri Kuznetsov
2022-10-18 17:13:56 +03:00
parent 07ee43d4d7
commit d6dc858720
7 changed files with 164 additions and 56 deletions

View File

@@ -31,17 +31,24 @@ namespace Espo\Controllers;
use Espo\Core\Exceptions\BadRequest;
use Espo\Services\EmailTemplate as Service;
use Espo\Core\Exceptions\ForbiddenSilent;
use Espo\Core\Exceptions\NotFound;
use Espo\Tools\EmailTemplate\Data;
use Espo\Tools\EmailTemplate\Service;
use Espo\Core\{
Controllers\Record,
Api\Request,
};
use Espo\Core\Api\Request;
use Espo\Core\Controllers\Record;
use stdClass;
class EmailTemplate extends Record
{
/**
* @throws BadRequest
* @throws NotFound
* @throws ForbiddenSilent
*/
public function actionParse(Request $request): stdClass
{
$id = $request->getQueryParam('id');
@@ -50,22 +57,21 @@ class EmailTemplate extends Record
throw new BadRequest("No `id`.");
}
return (object) $this->getEmailTempalteService()->parse(
$id,
[
'emailAddress' => $request->getQueryParam('emailAddress'),
'parentType' => $request->getQueryParam('parentType'),
'parentId' => $request->getQueryParam('parentId'),
'relatedType' => $request->getQueryParam('relatedType'),
'relatedId' => $request->getQueryParam('relatedId'),
],
true
);
$data = Data::create()
->withRelatedType($request->getQueryParam('relatedType'))
->withRelatedId($request->getQueryParam('relatedId'))
->withParentType($request->getQueryParam('parentType'))
->withParentId($request->getQueryParam('parentId'))
->withEmailAddress($request->getQueryParam('emailAddress'));
$result = $this->getEmailTemplateService()->process($id, $data);
return $result->getValueMap();
}
private function getEmailTempalteService(): Service
private function getEmailTemplateService(): Service
{
/** @var Service */
return $this->getRecordService();
return $this->injectableFactory->create(Service::class);
}
}

View File

@@ -36,6 +36,9 @@ use Espo\Core\Templates\Entities\Person;
use Espo\Modules\Crm\Entities\Contact;
use Espo\Modules\Crm\Entities\Lead;
use Espo\Tools\Email\Util;
use Espo\Tools\EmailTemplate\Data as EmailTemplateData;
use Espo\Tools\EmailTemplate\Params as EmailTemplateParams;
use Espo\Tools\EmailTemplate\Service as EmailTemplateService;
use Laminas\Mail\Message;
use Espo\Core\Mail\Account\Account;
@@ -46,11 +49,9 @@ use Espo\Core\Mail\EmailSender;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\DateTime as DateTimeUtil;
use Espo\Core\InjectableFactory;
use Espo\Core\Utils\Log;
use Espo\Tools\Stream\Service as StreamService;
use Espo\Services\EmailTemplate as EmailTemplateService;
use Espo\Entities\InboundEmail;
use Espo\Entities\Email;
@@ -77,7 +78,6 @@ class AfterFetch implements AfterFetchInterface
private StreamService $streamService;
private Config $config;
private EmailSender $emailSender;
private InjectableFactory $injectableFactory;
private Log $log;
private RoundRobin $roundRobin;
private LeastBusy $leastBusy;
@@ -85,27 +85,28 @@ class AfterFetch implements AfterFetchInterface
private const DEFAULT_AUTOREPLY_LIMIT = 5;
private const DEFAULT_AUTOREPLY_SUPPRESS_PERIOD = '2 hours';
private GroupAccountFactory $groupAccountFactory;
private EmailTemplateService $emailTemplateService;
public function __construct(
EntityManager $entityManager,
StreamService $streamService,
Config $config,
EmailSender $emailSender,
InjectableFactory $injectableFactory,
Log $log,
RoundRobin $roundRobin,
LeastBusy $leastBusy,
GroupAccountFactory $groupAccountFactory
GroupAccountFactory $groupAccountFactory,
EmailTemplateService $emailTemplateService
) {
$this->entityManager = $entityManager;
$this->streamService = $streamService;
$this->config = $config;
$this->emailSender = $emailSender;
$this->injectableFactory = $injectableFactory;
$this->log = $log;
$this->roundRobin = $roundRobin;
$this->leastBusy = $leastBusy;
$this->groupAccountFactory = $groupAccountFactory;
$this->emailTemplateService = $emailTemplateService;
}
public function process(Account $account, Email $email, BeforeFetchResult $beforeFetchResult): void
@@ -269,27 +270,29 @@ class AfterFetch implements AfterFetchInterface
$entityHash[User::ENTITY_TYPE] = $user;
}
$emailTemplateService = $this->getEmailTemplateService();
$replyData = $emailTemplateService->parse(
$replyData = $this->emailTemplateService->process(
$replyEmailTemplateId,
['entityHash' => $entityHash],
true
EmailTemplateData::create()
->withEntityHash($entityHash),
EmailTemplateParams::create()
->withApplyAcl(false)
->withCopyAttachments(true)
);
$subject = $replyData['subject'];
$subject = $replyData->getSubject();
if ($case) {
$subject = '[#' . $case->get('number'). '] ' . $subject;
}
/** @var Email $reply */
$reply = $this->entityManager->getRDBRepositoryByClass(Email::class)->getNew();
$reply->set('to', $fromAddress);
$reply->set('subject', $subject);
$reply->set('body', $replyData['body']);
$reply->set('isHtml', $replyData['isHtml']);
$reply->set('attachmentsIds', $replyData['attachmentsIds']);
$reply
->addToAddress($fromAddress)
->setSubject($subject)
->setBody($replyData->getBody())
->setIsHtml($replyData->isHtml());
if ($email->has('teamsIds')) {
$reply->set('teamsIds', $email->get('teamsIds'));
@@ -335,6 +338,7 @@ class AfterFetch implements AfterFetchInterface
$sender
->withParams($senderParams)
->withMessage($message)
->withAttachments($replyData->getAttachmentList())
->send($reply);
$this->entityManager->saveEntity($reply);
@@ -344,12 +348,6 @@ class AfterFetch implements AfterFetchInterface
}
}
private function getEmailTemplateService(): EmailTemplateService
{
/** @var EmailTemplateService */
return $this->injectableFactory->create(EmailTemplateService::class);
}
private function createCase(GroupAccount $account, Email $email): void
{
$inboundEmail = $account->getEntity();

View File

@@ -170,6 +170,9 @@ class Email extends Entity
$this->get('createdById') !== ApplicationUser::SYSTEM_USER_ID;
}
/**
* @todo Revise.
*/
public function addAttachment(Attachment $attachment): void
{
if (!$this->id) {

View File

@@ -29,6 +29,7 @@
namespace Espo\Services;
use Espo\Core\Exceptions\Forbidden;
use Espo\Repositories\EmailAddress as EmailAddressRepository;
use Espo\Tools\EmailTemplate\Processor;
@@ -46,6 +47,8 @@ use Espo\Core\Di;
use stdClass;
/**
* @deprecated For bc. Use `Espo\Tools\EmailTemplate\Service`.
*
* @extends Record<\Espo\Entities\EmailTemplate>
*/
class EmailTemplate extends Record implements
@@ -55,6 +58,8 @@ class EmailTemplate extends Record implements
use Di\FieldUtilSetter;
/**
* @deprecated For bc. Use `Espo\Tools\EmailTemplate\Processor`.
*
* @param array<string,mixed> $params
* @return array{
* subject: string,
@@ -99,9 +104,11 @@ class EmailTemplate extends Record implements
}
/**
* @deprecated For bc. Use `Espo\Tools\EmailTemplate\Service`.
*
* @param array<string,mixed> $params
* @return array<string,mixed>
* @throws \Espo\Core\Exceptions\ForbiddenSilent
* @throws Forbidden
* @throws NotFound
*/
public function parse(string $id, array $params = [], bool $copyAttachments = false): array

View File

@@ -30,28 +30,18 @@
namespace Espo\Tools\EmailTemplate;
use Espo\ORM\Entity;
use Espo\Entities\User;
class Data
{
/**
* @var array<string,Entity>
*/
/** @var array<string, Entity> */
private $entityHash = [];
private ?string $emailAddress = null;
private ?Entity $parent = null;
private ?string $parentId = null;
private ?string $parentType = null;
private ?string $relatedId = null;
private ?string $relatedType = null;
private ?User $user = null;
/**

View File

@@ -141,6 +141,13 @@ class Processor
$service->loadAdditionalFields($parent);
if (
$params->applyAcl() &&
!$this->aclManager->checkEntityRead($this->user, $parent)
) {
$parent = null;
}
$data = $data->withParent($parent);
}
}
@@ -159,6 +166,14 @@ class Processor
if ($data->getRelatedId() && $data->getRelatedType()) {
$related = $this->entityManager->getEntity($data->getRelatedType(), $data->getRelatedId());
if (
$related &&
$params->applyAcl() &&
!$this->aclManager->checkEntityRead($this->user, $related)
) {
$related = null;
}
if ($related) {
$entityHash[$related->getEntityType()] = $related;
}
@@ -169,8 +184,6 @@ class Processor
$parent = $entityHash[self::KEY_PARENT] ?? null;
$htmlizer = null;
if ($parent && !$this->config->get('emailTemplateHtmlizerDisabled')) {
$handlebarsInSubject = strpos($subject, '{{') !== false && strpos($subject, '}}') !== false;
$handlebarsInBody = strpos($body, '{{') !== false && strpos($body, '}}') !== false;

View File

@@ -0,0 +1,91 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* 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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\EmailTemplate;
use Espo\Core\Acl;
use Espo\Core\Exceptions\ForbiddenSilent;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Record\ServiceContainer;
use Espo\Entities\EmailTemplate;
use Espo\Entities\User;
use Espo\ORM\EntityManager;
class Service
{
private Processor $processor;
private User $user;
private Acl $acl;
private EntityManager $entityManager;
public function __construct(
Processor $processor,
User $user,
Acl $acl,
EntityManager $entityManager
) {
$this->processor = $processor;
$this->user = $user;
$this->acl = $acl;
$this->entityManager = $entityManager;
}
/**
* Prepare an email data with an applied template.
*
* @throws NotFound
* @throws ForbiddenSilent
*/
public function process(string $emailTemplateId, Data $data, ?Params $params = null): Result
{
/** @var ?EmailTemplate $emailTemplate */
$emailTemplate = $this->entityManager->getEntityById(EmailTemplate::ENTITY_TYPE, $emailTemplateId);
if (!$emailTemplate) {
throw new NotFound();
}
$params ??= Params::create()
->withApplyAcl(true)
->withCopyAttachments(true);
if (
$params->applyAcl() &&
!$this->acl->checkEntityRead($emailTemplate)
) {
throw new ForbiddenSilent();
}
if (!$data->getUser()) {
$data = $data->withUser($this->user);
}
return $this->processor->process($emailTemplate, $params, $data);
}
}