Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\EmailBundle\Model;
|
||||
|
||||
use Mautic\CategoryBundle\Entity\Category;
|
||||
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
|
||||
use Mautic\EmailBundle\Entity\Email;
|
||||
use Mautic\EmailBundle\Entity\EmailRepository;
|
||||
|
||||
class EmailActionModel
|
||||
{
|
||||
public function __construct(
|
||||
private EmailModel $emailModel,
|
||||
private EmailRepository $emailRepository,
|
||||
private CorePermissions $corePermissions,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int> $emailsIds
|
||||
*
|
||||
* @return array<Email>
|
||||
*/
|
||||
public function setCategory(array $emailsIds, Category $newCategory): array
|
||||
{
|
||||
$emails = $this->emailRepository->findBy(['id' => $emailsIds]);
|
||||
|
||||
$affected = [];
|
||||
|
||||
foreach ($emails as $email) {
|
||||
if (!$this->canEdit($email)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$email->setCategory($newCategory);
|
||||
$affected[] = $email;
|
||||
}
|
||||
|
||||
if ($affected) {
|
||||
$this->saveEntities($emails);
|
||||
}
|
||||
|
||||
return $affected;
|
||||
}
|
||||
|
||||
private function canEdit(Email $email): bool
|
||||
{
|
||||
return $this->corePermissions->hasEntityAccess('email:emails:editown', 'email:emails:editother', $email->getCreatedBy());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Email> $emails
|
||||
*/
|
||||
private function saveEntities(array $emails): void
|
||||
{
|
||||
$this->emailModel->saveEntities($emails);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\EmailBundle\Model;
|
||||
|
||||
use Mautic\CoreBundle\Model\AbstractCommonModel;
|
||||
use Mautic\EmailBundle\Entity\Email;
|
||||
use Mautic\EmailBundle\Entity\EmailDraft;
|
||||
use Mautic\EmailBundle\Entity\EmailDraftRepository;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class EmailDraftModel extends AbstractCommonModel
|
||||
{
|
||||
public function createDraft(Email $email, string $html, string $template, bool $publicPreview = true): EmailDraft
|
||||
{
|
||||
$emailDraft = $this->getRepository()->findOneBy(['email' => $email]);
|
||||
if (!is_null($emailDraft)) {
|
||||
throw new \Exception(sprintf('Draft already exists for email %d', $email->getId()));
|
||||
}
|
||||
$emailDraft = new EmailDraft($email, $html, $template, $publicPreview);
|
||||
|
||||
$this->em->persist($emailDraft);
|
||||
$this->em->flush();
|
||||
|
||||
return $emailDraft;
|
||||
}
|
||||
|
||||
public function deleteDraft(Email $email): void
|
||||
{
|
||||
if (is_null($emailDraft = $email->getDraft())) {
|
||||
throw new NotFoundHttpException(sprintf('Draft not found for email %d', $email->getId()));
|
||||
}
|
||||
$this->em->remove($emailDraft);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
public function getPermissionBase(): string
|
||||
{
|
||||
return 'email:emails';
|
||||
}
|
||||
|
||||
public function getRepository(): EmailDraftRepository
|
||||
{
|
||||
return $this->em->getRepository(EmailDraft::class);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\EmailBundle\Model;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Mautic\EmailBundle\EmailEvents;
|
||||
use Mautic\EmailBundle\Entity\Stat;
|
||||
use Mautic\EmailBundle\Entity\StatRepository;
|
||||
use Mautic\EmailBundle\Event\EmailStatEvent;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class EmailStatModel
|
||||
{
|
||||
public function __construct(private EntityManagerInterface $entityManager, private EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
}
|
||||
|
||||
public function saveEntity(Stat $stat): void
|
||||
{
|
||||
$this->saveEntities([$stat]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stat[] $stats
|
||||
*/
|
||||
public function saveEntities(array $stats): void
|
||||
{
|
||||
$event = new EmailStatEvent($stats);
|
||||
|
||||
$this->dispatcher->dispatch($event, EmailEvents::ON_EMAIL_STAT_PRE_SAVE);
|
||||
|
||||
$this->getRepository()->saveEntities($stats);
|
||||
|
||||
$this->dispatcher->dispatch($event, EmailEvents::ON_EMAIL_STAT_POST_SAVE);
|
||||
}
|
||||
|
||||
public function getRepository(): StatRepository
|
||||
{
|
||||
return $this->entityManager->getRepository(Stat::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Model;
|
||||
|
||||
use Mautic\EmailBundle\Entity\Email;
|
||||
use Mautic\EmailBundle\Exception\FailedToSendToContactException;
|
||||
use Mautic\EmailBundle\Helper\MailHelper;
|
||||
use Mautic\EmailBundle\Mailer\Exception\BatchQueueMaxException;
|
||||
use Mautic\EmailBundle\Stat\Exception\StatNotFoundException;
|
||||
use Mautic\EmailBundle\Stat\Reference;
|
||||
use Mautic\EmailBundle\Stat\StatHelper;
|
||||
use Mautic\LeadBundle\Entity\DoNotContact as DNC;
|
||||
use Mautic\LeadBundle\Model\DoNotContact;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class SendEmailToContact
|
||||
{
|
||||
private array $failedContacts = [];
|
||||
|
||||
private array $errorMessages = [];
|
||||
|
||||
private array $badEmails = [];
|
||||
|
||||
private array $emailSentCounts = [];
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $emailEntityErrors;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $emailEntityId;
|
||||
|
||||
private ?int $listId = null;
|
||||
|
||||
private int $statBatchCounter = 0;
|
||||
|
||||
private array $contact = [];
|
||||
|
||||
public function __construct(
|
||||
private MailHelper $mailer,
|
||||
private StatHelper $statHelper,
|
||||
private DoNotContact $dncModel,
|
||||
private TranslatorInterface $translator,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $resetMailer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function flush($resetMailer = true)
|
||||
{
|
||||
// Flushes the batch in case of using API mailers
|
||||
if ($this->emailEntityId && !$flushResult = $this->mailer->flushQueue()) {
|
||||
$sendFailures = $this->mailer->getErrors();
|
||||
|
||||
// Check to see if failed recipients were stored by the transport
|
||||
if (!empty($sendFailures['failures'])) {
|
||||
$this->processSendFailures($sendFailures);
|
||||
}
|
||||
}
|
||||
|
||||
if ($resetMailer) {
|
||||
$this->mailer->reset(true);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any remaining queued contacts, process spending stats, create DNC entries and reset this class.
|
||||
*/
|
||||
public function finalFlush(): void
|
||||
{
|
||||
$this->flush();
|
||||
$this->statHelper->deletePending();
|
||||
$this->statHelper->reset();
|
||||
|
||||
$this->processBadEmails();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use an Email entity to populate content, from, etc.
|
||||
*
|
||||
* @param array $channel ['channelName', 'channelId']
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setEmail(Email $email, array $channel = [], array $customHeaders = [], array $assetAttachments = [], ?string $emailType = null)
|
||||
{
|
||||
// Flush anything that's pending from a previous email
|
||||
$this->flush();
|
||||
|
||||
// Enable the queue if applicable to the transport
|
||||
$this->mailer->enableQueue();
|
||||
|
||||
if ($this->mailer->setEmail($email, true, $assetAttachments)) {
|
||||
$this->mailer->setEmailType($emailType);
|
||||
$this->mailer->setSource($channel);
|
||||
$this->mailer->setCustomHeaders($customHeaders);
|
||||
|
||||
// Note that the entity is set so that addContact does not generate errors
|
||||
$this->emailEntityId = $email->getId();
|
||||
} else {
|
||||
// Fail all the contacts in this batch
|
||||
$this->emailEntityErrors = $this->mailer->getErrors();
|
||||
$this->emailEntityId = null;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $id
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setListId($id)
|
||||
{
|
||||
$this->listId = empty($id) ? null : (int) $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*
|
||||
* @throws FailedToSendToContactException
|
||||
*/
|
||||
public function setContact(array $contact, array $tokens = [])
|
||||
{
|
||||
$this->contact = $contact;
|
||||
|
||||
if (!$this->emailEntityId) {
|
||||
// There was an error configuring the email so auto fail
|
||||
$this->failContact(false, $this->emailEntityErrors);
|
||||
}
|
||||
|
||||
$this->mailer->setTokens($tokens);
|
||||
$this->mailer->setLead($contact);
|
||||
$this->mailer->setIdHash(); // auto generates
|
||||
|
||||
try {
|
||||
if (!$this->mailer->addTo($contact['email'], $contact['firstname'].' '.$contact['lastname'])) {
|
||||
$this->failContact();
|
||||
}
|
||||
} catch (BatchQueueMaxException) {
|
||||
// Queue full so flush then try again
|
||||
$this->flush(false);
|
||||
|
||||
if (!$this->mailer->addTo($contact['email'], $contact['firstname'].' '.$contact['lastname'])) {
|
||||
$this->failContact();
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FailedToSendToContactException
|
||||
*/
|
||||
public function send(): void
|
||||
{
|
||||
if ($this->mailer->inTokenizationMode()) {
|
||||
[$success, $errors] = $this->queueTokenizedEmail();
|
||||
} else {
|
||||
[$success, $errors] = $this->sendStandardEmail();
|
||||
}
|
||||
|
||||
// queue or send the message
|
||||
if (!$success) {
|
||||
unset($errors['failures']);
|
||||
$this->failContact(false, implode('; ', (array) $errors));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset everything.
|
||||
*/
|
||||
public function reset(): void
|
||||
{
|
||||
$this->badEmails = [];
|
||||
$this->errorMessages = [];
|
||||
$this->failedContacts = [];
|
||||
$this->emailEntityErrors = null;
|
||||
$this->emailEntityId = null;
|
||||
$this->emailSentCounts = [];
|
||||
$this->listId = null;
|
||||
$this->statBatchCounter = 0;
|
||||
$this->contact = [];
|
||||
|
||||
$this->mailer->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSentCounts()
|
||||
{
|
||||
return $this->emailSentCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errorMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFailedContacts()
|
||||
{
|
||||
return $this->failedContacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $hasBadEmail
|
||||
* @param array $errorMessages
|
||||
*
|
||||
* @throws FailedToSendToContactException
|
||||
*/
|
||||
protected function failContact($hasBadEmail = true, $errorMessages = null)
|
||||
{
|
||||
if (null === $errorMessages) {
|
||||
// Clear the errors so it doesn't stop the next send
|
||||
$errorMessages = implode('; ', (array) $this->mailer->getErrors());
|
||||
} elseif (is_array($errorMessages)) {
|
||||
$errorMessages = implode('; ', $errorMessages);
|
||||
}
|
||||
|
||||
$this->errorMessages[$this->contact['id']] = $errorMessages;
|
||||
$this->failedContacts[$this->contact['id']] = $this->contact['email'];
|
||||
|
||||
try {
|
||||
$stat = $this->statHelper->getStat($this->contact['email']);
|
||||
$this->downEmailSentCount($stat->getEmailId());
|
||||
$this->statHelper->markForDeletion($stat);
|
||||
} catch (StatNotFoundException) {
|
||||
}
|
||||
|
||||
if ($hasBadEmail) {
|
||||
$this->badEmails[$this->contact['id']] = $this->contact['email'];
|
||||
}
|
||||
|
||||
throw new FailedToSendToContactException($errorMessages);
|
||||
}
|
||||
|
||||
protected function processSendFailures($sendFailures)
|
||||
{
|
||||
$failedEmailAddresses = $sendFailures['failures'];
|
||||
unset($sendFailures['failures']);
|
||||
$error = implode('; ', $sendFailures);
|
||||
|
||||
// Delete the stat
|
||||
foreach ($failedEmailAddresses as $failedEmail) {
|
||||
try {
|
||||
/** @var Reference $stat */
|
||||
$stat = $this->statHelper->getStat($failedEmail);
|
||||
} catch (StatNotFoundException) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add lead ID to list of failures
|
||||
$this->failedContacts[$stat->getLeadId()] = $failedEmail;
|
||||
$this->errorMessages[$stat->getLeadId()] = $error;
|
||||
|
||||
$this->statHelper->markForDeletion($stat);
|
||||
|
||||
// Down sent counts
|
||||
$this->downEmailSentCount($stat->getEmailId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add DNC entries for bad emails to get them out of the queue permanently.
|
||||
*/
|
||||
protected function processBadEmails()
|
||||
{
|
||||
// Update bad emails as bounces
|
||||
if (count($this->badEmails)) {
|
||||
foreach ($this->badEmails as $contactId => $contactEmail) {
|
||||
$this->dncModel->addDncForContact(
|
||||
$contactId,
|
||||
['email' => $this->emailEntityId],
|
||||
DNC::BOUNCED,
|
||||
$this->translator->trans('mautic.email.bounce.reason.bad_email'),
|
||||
true,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function createContactStatEntry($email)
|
||||
{
|
||||
++$this->statBatchCounter;
|
||||
|
||||
$stat = $this->mailer->createEmailStat(false, null, $this->listId);
|
||||
|
||||
// Store it in the statEntities array so that the stat can be deleted if the transport fails the
|
||||
// send for whatever reason after flushing the queue
|
||||
$this->statHelper->storeStat($stat, $email);
|
||||
|
||||
$this->upEmailSentCount($stat->getEmail()->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Up sent counter for the given email ID.
|
||||
*/
|
||||
protected function upEmailSentCount($emailId)
|
||||
{
|
||||
// Up sent counts
|
||||
if (!isset($this->emailSentCounts[$emailId])) {
|
||||
$this->emailSentCounts[$emailId] = 0;
|
||||
}
|
||||
|
||||
++$this->emailSentCounts[$emailId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Down sent counter for the given email ID.
|
||||
*/
|
||||
protected function downEmailSentCount($emailId)
|
||||
{
|
||||
--$this->emailSentCounts[$emailId];
|
||||
}
|
||||
|
||||
protected function queueTokenizedEmail(): array
|
||||
{
|
||||
[$queued, $queueErrors] = $this->mailer->queue(true, MailHelper::QUEUE_RETURN_ERRORS);
|
||||
|
||||
if ($queued) {
|
||||
// Create stat first to ensure it is available for emails sent immediately
|
||||
$this->createContactStatEntry($this->contact['email']);
|
||||
}
|
||||
|
||||
return [$queued, $queueErrors];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function sendStandardEmail()
|
||||
{
|
||||
// Dispatch the event to generate the tokens
|
||||
$this->mailer->dispatchSendEvent();
|
||||
|
||||
// Create the stat to ensure it is available for emails sent
|
||||
$this->createContactStatEntry($this->contact['email']);
|
||||
|
||||
// Now send but don't redispatch the event
|
||||
return $this->mailer->queue(false, MailHelper::QUEUE_RETURN_ERRORS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Model;
|
||||
|
||||
use Doctrine\ORM\ORMException;
|
||||
use Mautic\CoreBundle\Event\TokenReplacementEvent;
|
||||
use Mautic\CoreBundle\Exception\InvalidValueException;
|
||||
use Mautic\CoreBundle\Exception\RecordException;
|
||||
use Mautic\CoreBundle\Helper\ArrayHelper;
|
||||
use Mautic\EmailBundle\EmailEvents;
|
||||
use Mautic\EmailBundle\Exception\EmailCouldNotBeSentException;
|
||||
use Mautic\EmailBundle\Exception\InvalidEmailException;
|
||||
use Mautic\EmailBundle\Helper\EmailValidator;
|
||||
use Mautic\EmailBundle\OptionsAccessor\EmailToUserAccessor;
|
||||
use Mautic\LeadBundle\DataObject\ContactFieldToken;
|
||||
use Mautic\LeadBundle\Entity\Lead;
|
||||
use Mautic\LeadBundle\Exception\InvalidContactFieldTokenException;
|
||||
use Mautic\LeadBundle\Validator\CustomFieldValidator;
|
||||
use Mautic\UserBundle\Hash\UserHash;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class SendEmailToUser
|
||||
{
|
||||
public function __construct(
|
||||
private EmailModel $emailModel,
|
||||
private EventDispatcherInterface $dispatcher,
|
||||
private CustomFieldValidator $customFieldValidator,
|
||||
private EmailValidator $emailValidator,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws EmailCouldNotBeSentException
|
||||
* @throws ORMException
|
||||
*/
|
||||
public function sendEmailToUsers(array $config, Lead $lead): void
|
||||
{
|
||||
$emailToUserAccessor = new EmailToUserAccessor($config);
|
||||
|
||||
$email = $this->emailModel->getEntity($emailToUserAccessor->getEmailID());
|
||||
|
||||
if (!$email || !$email->isPublished()) {
|
||||
throw new EmailCouldNotBeSentException('Email not found or published');
|
||||
}
|
||||
|
||||
$leadCredentials = $lead->getProfileFields();
|
||||
|
||||
$to = ArrayHelper::removeEmptyValues($this->replaceTokens($emailToUserAccessor->getToFormatted(), $lead));
|
||||
$cc = ArrayHelper::removeEmptyValues($this->replaceTokens($emailToUserAccessor->getCcFormatted(), $lead));
|
||||
$bcc = ArrayHelper::removeEmptyValues($this->replaceTokens($emailToUserAccessor->getBccFormatted(), $lead));
|
||||
|
||||
$users = $emailToUserAccessor->getUserIdsToSend($lead->getOwner());
|
||||
$idHash = UserHash::getFakeUserHash();
|
||||
$tokens = $this->emailModel->dispatchEmailSendEvent($email, $leadCredentials, $idHash)->getTokens();
|
||||
$errors = $this->emailModel->sendEmailToUser($email, $users, $leadCredentials, $tokens, [], false, $to, $cc, $bcc);
|
||||
|
||||
if ($errors) {
|
||||
throw new EmailCouldNotBeSentException(implode(', ', $errors));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $emailAddressesOrTokens
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function replaceTokens(array $emailAddressesOrTokens, Lead $lead): array
|
||||
{
|
||||
return array_map($this->makeTokenReplacerCallback($lead), $emailAddressesOrTokens);
|
||||
}
|
||||
|
||||
private function makeTokenReplacerCallback(Lead $lead): callable
|
||||
{
|
||||
return function (string $emailAddressOrToken) use ($lead): string {
|
||||
try {
|
||||
$contactFieldToken = new ContactFieldToken($emailAddressOrToken);
|
||||
} catch (InvalidContactFieldTokenException) {
|
||||
try {
|
||||
$this->emailValidator->validate($emailAddressOrToken);
|
||||
|
||||
return $emailAddressOrToken;
|
||||
} catch (InvalidEmailException) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// The values are validated on form save.
|
||||
// But ensure the custom field is still valid on email send before asking for the replacement value.
|
||||
try {
|
||||
// Validate that the contact field exists and is type of email.
|
||||
$this->customFieldValidator->validateFieldType($contactFieldToken->getFieldAlias(), 'email');
|
||||
|
||||
return $this->replaceToken($contactFieldToken->getFullToken(), $lead);
|
||||
} catch (InvalidValueException|RecordException) {
|
||||
// If the field does not exist or is not type of email then use the default value.
|
||||
return (string) $contactFieldToken->getDefaultValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private function replaceToken(string $token, Lead $lead): string
|
||||
{
|
||||
$tokenEvent = new TokenReplacementEvent($token, $lead);
|
||||
$this->dispatcher->dispatch($tokenEvent, EmailEvents::ON_EMAIL_ADDRESS_TOKEN_REPLACEMENT);
|
||||
|
||||
return $tokenEvent->getContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\EmailBundle\Model;
|
||||
|
||||
use Mautic\CoreBundle\Helper\DateTimeHelper;
|
||||
use Mautic\EmailBundle\Entity\Stat;
|
||||
use Mautic\EmailBundle\MonitoredEmail\Search\ContactFinder;
|
||||
use Mautic\LeadBundle\Entity\DoNotContact as DNC;
|
||||
use Mautic\LeadBundle\Model\DoNotContact;
|
||||
|
||||
class TransportCallback
|
||||
{
|
||||
public function __construct(
|
||||
private DoNotContact $dncModel,
|
||||
private ContactFinder $finder,
|
||||
private EmailStatModel $emailStatModel,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hashId
|
||||
* @param string $comments
|
||||
* @param int $dncReason
|
||||
*/
|
||||
public function addFailureByHashId($hashId, $comments, $dncReason = DNC::BOUNCED): void
|
||||
{
|
||||
$result = $this->finder->findByHash($hashId);
|
||||
|
||||
if ($contacts = $result->getContacts()) {
|
||||
$stat = $result->getStat();
|
||||
$this->updateStatDetails($stat, $comments, $dncReason);
|
||||
|
||||
$email = $stat->getEmail();
|
||||
$channel = ($email) ? ['email' => $email->getId()] : 'email';
|
||||
foreach ($contacts as $contact) {
|
||||
$this->dncModel->addDncForContact($contact->getId(), $channel, $dncReason, $comments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $address
|
||||
* @param string $comments
|
||||
* @param int $dncReason
|
||||
* @param int|null $channelId
|
||||
*/
|
||||
public function addFailureByAddress($address, $comments, $dncReason = DNC::BOUNCED, $channelId = null): void
|
||||
{
|
||||
$result = $this->finder->findByAddress($address);
|
||||
|
||||
if ($contacts = $result->getContacts()) {
|
||||
foreach ($contacts as $contact) {
|
||||
$channel = ($channelId) ? ['email' => $channelId] : 'email';
|
||||
$this->dncModel->addDncForContact($contact->getId(), $channel, $dncReason, $comments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dncReason
|
||||
* @param int|null $channelId
|
||||
*/
|
||||
public function addFailureByContactId($id, $comments, $dncReason = DNC::BOUNCED, $channelId = null): void
|
||||
{
|
||||
$channel = ($channelId) ? ['email' => $channelId] : 'email';
|
||||
$this->dncModel->addDncForContact($id, $channel, $dncReason, $comments);
|
||||
}
|
||||
|
||||
private function updateStatDetails(Stat $stat, $comments, $dncReason): void
|
||||
{
|
||||
if (DNC::BOUNCED === $dncReason) {
|
||||
$stat->setIsFailed(true);
|
||||
}
|
||||
|
||||
$openDetails = $stat->getOpenDetails();
|
||||
if (!isset($openDetails['bounces'])) {
|
||||
$openDetails['bounces'] = [];
|
||||
}
|
||||
$dtHelper = new DateTimeHelper();
|
||||
$openDetails['bounces'][] = [
|
||||
'datetime' => $dtHelper->toUtcString(),
|
||||
'reason' => $comments,
|
||||
];
|
||||
$stat->setOpenDetails($openDetails);
|
||||
$this->emailStatModel->saveEntity($stat);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user