Move ModelValidator::validateNonRoleEmail() to a new Validator class

We want to remove/refactor the whole ModelValidator class as part of the
Doctrine refactor.

This commit moves the method ModelValidator::validateNonRoleEmail() to a
new Validator class as the method is not used by the validator system of
the Paris models. ModelValidator::validateEmail() was also moved as it
is called by ModelValidator::validateNonRoleEmail().

[MAILPOET-4343]
This commit is contained in:
Rodrigo Primo
2023-05-05 16:37:23 -03:00
committed by Aschepikov
parent d760272678
commit 00d021109c
13 changed files with 123 additions and 67 deletions

View File

@ -15,6 +15,7 @@ use MailPoet\Newsletter\Options\NewsletterOptionsRepository;
use MailPoet\Segments\SegmentSaveController; use MailPoet\Segments\SegmentSaveController;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Segments\WP; use MailPoet\Segments\WP;
use MailPoet\Services\Validator;
use MailPoet\Subscribers\ImportExport\Export\Export; use MailPoet\Subscribers\ImportExport\Export\Export;
use MailPoet\Subscribers\ImportExport\Import\Import; use MailPoet\Subscribers\ImportExport\Import\Import;
use MailPoet\Subscribers\ImportExport\Import\MailChimp; use MailPoet\Subscribers\ImportExport\Import\MailChimp;
@ -51,6 +52,9 @@ class ImportExport extends APIEndpoint {
/** @var TagRepository */ /** @var TagRepository */
private $tagRepository; private $tagRepository;
/** @var Validator */
private $validator;
/** @var CronWorkerScheduler */ /** @var CronWorkerScheduler */
private $cronWorkerScheduler; private $cronWorkerScheduler;
@ -68,7 +72,8 @@ class ImportExport extends APIEndpoint {
SegmentsResponseBuilder $segmentsResponseBuilder, SegmentsResponseBuilder $segmentsResponseBuilder,
CronWorkerScheduler $cronWorkerScheduler, CronWorkerScheduler $cronWorkerScheduler,
SubscribersRepository $subscribersRepository, SubscribersRepository $subscribersRepository,
TagRepository $tagRepository TagRepository $tagRepository,
Validator $validator
) { ) {
$this->wpSegment = $wpSegment; $this->wpSegment = $wpSegment;
$this->customFieldsRepository = $customFieldsRepository; $this->customFieldsRepository = $customFieldsRepository;
@ -80,6 +85,7 @@ class ImportExport extends APIEndpoint {
$this->cronWorkerScheduler = $cronWorkerScheduler; $this->cronWorkerScheduler = $cronWorkerScheduler;
$this->segmentsResponseBuilder = $segmentsResponseBuilder; $this->segmentsResponseBuilder = $segmentsResponseBuilder;
$this->tagRepository = $tagRepository; $this->tagRepository = $tagRepository;
$this->validator = $validator;
} }
public function getMailChimpLists($data) { public function getMailChimpLists($data) {
@ -133,6 +139,7 @@ class ImportExport extends APIEndpoint {
$this->newsletterOptionsRepository, $this->newsletterOptionsRepository,
$this->subscriberRepository, $this->subscriberRepository,
$this->tagRepository, $this->tagRepository,
$this->validator,
json_decode($data, true) json_decode($data, true)
); );
$process = $import->process(); $process = $import->process();

View File

@ -4,7 +4,7 @@ namespace MailPoet\AdminPages\Pages;
use MailPoet\AdminPages\PageRenderer; use MailPoet\AdminPages\PageRenderer;
use MailPoet\Form\Block; use MailPoet\Form\Block;
use MailPoet\Models\ModelValidator; use MailPoet\Services\Validator;
use MailPoet\Subscribers\ImportExport\ImportExportFactory; use MailPoet\Subscribers\ImportExport\ImportExportFactory;
class SubscribersImport { class SubscribersImport {
@ -30,7 +30,7 @@ class SubscribersImport {
'date_formats' => $this->dateBlock->getDateFormats(), 'date_formats' => $this->dateBlock->getDateFormats(),
'month_names' => $this->dateBlock->getMonthNames(), 'month_names' => $this->dateBlock->getMonthNames(),
'sub_menu' => 'mailpoet-subscribers', 'sub_menu' => 'mailpoet-subscribers',
'role_based_emails' => json_encode(ModelValidator::ROLE_EMAILS), 'role_based_emails' => json_encode(Validator::ROLE_EMAILS),
]); ]);
$this->pageRenderer->displayPage('subscribers/importExport/import.html', $data); $this->pageRenderer->displayPage('subscribers/importExport/import.html', $data);
} }

