Skip to content

Commit

Permalink
Merge pull request mautic#1289 from acquia/MAUT-5131-2
Browse files Browse the repository at this point in the history
MAUT 5131 - Send example email as a specified contact
  • Loading branch information
fedys authored and escopecz committed Jul 18, 2024
1 parent 0d19f84 commit 4a6e807
Show file tree
Hide file tree
Showing 6 changed files with 419 additions and 14 deletions.
33 changes: 33 additions & 0 deletions app/bundles/EmailBundle/Assets/js/send.example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Used in data-lookup-callback attr of form field in ExampleSendType
* Take a look at https://github.com/twitter/typeahead.js/
*/
Mautic.activateContactLookupField = function(fieldOptions, filterId) {

const lookupElementId = 'example_send_contact';
const action = mQuery('#'+ lookupElementId).attr('data-chosen-lookup');

const options = {
limit: 20,
'searchKey': 'lead.lead',
};

Mautic.activateFieldTypeahead(lookupElementId, filterId, options, action);

mQuery('#'+ lookupElementId).on("change",function(event) {
if (event.target.value === '') {
// Delete selected contact ID from hidden field
mQuery('#example_send_contact_id').val('');
}
});
};

/**
* Used in data-lookup-callback attr of form field in ExampleSendType
*/
Mautic.updateContactLookupListFilter = function(field, item) {
if (item && item.id) {
mQuery('#example_send_contact_id').val(item.id);
mQuery(field).val(item.value);
}
};
54 changes: 42 additions & 12 deletions app/bundles/EmailBundle/Controller/EmailController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Mautic\EmailBundle\Controller;

