Add an endpoint to set new authorized FROM email address

[MAILPOET-2804]
This commit is contained in:
Jan Jakeš
2020-03-25 12:34:57 +01:00
committed by Veljko V
parent b94dc6c542
commit 3cdd224e14
4 changed files with 128 additions and 4 deletions

View File

@ -75,6 +75,25 @@ class Settings extends APIEndpoint {
}
}
public function setAuthorizedFromAddress($data = []) {
$address = $data['address'] ?? null;
if (!$address) {
return $this->badRequest([
APIError::BAD_REQUEST => WPFunctions::get()->__('No email address specified.', 'mailpoet'),
]);
}
$address = trim($address);
try {
$this->authorizedEmailsController->setFromEmailAddress($address);
} catch (\InvalidArgumentException $e) {
return $this->badRequest([
APIError::UNAUTHORIZED => WPFunctions::get()->__('Cant use this email yet! Please authorize it first.', 'mailpoet'),
]);
}
return $this->successResponse();
}
private function onSettingsChange($oldSettings, $newSettings) {
// Recalculate inactive subscribers
$oldInactivationInterval = $oldSettings['deactivate_subscriber_after_inactive_days'];

View File

@ -2,6 +2,7 @@
namespace MailPoet\Mailer;
use MailPoet\DI\ContainerWrapper;
use MailPoet\Mailer\Methods\AmazonSES;
use MailPoet\Mailer\Methods\ErrorMappers\AmazonSESMapper;
use MailPoet\Mailer\Methods\ErrorMappers\MailPoetMapper;
@ -13,7 +14,6 @@ use MailPoet\Mailer\Methods\PHPMail;
use MailPoet\Mailer\Methods\SendGrid;
use MailPoet\Mailer\Methods\SMTP;
use MailPoet\Services\AuthorizedEmailsController;
use MailPoet\Services\Bridge;
use MailPoet\Settings\SettingsController;
class Mailer {
@ -74,7 +74,7 @@ class Mailer {
$this->sender,
$this->replyTo,
new MailPoetMapper(),
new AuthorizedEmailsController($this->settings, new Bridge)
ContainerWrapper::getInstance()->get(AuthorizedEmailsController::class)
);
break;
case self::METHOD_SENDGRID:

View File

@ -2,9 +2,11 @@
namespace MailPoet\Services;
use MailPoet\Mailer\Mailer;
use MailPoet\Mailer\MailerError;
use MailPoet\Mailer\MailerLog;
use MailPoet\Models\Newsletter;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Settings\SettingsController;
class AuthorizedEmailsController {
@ -16,15 +18,43 @@ class AuthorizedEmailsController {
/** @var SettingsController */
private $settings;
/** @var NewslettersRepository */
private $newslettersRepository;
private $automaticEmailTypes = [
Newsletter::TYPE_WELCOME,
Newsletter::TYPE_NOTIFICATION,
Newsletter::TYPE_AUTOMATIC,
];
public function __construct(SettingsController $settingsController, Bridge $bridge) {
public function __construct(
SettingsController $settingsController,
Bridge $bridge,
NewslettersRepository $newslettersRepository
) {
$this->settings = $settingsController;
$this->bridge = $bridge;
$this->newslettersRepository = $newslettersRepository;
}
public function setFromEmailAddress(string $address) {
$authorizedEmails = array_map('strtolower', $this->bridge->getAuthorizedEmailAddresses() ?: []);
$isAuthorized = $this->validateAuthorizedEmail($authorizedEmails, $address);
if (!$isAuthorized) {
throw new \InvalidArgumentException("Email address '$address' is not authorized");
}
// update FROM address in settings & all scheduled and active emails
$this->settings->set('sender.address', $address);
$result = $this->validateAddressesInScheduledAndAutomaticEmails($authorizedEmails);
foreach ($result['invalid_senders_in_newsletters'] ?? [] as $item) {
$newsletter = $this->newslettersRepository->findOneById((int)$item['newsletter_id']);
if ($newsletter) {
$newsletter->setSenderAddress($address);
}
}
$this->newslettersRepository->flush();
$this->settings->set(self::AUTHORIZED_EMAIL_ADDRESSES_ERROR_SETTING, null);
}
public function checkAuthorizedEmailAddresses() {

View File

@ -3,10 +3,13 @@
namespace MailPoet\Test\Services;
use Codeception\Stub\Expected;
use InvalidArgumentException;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Mailer\Mailer;
use MailPoet\Mailer\MailerError;
use MailPoet\Mailer\MailerLog;
use MailPoet\Models\Newsletter;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Services\AuthorizedEmailsController;
use MailPoet\Services\Bridge;
use MailPoet\Settings\SettingsController;
@ -155,6 +158,77 @@ class AuthorizedEmailsControllerTest extends \MailPoetTest {
expect($error['invalid_senders_in_newsletters'][0]['subject'])->equals('Subject');
}
public function testItSetsFromAddressInSettings() {
$this->settings->set('sender.address', '');
$controller = $this->getController(['authorized@email.com']);
$controller->setFromEmailAddress('authorized@email.com');
expect($this->settings->get('sender.address'))->same('authorized@email.com');
}
public function testItSetsFromAddressInScheduledEmails() {
$newsletter = new NewsletterEntity();
$newsletter->setSubject('Subject');
$newsletter->setType(NewsletterEntity::TYPE_STANDARD);
$newsletter->setStatus(NewsletterEntity::STATUS_SCHEDULED);
$newsletter->setSenderAddress('invalid@email.com');
$this->entityManager->persist($newsletter);
$this->entityManager->flush();
$this->settings->set('sender.address', '');
$controller = $this->getController(['authorized@email.com']);
$controller->setFromEmailAddress('authorized@email.com');
expect($newsletter->getSenderAddress())->same('authorized@email.com');
// refresh from DB and check again
$this->entityManager->refresh($newsletter);
expect($newsletter->getSenderAddress())->same('authorized@email.com');
}
public function testItSetsFromAddressInAutomaticEmails() {
$newsletter = new NewsletterEntity();
$newsletter->setSubject('Subject');
$newsletter->setType(NewsletterEntity::TYPE_AUTOMATIC);
$newsletter->setStatus(NewsletterEntity::STATUS_ACTIVE);
$newsletter->setSenderAddress('invalid@email.com');
$this->entityManager->persist($newsletter);
$this->entityManager->flush();
$this->settings->set('sender.address', '');
$controller = $this->getController(['authorized@email.com']);
$controller->setFromEmailAddress('authorized@email.com');
expect($newsletter->getSenderAddress())->same('authorized@email.com');
// refresh from DB and check again
$this->entityManager->refresh($newsletter);
expect($newsletter->getSenderAddress())->same('authorized@email.com');
}
public function testItDoesntSetFromAddressForSentEmails() {
$newsletter = new NewsletterEntity();
$newsletter->setSubject('Subject');
$newsletter->setType(NewsletterEntity::TYPE_STANDARD);
$newsletter->setStatus(NewsletterEntity::STATUS_SENT);
$newsletter->setSenderAddress('invalid@email.com');
$this->entityManager->persist($newsletter);
$this->entityManager->flush();
$this->settings->set('sender.address', '');
$controller = $this->getController(['authorized@email.com']);
$controller->setFromEmailAddress('authorized@email.com');
expect($newsletter->getSenderAddress())->same('invalid@email.com');
// refresh from DB and check again
$this->entityManager->refresh($newsletter);
expect($newsletter->getSenderAddress())->same('invalid@email.com');
}
public function testSetsFromAddressThrowsForUnauthorizedEmail() {
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("Email address 'invalid@email.com' is not authorized");
$controller = $this->getController(['authorized@email.com']);
$controller->setFromEmailAddress('invalid@email.com');
}
private function setMailPoetSendingMethod() {
$this->settings->set(
Mailer::MAILER_CONFIG_SETTING_NAME,
@ -172,7 +246,8 @@ class AuthorizedEmailsControllerTest extends \MailPoetTest {
$getEmailsExpectaton = Expected::once($authorizedEmails);
}
$bridgeMock = $this->make(Bridge::class, ['getAuthorizedEmailAddresses' => $getEmailsExpectaton]);
return new AuthorizedEmailsController($this->settings, $bridgeMock);
$newslettersRepository = $this->diContainer->get(NewslettersRepository::class);
return new AuthorizedEmailsController($this->settings, $bridgeMock, $newslettersRepository);
}
public function _after() {