View File

@ -437,6 +437,7 @@ class ContainerConfigurator implements IContainerConfigurator {
$container->autowire(\MailPoet\Services\CongratulatoryMssEmailController::class)->setPublic(true); $container->autowire(\MailPoet\Services\CongratulatoryMssEmailController::class)->setPublic(true);
$container->autowire(\MailPoet\Services\AuthorizedSenderDomainController::class)->setPublic(true); $container->autowire(\MailPoet\Services\AuthorizedSenderDomainController::class)->setPublic(true);
$container->autowire(\MailPoet\Services\SubscribersCountReporter::class)->setPublic(true); $container->autowire(\MailPoet\Services\SubscribersCountReporter::class)->setPublic(true);
$container->autowire(\MailPoet\Services\Validator::class)->setPublic(true);
// Settings // Settings
$container->autowire(\MailPoet\Settings\SettingsController::class)->setPublic(true); $container->autowire(\MailPoet\Settings\SettingsController::class)->setPublic(true);
$container->autowire(\MailPoet\Settings\SettingsChangeHandler::class)->setPublic(true); $container->autowire(\MailPoet\Settings\SettingsChangeHandler::class)->setPublic(true);

View File

@ -3,7 +3,7 @@
namespace MailPoet\Form\Block; namespace MailPoet\Form\Block;
use MailPoet\Form\Util\FieldNameObfuscator; use MailPoet\Form\Util\FieldNameObfuscator;
use MailPoet\Models\ModelValidator; use MailPoet\Services\Validator;
use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Functions as WPFunctions;
/** /**
@ -32,8 +32,8 @@ class BlockRendererHelper {
if ($blockId === 'email') { if ($blockId === 'email') {
$rules['required'] = true; $rules['required'] = true;
$rules['minlength'] = ModelValidator::EMAIL_MIN_LENGTH; $rules['minlength'] = Validator::EMAIL_MIN_LENGTH;
$rules['maxlength'] = ModelValidator::EMAIL_MAX_LENGTH; $rules['maxlength'] = Validator::EMAIL_MAX_LENGTH;
$rules['type-message'] = __('This value should be a valid email.', 'mailpoet'); $rules['type-message'] = __('This value should be a valid email.', 'mailpoet');
} }

View File

@ -2,50 +2,13 @@
namespace MailPoet\Models; namespace MailPoet\Models;
use MailPoet\DI\ContainerWrapper;
use MailPoet\Services\Validator;
use MailPoet\Util\Helpers; use MailPoet\Util\Helpers;
use MailPoet\WP\Functions as WPFunctions;
class ModelValidator extends \MailPoetVendor\Sudzy\Engine { class ModelValidator extends \MailPoetVendor\Sudzy\Engine {
public $validators; public $validators;
const EMAIL_MIN_LENGTH = 6;
const EMAIL_MAX_LENGTH = 150;
const ROLE_EMAILS = [
'abuse',
'compliance',
'devnull',
'dns',
'ftp',
'hostmaster',
'inoc',
'ispfeedback',
'ispsupport',
'list-request',
'list',
'maildaemon',
'noc',
'no-reply',
'noreply',
'nospam',
'null',
'phish',
'phishing',
'postmaster',
'privacy',
'registrar',
'root',
'security',
'spam',
'sysadmin',
'undisclosed-recipients',
'unsubscribe',
'usenet',
'uucp',
'webmaster',
'www',
];
public function __construct() { public function __construct() {
parent::__construct(); parent::__construct();
$this->validators = [ $this->validators = [
@ -68,15 +31,8 @@ class ModelValidator extends \MailPoetVendor\Sudzy\Engine {
} }
public function validateEmail($email) { public function validateEmail($email) {
$permittedLength = (strlen($email) >= self::EMAIL_MIN_LENGTH && strlen($email) <= self::EMAIL_MAX_LENGTH); $validator = ContainerWrapper::getInstance()->get(Validator::class);
$validEmail = WPFunctions::get()->isEmail($email) !== false && parent::_isEmail($email, null); return $validator->validateEmail($email);
return ($permittedLength && $validEmail);
}
public function validateNonRoleEmail($email) {
if (!$this->validateEmail($email)) return false;
$firstPart = strtolower(substr($email, 0, (int)strpos($email, '@')));
return array_search($firstPart, self::ROLE_EMAILS) === false;
} }
public function validateRenderedNewsletterBody($newsletterBody) { public function validateRenderedNewsletterBody($newsletterBody) {

View File

@ -0,0 +1,60 @@
<?php declare(strict_types = 1);
namespace MailPoet\Services;
use MailPoet\WP\Functions as WPFunctions;
/**
* This class contains validation methods that were extracted from the \MailPoet\Models\ModelValidator class.
* It is used only in a few places and there is a chance in the future we can remove it.
*/
class Validator {
const EMAIL_MIN_LENGTH = 6;
const EMAIL_MAX_LENGTH = 150;
const ROLE_EMAILS = [
'abuse',
'compliance',
'devnull',
'dns',
'ftp',
'hostmaster',
'inoc',
'ispfeedback',
'ispsupport',
'list-request',
'list',
'maildaemon',
'noc',
'no-reply',
'noreply',
'nospam',
'null',
'phish',
'phishing',
'postmaster',
'privacy',
'registrar',
'root',
'security',
'spam',
'sysadmin',
'undisclosed-recipients',
'unsubscribe',
'usenet',
'uucp',
'webmaster',
'www',
];
public function validateEmail($email) {
$permittedLength = (strlen($email) >= self::EMAIL_MIN_LENGTH && strlen($email) <= self::EMAIL_MAX_LENGTH);
$validEmail = WPFunctions::get()->isEmail($email) !== false && filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
return ($permittedLength && $validEmail);
}
public function validateNonRoleEmail($email) {
if (!$this->validateEmail($email)) return false;
$firstPart = strtolower(substr($email, 0, (int)strpos($email, '@')));
return array_search($firstPart, self::ROLE_EMAILS) === false;
}
}

View File

@ -8,9 +8,9 @@ use MailPoet\Entities\SubscriberCustomFieldEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Entities\SubscriberSegmentEntity; use MailPoet\Entities\SubscriberSegmentEntity;
use MailPoet\Entities\SubscriberTagEntity; use MailPoet\Entities\SubscriberTagEntity;
use MailPoet\Models\ModelValidator;
use MailPoet\Newsletter\Options\NewsletterOptionsRepository; use MailPoet\Newsletter\Options\NewsletterOptionsRepository;
use MailPoet\Segments\WP; use MailPoet\Segments\WP;
use MailPoet\Services\Validator;
use MailPoet\Subscribers\ImportExport\ImportExportFactory; use MailPoet\Subscribers\ImportExport\ImportExportFactory;
use MailPoet\Subscribers\ImportExport\ImportExportRepository; use MailPoet\Subscribers\ImportExport\ImportExportRepository;
use MailPoet\Subscribers\Source; use MailPoet\Subscribers\Source;
@ -71,6 +71,9 @@ class Import {
/** @var TagRepository */ /** @var TagRepository */
private $tagRepository; private $tagRepository;
/** @var Validator */
private $validator;
public function __construct( public function __construct(
WP $wpSegment, WP $wpSegment,
CustomFieldsRepository $customFieldsRepository, CustomFieldsRepository $customFieldsRepository,
@ -78,6 +81,7 @@ class Import {
NewsletterOptionsRepository $newsletterOptionsRepository, NewsletterOptionsRepository $newsletterOptionsRepository,
SubscribersRepository $subscriberRepository, SubscribersRepository $subscriberRepository,
TagRepository $tagRepository, TagRepository $tagRepository,
Validator $validator,
array $data array $data
) { ) {
$this->wpSegment = $wpSegment; $this->wpSegment = $wpSegment;
@ -86,6 +90,7 @@ class Import {
$this->newsletterOptionsRepository = $newsletterOptionsRepository; $this->newsletterOptionsRepository = $newsletterOptionsRepository;
$this->subscriberRepository = $subscriberRepository; $this->subscriberRepository = $subscriberRepository;
$this->tagRepository = $tagRepository; $this->tagRepository = $tagRepository;
$this->validator = $validator;
$this->validateImportData($data); $this->validateImportData($data);
$this->subscribersData = $this->transformSubscribersData( $this->subscribersData = $this->transformSubscribersData(
$data['subscribers'], $data['subscribers'],
@ -219,12 +224,11 @@ class Import {
*/ */
public function validateSubscribersData(array $subscribersData) { public function validateSubscribersData(array $subscribersData) {
$invalidRecords = []; $invalidRecords = [];
$validator = new ModelValidator();
foreach ($subscribersData as $column => &$data) { foreach ($subscribersData as $column => &$data) {
if ($column === 'email') { if ($column === 'email') {
$data = array_map( $data = array_map(
function($index, $email) use(&$invalidRecords, $validator) { function($index, $email) use(&$invalidRecords) {
if (!$validator->validateNonRoleEmail($email)) { if (!$this->validator->validateNonRoleEmail($email)) {
$invalidRecords[] = $index; $invalidRecords[] = $index;
} }
return strtolower($email); return strtolower($email);

View File

@ -56,7 +56,7 @@ parameters:
path: ../../lib/API/JSON/v1/ImportExport.php path: ../../lib/API/JSON/v1/ImportExport.php
- -
message: "#^Parameter \\#7 \\$data of class MailPoet\\\\Subscribers\\\\ImportExport\\\\Import\\\\Import constructor expects array, mixed given\\.$#" message: "#^Parameter \\#8 \\$data of class MailPoet\\\\Subscribers\\\\ImportExport\\\\Import\\\\Import constructor expects array, mixed given\\.$#"
count: 1 count: 1
path: ../../lib/API/JSON/v1/ImportExport.php path: ../../lib/API/JSON/v1/ImportExport.php

View File

@ -56,7 +56,7 @@ parameters:
path: ../../lib/API/JSON/v1/ImportExport.php path: ../../lib/API/JSON/v1/ImportExport.php
- -
message: "#^Parameter \\#7 \\$data of class MailPoet\\\\Subscribers\\\\ImportExport\\\\Import\\\\Import constructor expects array, mixed given\\.$#" message: "#^Parameter \\#8 \\$data of class MailPoet\\\\Subscribers\\\\ImportExport\\\\Import\\\\Import constructor expects array, mixed given\\.$#"
count: 1 count: 1
path: ../../lib/API/JSON/v1/ImportExport.php path: ../../lib/API/JSON/v1/ImportExport.php

View File

@ -55,7 +55,7 @@ parameters:
path: ../../lib/API/JSON/v1/ImportExport.php path: ../../lib/API/JSON/v1/ImportExport.php
- -
message: "#^Parameter \\#7 \\$data of class MailPoet\\\\Subscribers\\\\ImportExport\\\\Import\\\\Import constructor expects array, mixed given\\.$#" message: "#^Parameter \\#8 \\$data of class MailPoet\\\\Subscribers\\\\ImportExport\\\\Import\\\\Import constructor expects array, mixed given\\.$#"
count: 1 count: 1
path: ../../lib/API/JSON/v1/ImportExport.php path: ../../lib/API/JSON/v1/ImportExport.php

View File

@ -27,12 +27,6 @@ class ModelValidatorTest extends \MailPoetTest {
expect($this->validator->validateEmail('a@b.c'))->false(); expect($this->validator->validateEmail('a@b.c'))->false();
} }
public function testItValidatesNonRoleEmail() {
expect($this->validator->validateNonRoleEmail('test'))->false();
expect($this->validator->validateNonRoleEmail('webmaster@example.com'))->false();
expect($this->validator->validateNonRoleEmail('test@example.com'))->true();
}
public function testItValidatesRenderedNewsletterBody() { public function testItValidatesRenderedNewsletterBody() {
expect($this->validator->validateRenderedNewsletterBody('test'))->false(); expect($this->validator->validateRenderedNewsletterBody('test'))->false();
expect($this->validator->validateRenderedNewsletterBody(serialize('test')))->false(); expect($this->validator->validateRenderedNewsletterBody(serialize('test')))->false();

View File

@ -0,0 +1,28 @@
<?php declare(strict_types = 1);
namespace MailPoet\Test\Services;
use MailPoet\Services\Validator;
class ValidatorTest extends \MailPoetTest {
public $validator;
public function _before() {
parent::_before();
$this->validator = $this->diContainer->get(Validator::class);
}
public function testItValidatesEmail() {
expect($this->validator->validateEmail('test'))->false();
expect($this->validator->validateEmail('tést@éxample.com'))->false();
expect($this->validator->validateEmail('test@example.com'))->true();
expect($this->validator->validateEmail('loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_email@example.com'))->false();
expect($this->validator->validateEmail('a@b.c'))->false();
}
public function testItValidatesNonRoleEmail() {
expect($this->validator->validateNonRoleEmail('test'))->false();
expect($this->validator->validateNonRoleEmail('webmaster@example.com'))->false();
expect($this->validator->validateNonRoleEmail('test@example.com'))->true();
}
}

View File

@ -13,6 +13,7 @@ use MailPoet\Entities\TagEntity;
use MailPoet\Newsletter\Options\NewsletterOptionsRepository; use MailPoet\Newsletter\Options\NewsletterOptionsRepository;
use MailPoet\Segments\SegmentsRepository; use MailPoet\Segments\SegmentsRepository;
use MailPoet\Segments\WP; use MailPoet\Segments\WP;
use MailPoet\Services\Validator;
use MailPoet\Subscribers\ImportExport\ImportExportRepository; use MailPoet\Subscribers\ImportExport\ImportExportRepository;
use MailPoet\Subscribers\SubscriberCustomFieldRepository; use MailPoet\Subscribers\SubscriberCustomFieldRepository;
use MailPoet\Subscribers\SubscriberSegmentRepository; use MailPoet\Subscribers\SubscriberSegmentRepository;
@ -71,6 +72,9 @@ class ImportTest extends \MailPoetTest {
/** @var SubscriberTagRepository */ /** @var SubscriberTagRepository */
private $subscribersTagRepository; private $subscribersTagRepository;
/** @var Validator */
private $validator;
public function _before(): void { public function _before(): void {
$this->wpSegment = $this->diContainer->get(WP::class); $this->wpSegment = $this->diContainer->get(WP::class);
$this->customFieldsRepository = $this->diContainer->get(CustomFieldsRepository::class); $this->customFieldsRepository = $this->diContainer->get(CustomFieldsRepository::class);
@ -81,6 +85,7 @@ class ImportTest extends \MailPoetTest {
$this->subscriberRepository = $this->diContainer->get(SubscribersRepository::class); $this->subscriberRepository = $this->diContainer->get(SubscribersRepository::class);
$this->subscriberSegmentRepository = $this->diContainer->get(SubscriberSegmentRepository::class); $this->subscriberSegmentRepository = $this->diContainer->get(SubscriberSegmentRepository::class);
$this->tagRepository = $this->diContainer->get(TagRepository::class); $this->tagRepository = $this->diContainer->get(TagRepository::class);
$this->validator = $this->diContainer->get(Validator::class);
$this->subscribersTagRepository = $this->diContainer->get(SubscriberTagRepository::class); $this->subscribersTagRepository = $this->diContainer->get(SubscriberTagRepository::class);
$customField = $this->customFieldsRepository->createOrUpdate([ $customField = $this->customFieldsRepository->createOrUpdate([
'name' => 'country', 'name' => 'country',
@ -832,6 +837,7 @@ class ImportTest extends \MailPoetTest {
$this->newsletterOptionsRepository, $this->newsletterOptionsRepository,
$this->subscriberRepository, $this->subscriberRepository,
$this->tagRepository, $this->tagRepository,
$this->validator,
$data $data
); );
} }