From a5103f95969854d7e97d663ac53de5784f7d2ea0 Mon Sep 17 00:00:00 2001 From: John Oleksowicz Date: Fri, 15 Apr 2022 13:15:28 -0500 Subject: [PATCH] Move reengagement validations into validator [MAILPOET-4236] --- mailpoet/lib/API/JSON/v1/Newsletters.php | 25 ------ mailpoet/lib/Newsletter/Validator.php | 85 ++++++++++++------- .../API/JSON/v1/NewslettersTest.php | 2 - .../API/JSON/v1/SendingQueueTest.php | 3 +- 4 files changed, 57 insertions(+), 58 deletions(-) diff --git a/mailpoet/lib/API/JSON/v1/Newsletters.php b/mailpoet/lib/API/JSON/v1/Newsletters.php index f150d1d654..ae136e1c26 100644 --- a/mailpoet/lib/API/JSON/v1/Newsletters.php +++ b/mailpoet/lib/API/JSON/v1/Newsletters.php @@ -24,7 +24,6 @@ use MailPoet\Newsletter\Scheduler\Scheduler; use MailPoet\Newsletter\Url as NewsletterUrl; use MailPoet\Newsletter\Validator; use MailPoet\Settings\SettingsController; -use MailPoet\Settings\TrackingConfig; use MailPoet\UnexpectedValueException; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; use MailPoet\Util\Security; @@ -100,7 +99,6 @@ class Newsletters extends APIEndpoint { SendPreviewController $sendPreviewController, NewsletterSaveController $newsletterSaveController, NewsletterUrl $newsletterUrl, - TrackingConfig $trackingConfig, Scheduler $scheduler, Validator $validator ) { @@ -117,7 +115,6 @@ class Newsletters extends APIEndpoint { $this->sendPreviewController = $sendPreviewController; $this->newsletterSaveController = $newsletterSaveController; $this->newsletterUrl = $newsletterUrl; - $this->trackingConfig = $trackingConfig; $this->scheduler = $scheduler; $this->validator = $validator; } @@ -197,28 +194,6 @@ class Newsletters extends APIEndpoint { } } - // if the re-engagement email doesn't contain the re-engage link, it can't be activated - if ($newsletter->getType() === NewsletterEntity::TYPE_RE_ENGAGEMENT && $status === NewsletterEntity::STATUS_ACTIVE) { - if (strpos($newsletter->getContent(), '[link:subscription_re_engage_url]') === false) { - return $this->errorResponse([ - APIError::FORBIDDEN => __( - 'A re-engagement email must include a link with [link:subscription_re_engage_url] shortcode.', - 'mailpoet' - ), - ], [], Response::STATUS_FORBIDDEN); - } - } - - $tracking_enabled = $this->trackingConfig->isEmailTrackingEnabled(); - if (!$tracking_enabled && $newsletter->getType() === NewsletterEntity::TYPE_RE_ENGAGEMENT && $status === NewsletterEntity::STATUS_ACTIVE) { - return $this->errorResponse([ - APIError::FORBIDDEN => __( - 'Re-engagement emails are disabled because open and click tracking is disabled in MailPoet → Settings → Advanced.', - 'mailpoet' - ), - ], [], Response::STATUS_FORBIDDEN); - } - $this->newslettersRepository->prefetchOptions([$newsletter]); $newsletter->setStatus($status); diff --git a/mailpoet/lib/Newsletter/Validator.php b/mailpoet/lib/Newsletter/Validator.php index 041b04aecb..f8568598ec 100644 --- a/mailpoet/lib/Newsletter/Validator.php +++ b/mailpoet/lib/Newsletter/Validator.php @@ -4,49 +4,74 @@ namespace MailPoet\Newsletter; use MailPoet\Entities\NewsletterEntity; use MailPoet\Services\Bridge; +use MailPoet\Settings\TrackingConfig; +use MailPoet\Validator\ValidationException; class Validator { /** @var Bridge */ private $bridge; - + + /** @var TrackingConfig */ + private $trackingConfig; + public function __construct( - Bridge $bridge + Bridge $bridge, + TrackingConfig $trackingConfig ) { $this->bridge = $bridge; + $this->trackingConfig = $trackingConfig; } public function validate(NewsletterEntity $newsletterEntity): ?string { - if ( - $newsletterEntity->getBody() - && is_array($newsletterEntity->getBody()) - && $newsletterEntity->getBody()['content'] - ) { - $content = $newsletterEntity->getBody()['content']; - $encodedBody = json_encode($content); - if ($encodedBody === false) { - return $this->emptyContentErrorMessage(); - } else { - $blocks = $content['blocks'] ?? []; - if (empty($blocks)) { - return $this->emptyContentErrorMessage(); - } - } - - if ( - $this->bridge->isMailpoetSendingServiceEnabled() - && (strpos($encodedBody, '[link:subscription_unsubscribe_url]') === false) - && (strpos($encodedBody, '[link:subscription_unsubscribe]') === false) - ) { - return __('All emails must include an "Unsubscribe" link. Add a footer widget to your email to continue.'); - } - } else { - return $this->emptyContentErrorMessage(); + try { + $this->validateBody($newsletterEntity); + $this->validateUnsubscribeRequirements($newsletterEntity); + $this->validateReengagementRequirements($newsletterEntity); + } catch (ValidationException $exception) { + return __($exception->getMessage(), 'mailpoet'); } return null; } - - private function emptyContentErrorMessage(): string { - return __('Poet, please add prose to your masterpiece before you send it to your followers.'); + + private function validateUnsubscribeRequirements(NewsletterEntity $newsletterEntity): void { + if (!$this->bridge->isMailpoetSendingServiceEnabled()) { + return; + } + $content = $newsletterEntity->getContent(); + $hasUnsubscribeUrl = strpos($content, '[link:subscription_unsubscribe_url]') !== false; + $hasUnsubscribeLink = strpos($content, '[link:subscription_unsubscribe]') !== false; + + if (!$hasUnsubscribeLink && !$hasUnsubscribeUrl) { + throw new ValidationException('All emails must include an "Unsubscribe" link. Add a footer widget to your email to continue.'); + } + } + + private function validateBody(NewsletterEntity $newsletterEntity): void { + $emptyBodyErrorMessage = 'Poet, please add prose to your masterpiece before you send it to your followers.'; + $content = $newsletterEntity->getContent(); + + if ($content === '') { + throw new ValidationException($emptyBodyErrorMessage); + } + + $contentBlocks = $newsletterEntity->getBody()['content']['blocks'] ?? []; + if (count($contentBlocks) < 1) { + throw new ValidationException($emptyBodyErrorMessage); + } + } + + private function validateReengagementRequirements(NewsletterEntity $newsletterEntity): void { + if ($newsletterEntity->getType() !== NewsletterEntity::TYPE_RE_ENGAGEMENT) { + return; + } + + if (strpos($newsletterEntity->getContent(), '[link:subscription_re_engage_url]') === false) { + throw new ValidationException('A re-engagement email must include a link with [link:subscription_re_engage_url] shortcode.'); + } + + if (!$this->trackingConfig->isEmailTrackingEnabled()) { + throw new ValidationException('Re-engagement emails are disabled because open and click tracking is disabled in MailPoet → Settings → Advanced.'); + } } } diff --git a/mailpoet/tests/integration/API/JSON/v1/NewslettersTest.php b/mailpoet/tests/integration/API/JSON/v1/NewslettersTest.php index e3c01f9fc5..53dab0a62d 100644 --- a/mailpoet/tests/integration/API/JSON/v1/NewslettersTest.php +++ b/mailpoet/tests/integration/API/JSON/v1/NewslettersTest.php @@ -40,7 +40,6 @@ use MailPoet\Newsletter\Validator; use MailPoet\Router\Router; use MailPoet\Segments\SegmentsRepository; use MailPoet\Settings\SettingsController; -use MailPoet\Settings\TrackingConfig; use MailPoet\Tasks\Sending as SendingTask; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; use MailPoet\Util\Security; @@ -695,7 +694,6 @@ class NewslettersTest extends \MailPoetTest { $mocks['sendPreviewController'] ?? $this->diContainer->get(SendPreviewController::class), $this->diContainer->get(NewsletterSaveController::class), $this->diContainer->get(Url::class), - $this->diContainer->get(TrackingConfig::class), $this->scheduler, $this->diContainer->get(Validator::class) ); diff --git a/mailpoet/tests/integration/API/JSON/v1/SendingQueueTest.php b/mailpoet/tests/integration/API/JSON/v1/SendingQueueTest.php index 5bed592049..78567128d4 100644 --- a/mailpoet/tests/integration/API/JSON/v1/SendingQueueTest.php +++ b/mailpoet/tests/integration/API/JSON/v1/SendingQueueTest.php @@ -23,6 +23,7 @@ use MailPoet\Segments\SubscribersFinder; use MailPoet\Services\Bridge; use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsRepository; +use MailPoet\Settings\TrackingConfig; use MailPoet\Tasks\Sending; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; @@ -170,7 +171,7 @@ class SendingQueueTest extends \MailPoetTest { $this->diContainer->get(Scheduler::class), new Validator(Stub::make(Bridge::class, [ 'isMailpoetSendingServiceEnabled' => true, - ])) + ]), $this->diContainer->get(TrackingConfig::class)) ); $response = $sendingQueue->add(['newsletter_id' => $newsletter->getId()]); $response = $response->getData();