This commit is contained in:
Yuri Kuznetsov
2024-08-01 10:50:04 +03:00
parent e470bf4eb1
commit fde53deae6
2 changed files with 104 additions and 103 deletions
+37 -1
View File
@@ -30,11 +30,13 @@
namespace Espo\Entities;
use Espo\Core\Field\DateTime;
use Espo\Core\Field\LinkParent;
use Espo\Core\ORM\Entity;
use stdClass;
use LogicException;
class UniqueId extends \Espo\Core\ORM\Entity
class UniqueId extends Entity
{
public const ENTITY_TYPE = 'UniqueId';
@@ -65,4 +67,38 @@ class UniqueId extends \Espo\Core\ORM\Entity
return $value;
}
/**
* @param array<string, mixed>|stdClass $data
*/
public function setData(array|stdClass $data): self
{
$this->set('data', $data);
return $this;
}
public function setTarget(?LinkParent $target): self
{
if (!$target) {
$this->setMultiple([
'targetId' => null,
'targetType' => null,
]);
} else {
$this->setMultiple([
'targetId' => $target->getId(),
'targetType' => $target->getEntityType(),
]);
}
return $this;
}
public function setTerminateAt(?DateTime $terminateAt): self
{
$this->setValueObject('terminateAt', $terminateAt);
return $this;
}
}
@@ -29,13 +29,12 @@
namespace Espo\Modules\Crm\Business\Event;
use Espo\Core\Exceptions\Error;
use Espo\Core\Field\DateTime as DateTimeField;
use Espo\Core\Field\LinkParent;
use Espo\Core\Mail\Exceptions\SendingError;
use Espo\Entities\Attachment;
use Espo\Entities\Email;
use Espo\Entities\UniqueId;
use Laminas\Mail\Message;
use Espo\ORM\Entity;
use Espo\Entities\User;
use Espo\Core\Utils\Util;
@@ -45,9 +44,7 @@ use Espo\Core\Mail\SmtpParams;
use Espo\Core\ORM\EntityManager;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\DateTime as DateTimeUtil;
use Espo\Core\Utils\File\Manager as FileManager;
use Espo\Core\Utils\Language;
use Espo\Core\Utils\NumberUtil;
use Espo\Core\Utils\TemplateFileManager;
use DateTime;
@@ -57,47 +54,21 @@ class Invitations
private const TYPE_INVITATION = 'invitation';
private const TYPE_CANCELLATION = 'cancellation';
private $smtpParams;
private $entityManager;
private $emailSender;
private $config;
private $dateTime; /** @phpstan-ignore-line */
private $language;
private $number; /** @phpstan-ignore-line */
private $templateFileManager;
private $fileManager; /** @phpstan-ignore-line */
private $htmlizerFactory;
/**
* Some dependencies are unused to keep backward compatibility.
*/
public function __construct(
EntityManager $entityManager,
?SmtpParams $smtpParams,
EmailSender $emailSender,
Config $config,
FileManager $fileManager,
DateTimeUtil $dateTime,
NumberUtil $number,
Language $language,
TemplateFileManager $templateFileManager,
HtmlizerFactory $htmlizerFactory
) {
$this->entityManager = $entityManager;
$this->smtpParams = $smtpParams;
$this->emailSender = $emailSender;
$this->config = $config;
$this->dateTime = $dateTime;
$this->language = $language;
$this->number = $number;
$this->fileManager = $fileManager;
$this->templateFileManager = $templateFileManager;
$this->htmlizerFactory = $htmlizerFactory;
}
private EntityManager $entityManager,
private ?SmtpParams $smtpParams,
private EmailSender $emailSender,
private Config $config,
private Language $language,
private TemplateFileManager $templateFileManager,
private HtmlizerFactory $htmlizerFactory
) {}
/**
* @throws SendingError
* @throws Error
*/
public function sendInvitation(Entity $entity, Entity $invitee, string $link): void
{
@@ -106,7 +77,6 @@ class Invitations
/**
* @throws SendingError
* @throws Error
*/
public function sendCancellation(Entity $entity, Entity $invitee, string $link): void
{
@@ -115,7 +85,6 @@ class Invitations
/**
* @throws SendingError
* @throws Error
*/
private function sendInternal(
Entity $entity,
@@ -124,57 +93,30 @@ class Invitations
string $type = self::TYPE_INVITATION
): void {
$uid = $type === self::TYPE_INVITATION ?
$this->createUniqueId($entity, $invitee, $link) : null;
$uid = $type === self::TYPE_INVITATION ? $this->createUniqueId($entity, $invitee, $link) : null;
/** @var ?string $emailAddress */
$emailAddress = $invitee->get('emailAddress');
if (empty($emailAddress)) {
if (!$emailAddress) {
return;
}
/** @var Email $email */
$email = $this->entityManager->getNewEntity(Email::ENTITY_TYPE);
$htmlizer = $invitee instanceof User ?
$this->htmlizerFactory->createForUser($invitee) :
$this->htmlizerFactory->createNoAcl();
$email->set('to', $emailAddress);
$data = $this->prepareData($entity, $uid, $invitee);
$subjectTpl = $this->templateFileManager->getTemplate($type, 'subject', $entity->getEntityType(), 'Crm');
$bodyTpl = $this->templateFileManager->getTemplate($type, 'body', $entity->getEntityType(), 'Crm');
$subjectTpl = str_replace(["\n", "\r"], '', $subjectTpl);
$data = [];
$siteUrl = rtrim($this->config->get('siteUrl'), '/');
$recordUrl = $siteUrl . '/#' . $entity->getEntityType() . '/view/' . $entity->getId();
$data['recordUrl'] = $recordUrl;
if ($uid) {
$part = $siteUrl . '?entryPoint=eventConfirmation&action=';
$data['acceptLink'] = $part . 'accept&uid=' . $uid->getIdValue();
$data['declineLink'] = $part . 'decline&uid=' . $uid->getIdValue();
$data['tentativeLink'] = $part . 'tentative&uid=' . $uid->getIdValue();
}
if ($invitee instanceof User) {
$data['isUser'] = true;
$htmlizer = $this->htmlizerFactory->createForUser($invitee);
}
else {
$htmlizer = $this->htmlizerFactory->createNoAcl();
}
$data['inviteeName'] = $invitee->get('name');
$data['entityType'] = $this->language->translateLabel($entity->getEntityType(), 'scopeNames');
$data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']);
$bodyTpl = $this->templateFileManager->getTemplate($type, 'body', $entity->getEntityType(), 'Crm');
$subject = $htmlizer->render(
$entity,
$subjectTpl,
$type . '-email-subject-' . $entity->getEntityType(),
"$type-email-subject-{$entity->getEntityType()}",
$data,
true,
true
@@ -183,28 +125,28 @@ class Invitations
$body = $htmlizer->render(
$entity,
$bodyTpl,
$type . '-email-body-' . $entity->getEntityType(),
"$type-email-body-{$entity->getEntityType()}",
$data,
false,
true
);
$email->set('subject', $subject);
$email->set('body', $body);
$email->set('isHtml', true);
$email = $this->entityManager->getRDBRepositoryByClass(Email::class)->getNew();
$email
->addToAddress($emailAddress)
->setSubject($subject)
->setBody($body)
->setIsHtml();
$attachmentName = ucwords($this->language->translateLabel($entity->getEntityType(), 'scopeNames')) . '.ics';
/** @var Attachment $attachment */
$attachment = $this->entityManager->getNewEntity(Attachment::ENTITY_TYPE);
$attachment = $this->entityManager->getRDBRepositoryByClass(Attachment::class)->getNew();
$attachment->set([
'name' => $attachmentName,
'type' => 'text/calendar',
'contents' => $this->getIcsContents($entity, $type),
]);
$message = new Message();
$attachment
->setName($attachmentName)
->setType('text/calendar')
->setContents($this->getIcsContents($entity, $type));
$sender = $this->emailSender->create();
@@ -213,17 +155,15 @@ class Invitations
}
$sender
->withMessage($message)
->withAttachments([$attachment])
->send($email);
}
private function createUniqueId(Entity $entity, Entity $invitee, string $link): UniqueId
{
/** @var UniqueId $uid */
$uid = $this->entityManager->getNewEntity(UniqueId::ENTITY_TYPE);
$uid = $this->entityManager->getRDBRepositoryByClass(UniqueId::class)->getNew();
$uid->set('data', [
$uid->setData([
'eventType' => $entity->getEntityType(),
'eventId' => $entity->getId(),
'inviteeId' => $invitee->getId(),
@@ -234,19 +174,15 @@ class Invitations
if ($entity->get('dateEnd')) {
$terminateAt = $entity->get('dateEnd');
}
else {
} else {
$dt = new DateTime();
$dt->modify('+1 month');
$terminateAt = $dt->format(DateTimeUtil::SYSTEM_DATE_TIME_FORMAT);
}
$uid->set([
'targetId' => $entity->getId(),
'targetType' => $entity->getEntityType(),
'terminateAt' => $terminateAt,
]);
$uid->setTarget(LinkParent::createFromEntity($entity));
$uid->setTerminateAt(DateTimeField::fromString($terminateAt));
$this->entityManager->saveEntity($uid);
@@ -257,7 +193,6 @@ class Invitations
{
/** @var ?User $user */
$user = $this->entityManager
->getRDBRepository($entity->getEntityType())
->getRelation($entity, 'assignedUser')
->findOne();
@@ -291,4 +226,34 @@ class Invitations
return $ics->get();
}
/**
* @return array<string, mixed>
*/
private function prepareData(Entity $entity, ?UniqueId $uid, Entity $invitee): array
{
$data = [];
$siteUrl = rtrim($this->config->get('siteUrl'), '/');
$data['recordUrl'] = "$siteUrl/#{$entity->getEntityType()}/view/{$entity->getId()}";
if ($uid) {
$part = "$siteUrl?entryPoint=eventConfirmation&action=";
$data['acceptLink'] = $part . 'accept&uid=' . $uid->getIdValue();
$data['declineLink'] = $part . 'decline&uid=' . $uid->getIdValue();
$data['tentativeLink'] = $part . 'tentative&uid=' . $uid->getIdValue();
}
if ($invitee instanceof User) {
$data['isUser'] = true;
}
$data['inviteeName'] = $invitee->get('name');
$data['entityType'] = $this->language->translateLabel($entity->getEntityType(), 'scopeNames');
$data['entityTypeLowerFirst'] = Util::mbLowerCaseFirst($data['entityType']);
return $data;
}
}