Check validity on activating newsletters
This prevents users from activating automatic emails from listing pages that are not valid. This also adds more checks for the content of a newsletter, requiring that a newsletter have at least one content block in order to be valid. This change makes the server side validation check match what we're checking in the editor in mailpoet/assets/js/src/newsletter_editor /components/save.js and mailpoet/assets/js/src/newsletters/send.jsx [MAILPOET-4236]
This commit is contained in:
committed by
Veljko V
parent
fdaf22d46b
commit
27a86d2ca6
@ -22,6 +22,7 @@ use MailPoet\Newsletter\Preview\SendPreviewException;
|
||||
use MailPoet\Newsletter\Scheduler\PostNotificationScheduler;
|
||||
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;
|
||||
@ -79,6 +80,9 @@ class Newsletters extends APIEndpoint {
|
||||
/** @var TrackingConfig */
|
||||
private $trackingConfig;
|
||||
|
||||
/** @var Validator */
|
||||
private $validator;
|
||||
|
||||
/** @var Scheduler */
|
||||
private $scheduler;
|
||||
|
||||
@ -97,7 +101,8 @@ class Newsletters extends APIEndpoint {
|
||||
NewsletterSaveController $newsletterSaveController,
|
||||
NewsletterUrl $newsletterUrl,
|
||||
TrackingConfig $trackingConfig,
|
||||
Scheduler $scheduler
|
||||
Scheduler $scheduler,
|
||||
Validator $validator
|
||||
) {
|
||||
$this->listingHandler = $listingHandler;
|
||||
$this->wp = $wp;
|
||||
@ -114,6 +119,7 @@ class Newsletters extends APIEndpoint {
|
||||
$this->newsletterUrl = $newsletterUrl;
|
||||
$this->trackingConfig = $trackingConfig;
|
||||
$this->scheduler = $scheduler;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
public function get($data = []) {
|
||||
@ -184,6 +190,13 @@ class Newsletters extends APIEndpoint {
|
||||
]);
|
||||
}
|
||||
|
||||
if ($status === NewsletterEntity::STATUS_ACTIVE) {
|
||||
$validationError = $this->validator->validate($newsletter);
|
||||
if ($validationError !== null) {
|
||||
return $this->errorResponse([APIError::FORBIDDEN => $validationError], [], Response::STATUS_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -22,21 +22,31 @@ class Validator {
|
||||
&& is_array($newsletterEntity->getBody())
|
||||
&& $newsletterEntity->getBody()['content']
|
||||
) {
|
||||
$body = json_encode($newsletterEntity->getBody()['content']);
|
||||
if ($body === false) {
|
||||
return __('Poet, please add prose to your masterpiece before you send it to your followers.');
|
||||
$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($body, '[link:subscription_unsubscribe_url]') === false)
|
||||
&& (strpos($body, '[link:subscription_unsubscribe]') === false)
|
||||
&& (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 __('Poet, please add prose to your masterpiece before you send it to your followers.');
|
||||
return $this->emptyContentErrorMessage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function emptyContentErrorMessage(): string {
|
||||
return __('Poet, please add prose to your masterpiece before you send it to your followers.');
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ use MailPoet\Newsletter\Segment\NewsletterSegmentRepository;
|
||||
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
|
||||
use MailPoet\Newsletter\Statistics\NewsletterStatisticsRepository;
|
||||
use MailPoet\Newsletter\Url;
|
||||
use MailPoet\Newsletter\Validator;
|
||||
use MailPoet\Router\Router;
|
||||
use MailPoet\Segments\SegmentsRepository;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
@ -695,14 +696,15 @@ class NewslettersTest extends \MailPoetTest {
|
||||
$this->diContainer->get(NewsletterSaveController::class),
|
||||
$this->diContainer->get(Url::class),
|
||||
$this->diContainer->get(TrackingConfig::class),
|
||||
$this->scheduler
|
||||
$this->scheduler,
|
||||
$this->diContainer->get(Validator::class)
|
||||
);
|
||||
}
|
||||
|
||||
private function createNewsletter(string $subject, string $type): NewsletterEntity {
|
||||
$newsletter = new NewsletterEntity();
|
||||
$newsletter->setSubject($subject);
|
||||
$newsletter->setBody(Fixtures::get('newsletter_body_template'));
|
||||
$newsletter->setBody((array)json_decode(Fixtures::get('newsletter_body_template'), true));
|
||||
$newsletter->setType($type);
|
||||
$newsletter->setHash(Security::generateHash());
|
||||
$this->newsletterRepository->persist($newsletter);
|
||||
|
@ -143,7 +143,21 @@ class SendingQueueTest extends \MailPoetTest {
|
||||
$newsletter = new NewsletterEntity();
|
||||
$newsletter->setSubject('subject');
|
||||
$newsletter->setType(NewsletterEntity::TYPE_STANDARD);
|
||||
$newsletter->setBody(['content' => ['type' => 'container', 'columnLayout' => false, 'orientation' => 'vertical']]);
|
||||
$newsletter->setBody([
|
||||
'content' =>
|
||||
[
|
||||
'type' => 'container',
|
||||
'columnLayout' => false,
|
||||
'orientation' => 'vertical',
|
||||
'blocks' => [
|
||||
[
|
||||
'type' => 'header',
|
||||
'link' => '',
|
||||
'text' => 'Hello!'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
$this->entityManager->persist($newsletter);
|
||||
$this->entityManager->flush();
|
||||
$sendingQueue = new SendingQueueAPI(
|
||||
@ -165,6 +179,20 @@ class SendingQueueTest extends \MailPoetTest {
|
||||
expect($response['errors'][0]['error'])->stringContainsString('bad_request');
|
||||
}
|
||||
|
||||
public function testItRejectsNewslettersWithoutContentBlocks() {
|
||||
$newsletter = new NewsletterEntity();
|
||||
$newsletter->setSubject('subject');
|
||||
$newsletter->setType(NewsletterEntity::TYPE_STANDARD);
|
||||
$newsletter->setBody(['content' => ['type' => 'container', 'columnLayout' => false, 'orientation' => 'vertical']]);
|
||||
$this->entityManager->persist($newsletter);
|
||||
$this->entityManager->flush();
|
||||
$sendingQueue = $this->diContainer->get(SendingQueueAPI::class);
|
||||
$response = $sendingQueue->add(['newsletter_id' => $newsletter->getId()]);
|
||||
$result = $response->getData();
|
||||
expect($result['errors'][0])->array();
|
||||
expect($result['errors'][0]['message'])->stringContainsString('Poet, please add prose to your masterpiece before you send it to your followers');
|
||||
}
|
||||
|
||||
private function _createOrUpdateNewsletterOptions(NewsletterEntity $newsletter, $newsletterType, $options) {
|
||||
$newsletterOptionFieldRepository = $this->diContainer->get(NewsletterOptionFieldsRepository::class);
|
||||
$newsletterOptionRepository = $this->diContainer->get(NewsletterOptionsRepository::class);
|
||||
|
Reference in New Issue
Block a user