use Mautic\AssetBundle\Model\AssetModel;
use Mautic\CampaignBundle\Entity\Lead;
use Mautic\CoreBundle\Controller\BuilderControllerTrait;
use Mautic\CoreBundle\Controller\FormController;
use Mautic\CoreBundle\Controller\FormErrorMessagesTrait;
Expand All @@ -17,12 +18,15 @@
use Mautic\CoreBundle\Translation\Translator;
use Mautic\CoreBundle\Twig\Helper\AssetsHelper;
use Mautic\CoreBundle\Twig\Helper\SlotsHelper;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Mautic\EmailBundle\Entity\Email;
use Mautic\EmailBundle\Form\Type\BatchSendType;
use Mautic\EmailBundle\Form\Type\ExampleSendType;
use Mautic\EmailBundle\Helper\PlainTextHelper;
use Mautic\EmailBundle\Model\EmailModel;
use Mautic\LeadBundle\Controller\EntityContactsTrait;
use Mautic\LeadBundle\Model\FieldModel;
use Mautic\LeadBundle\Model\LeadModel;
use Mautic\LeadBundle\Model\ListModel;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand Down Expand Up @@ -1517,19 +1521,45 @@ public function sendExampleAction(Request $request, $objectId)
$isCancelled = $this->isFormCancelled($form);
$isValid = $this->isFormValid($form);
if (!$isCancelled && $isValid) {
$emails = $form['emails']->getData()['list'];

// Prepare a fake lead
/** @var \Mautic\LeadBundle\Model\FieldModel $fieldModel */
$fieldModel = $this->getModel('lead.field');
$fields = $fieldModel->getFieldList(false, false);
array_walk(
$fields,
function (&$field): void {
$field = "[$field]";
$emails = $form['emails']->getData()['list'];
// Use this contact data to fill email body content
$previewForContactId = (int) $form->getData()['contact_id'];

/** @var CorePermissions $security */
$security = $this->get('mautic.security');
if ($previewForContactId && (
!$security->isAdmin()
|| !$security->hasEntityAccess('lead:leads:viewown', 'lead:leads:viewother')
)
) {
// disallow displaying contact information
$previewForContactId = null;
}

if ($previewForContactId) {
// We have one from request parameter
/** @var LeadModel $fieldModel */
$leadModel = $this->getModel('lead.lead');
/** @var Lead $contact */
$contact = $leadModel->getEntity($previewForContactId);
if ($contact && $contact->getId()) {
$fields = $contact->convertToArray();
}
);
$fields['id'] = 0;
}

if (!isset($fields)) {
// Prepare a fake lead
/** @var FieldModel $fieldModel */
$fieldModel = $this->getModel('lead.field');
$fields = $fieldModel->getFieldList(false, false);
array_walk(
$fields,
function (&$field) {
$field = "[$field]";
}
);
$fields['id'] = 0;
}

$errors = [];
foreach ($emails as $email) {
Expand Down
37 changes: 37 additions & 0 deletions app/bundles/EmailBundle/Form/Type/ExampleSendType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@
namespace Mautic\EmailBundle\Form\Type;

use Mautic\CoreBundle\Form\Type\FormButtonsType;
use Mautic\CoreBundle\Form\Type\LookupType;
use Mautic\CoreBundle\Form\Type\SortableListType;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
* @extends AbstractType<mixed>
*/
class ExampleSendType extends AbstractType
{
public function __construct(private TranslatorInterface $translator, private CorePermissions $security)
{
}

public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add(
Expand All @@ -26,6 +34,35 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
]
);

if ($this->security->isAdmin()
|| $this->security->hasEntityAccess('lead:leads:viewown', 'lead:leads:viewother')
) {
$builder->add(
'contact',
LookupType::class,
[
'attr' => [
'class' => 'form-control',
'data-callback' => 'activateContactLookupField',
'data-toggle' => 'field-lookup',
'data-lookup-callback' => 'updateContactLookupListFilter',
'data-chosen-lookup' => 'lead:contactList',
'placeholder' => $this->translator->trans(
'mautic.lead.list.form.startTyping'
),
'data-no-record-message' => $this->translator->trans(
'mautic.core.form.nomatches'
),
],
]
);

$builder->add(
'contact_id',
HiddenType::class
);
}

$builder->add(
'buttons',
FormButtonsType::class,
Expand Down
24 changes: 22 additions & 2 deletions app/bundles/EmailBundle/Model/EmailModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -2165,8 +2165,14 @@ private function getContactCompanies(array &$sendTo): void
*
* @throws \Doctrine\ORM\ORMException
*/
public function sendSampleEmailToUser($email, $users, $leadFields = null, $tokens = [], $assetAttachments = [], $saveStat = true)
{
public function sendSampleEmailToUser(
$email,
$users,
$leadFields = null,
$tokens = [],
$assetAttachments = [],
$saveStat = true
) {
if (!$emailId = $email->getId()) {
return false;
}
Expand All @@ -2184,6 +2190,20 @@ public function sendSampleEmailToUser($email, $users, $leadFields = null, $token
return false;
}

// Generate and replace tokens
$event = new EmailSendEvent(
null,
[
'content' => $email->getCustomHtml(),
'email' => $email,
'idHash' => 'xxxxxxxxxxxxxx', // bogus ID
'tokens' => ['{tracking_pixel}' => ''], // Override tracking_pixel
'internalSend' => true,
'lead' => $leadFields,
]
);
$this->dispatcher->dispatch(EmailEvents::EMAIL_ON_DISPLAY, $event);

$mailer = $this->mailHelper->getSampleMailer();
$mailer->setLead($leadFields, true);
$mailer->setTokens($tokens);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

declare(strict_types=1);

/*
* @copyright 2021 Mautic Contributors. All rights reserved
* @author Mautic
*
* @link https://mautic.org
*
* @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
*/

namespace Mautic\EmailBundle\Tests\Controller;

use DateTime;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\EmailBundle\Entity\Email;
use Mautic\LeadBundle\Entity\Lead;
use Swift_Events_EventListener;
use Swift_Mime_SimpleMessage;
use Swift_Transport;
use Symfony\Component\HttpFoundation\Request;

class EmailExampleFunctionalTest extends MauticMysqlTestCase
{
protected function setUp(): void
{
$this->configParams['mailer_spool_type'] = 'file';

parent::setUp();
}

public function testSendEmail(): void
{
$this->container->set('swiftmailer.transport.real', $transport = $this->createTransportFake());

$lead = $this->createLead();
$email = $this->createEmail();
$this->em->flush();

$crawler = $this->client->request(Request::METHOD_GET, "/s/emails/sendExample/{$email->getId()}");
$formCrawler = $crawler->filter('form[name=example_send]');
self::assertSame(1, $formCrawler->count());
$form = $formCrawler->form();
$form->setValues([
'example_send[emails][list][0]' => '[email protected]',
'example_send[contact]' => 'somebody',
'example_send[contact_id]' => $lead->getId(),
]);
$this->client->submit($form);

self::assertCount(1, $transport->messages);

$message = $transport->messages[0];

// Asserting email data
self::assertInstanceOf('Swift_Message', $message);
self::assertSame('[email protected]', key($message->getTo()));
self::assertContains('Email subject', $message->getSubject());
self::assertContains(
'Contact emails is [email protected]',
$message->getBody()
);
}

private function createEmail(): Email
{
$email = new Email();
$email->setDateAdded(new DateTime());
$email->setName('Email name');
$email->setSubject('Email subject');
$email->setTemplate('Blank');
$email->setCustomHtml('Contact emails is {contactfield=email}');
$this->em->persist($email);

return $email;
}

private function createLead(): Lead
{
$lead = new Lead();
$lead->setEmail('[email protected]');
$this->em->persist($lead);

return $lead;
}

private function createTransportFake(): Swift_Transport
{
return new class() implements Swift_Transport {
/**
* @var array
*/
public $messages = [];

public function isStarted(): bool
{
return true;
}

public function start(): void
{
}

public function stop(): void
{
}

public function ping(): bool
{
return true;
}

public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null): int
{
$this->messages[] = clone $message;

return count((array) $message->getTo())
+ count((array) $message->getCc())
+ count((array) $message->getBcc());
}

public function registerPlugin(Swift_Events_EventListener $plugin): void
{
}
};
}
}
Loading

0 comments on commit 4a6e807

Please sign in to comment.