Reject requests without mandatory custom fields
We need to make sure subscribers cannot be created without custom fields Users require GDPR consent and we need to make sure there are no way to create a subscriber without mandatory custom fields [MAILPOET-1405]
This commit is contained in:
@ -64,7 +64,7 @@ class API {
|
||||
);
|
||||
|
||||
if(!$ignoreToken && $this->checkToken() === false) {
|
||||
$error_message = __('Sorry, but we couldn\'t connect to the MailPoet server. Please refresh the web page and try again.', 'mailpoet');
|
||||
$error_message = __("Sorry, but we couldn't connect to the MailPoet server. Please refresh the web page and try again.", 'mailpoet');
|
||||
$error_response = $this->createErrorResponse(Error::UNAUTHORIZED, $error_message, Response::STATUS_UNAUTHORIZED);
|
||||
return $error_response->send();
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Newsletter\Scheduler\Scheduler;
|
||||
use MailPoet\Segments\BulkAction;
|
||||
use MailPoet\Segments\SubscribersListings;
|
||||
use MailPoet\Subscribers\RequiredCustomFieldValidator;
|
||||
use MailPoet\Subscribers\Source;
|
||||
use MailPoet\Subscription\Throttling as SubscriptionThrottling;
|
||||
use MailPoet\WP\Hooks;
|
||||
@ -121,6 +122,13 @@ class Subscribers extends APIEndpoint {
|
||||
|
||||
$data = $this->deobfuscateFormPayload($data);
|
||||
|
||||
try {
|
||||
$validator = new RequiredCustomFieldValidator();
|
||||
$validator->validate($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->badRequest([APIError::BAD_REQUEST => $e->getMessage()]);
|
||||
}
|
||||
|
||||
$segment_ids = (!empty($data['segments'])
|
||||
? (array)$data['segments']
|
||||
: array()
|
||||
|
@ -6,6 +6,7 @@ use MailPoet\Models\Segment;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Newsletter\Scheduler\Scheduler;
|
||||
use MailPoet\Subscribers\RequiredCustomFieldValidator;
|
||||
use MailPoet\Subscribers\Source;
|
||||
use MailPoet\Tasks\Sending;
|
||||
|
||||
@ -164,6 +165,9 @@ class API {
|
||||
// if some required default fields are missing, set their values
|
||||
$default_fields = Subscriber::setRequiredFieldsDefaultValues($default_fields);
|
||||
|
||||
$validator = new RequiredCustomFieldValidator();
|
||||
$validator->validate($custom_fields);
|
||||
|
||||
// add subscriber
|
||||
$new_subscriber = Subscriber::create();
|
||||
$new_subscriber->hydrate($default_fields);
|
||||
|
55
lib/Subscribers/RequiredCustomFieldValidator.php
Normal file
55
lib/Subscribers/RequiredCustomFieldValidator.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Subscribers;
|
||||
|
||||
use MailPoet\Models\CustomField;
|
||||
|
||||
class RequiredCustomFieldValidator {
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validate(array $data) {
|
||||
$all_custom_fields = $this->getCustomFields();
|
||||
foreach($all_custom_fields as $custom_field_id => $custom_field_name) {
|
||||
if($this->isCustomFieldMissing($custom_field_id, $data)) {
|
||||
throw new \Exception(
|
||||
__(sprintf('Missing value for custom field "%s"', $custom_field_name), 'mailpoet')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function isCustomFieldMissing($custom_field_id, $data) {
|
||||
if(!array_key_exists($custom_field_id, $data) && !array_key_exists('cf_' . $custom_field_id, $data)) {
|
||||
return true;
|
||||
}
|
||||
if(isset($data[$custom_field_id]) && !$data[$custom_field_id]) {
|
||||
return true;
|
||||
}
|
||||
if(isset($data['cf_' . $custom_field_id]) && !$data['cf_' . $custom_field_id]) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getCustomFields() {
|
||||
$result = [];
|
||||
|
||||
$required_custom_fields = CustomField::findMany();
|
||||
|
||||
foreach($required_custom_fields as $custom_field) {
|
||||
if(is_serialized($custom_field->params)) {
|
||||
$params = unserialize($custom_field->params);
|
||||
if(is_array($params) && isset($params['required']) && $params['required']) {
|
||||
$result[$custom_field->id] = $custom_field->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
@ -6,6 +6,7 @@ use Codeception\Util\Fixtures;
|
||||
use MailPoet\API\JSON\v1\Subscribers;
|
||||
use MailPoet\API\JSON\Response as APIResponse;
|
||||
use MailPoet\Form\Util\FieldNameObfuscator;
|
||||
use MailPoet\Models\CustomField;
|
||||
use MailPoet\Models\Form;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterOption;
|
||||
@ -478,6 +479,21 @@ class SubscribersTest extends \MailPoetTest {
|
||||
Setting::setValue('re_captcha', array());
|
||||
}
|
||||
|
||||
function testItCannotSubscribeWithoutMandatoryCustomField() {
|
||||
CustomField::createOrUpdate([
|
||||
'name' => 'custom field',
|
||||
'type' => 'text',
|
||||
'params' => ['required' => '1']
|
||||
]);
|
||||
$router = new Subscribers();
|
||||
$response = $router->subscribe(array(
|
||||
$this->obfuscatedEmail => 'toto@mailpoet.com',
|
||||
'form_id' => $this->form->id,
|
||||
$this->obfuscatedSegments => array($this->segment_1->id, $this->segment_2->id)
|
||||
));
|
||||
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
function testItCanSubscribeWithoutSegmentsIfTheyAreSelectedByAdmin() {
|
||||
$form = $this->form->asArray();
|
||||
$form['settings']['segments_selected_by'] = 'admin';
|
||||
@ -642,5 +658,6 @@ class SubscribersTest extends \MailPoetTest {
|
||||
\ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||
\ORM::raw_execute('TRUNCATE ' . SubscriberSegment::$_table);
|
||||
\ORM::raw_execute('TRUNCATE ' . SubscriberIP::$_table);
|
||||
\ORM::raw_execute('TRUNCATE ' . CustomField::$_table);
|
||||
}
|
||||
}
|
||||
|
@ -301,6 +301,21 @@ class APITest extends \MailPoetTest {
|
||||
expect($result['source'])->equals('api');
|
||||
}
|
||||
|
||||
function testItChecksForMandatoryCustomFields() {
|
||||
CustomField::createOrUpdate([
|
||||
'name' => 'custom field',
|
||||
'type' => 'text',
|
||||
'params' => ['required' => '1']
|
||||
]);
|
||||
|
||||
$subscriber = array(
|
||||
'email' => 'test@example.com',
|
||||
);
|
||||
|
||||
$this->setExpectedException('Exception');
|
||||
API::MP(self::VERSION)->addSubscriber($subscriber);
|
||||
}
|
||||
|
||||
function testItSubscribesToSegmentsWhenAddingSubscriber() {
|
||||
$API = Stub::makeEmptyExcept(
|
||||
new \MailPoet\API\MP\v1\API(),
|
||||
|
48
tests/unit/Subscribers/RequiredCustomFieldValidatorTest.php
Normal file
48
tests/unit/Subscribers/RequiredCustomFieldValidatorTest.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Subscribers;
|
||||
|
||||
use MailPoet\Models\CustomField;
|
||||
|
||||
class RequiredCustomFieldValidatorTest extends \MailPoetTest {
|
||||
|
||||
private $custom_field;
|
||||
|
||||
function _before() {
|
||||
\ORM::raw_execute('TRUNCATE ' . CustomField::$_table);
|
||||
$this->custom_field = CustomField::createOrUpdate([
|
||||
'name' => 'custom field',
|
||||
'type' => 'text',
|
||||
'params' => ['required' => '1']
|
||||
]);
|
||||
}
|
||||
|
||||
function testItValidatesDataWithoutCustomField() {
|
||||
$validator = new RequiredCustomFieldValidator();
|
||||
$this->setExpectedException('Exception');
|
||||
$validator->validate([]);
|
||||
}
|
||||
|
||||
function testItValidatesDataWithCustomFieldPassedAsId() {
|
||||
$validator = new RequiredCustomFieldValidator();
|
||||
$validator->validate([$this->custom_field->id() => 'value']);
|
||||
}
|
||||
|
||||
function testItValidatesDataWithCustomFieldPassedAsCFId() {
|
||||
$validator = new RequiredCustomFieldValidator();
|
||||
$validator->validate(['cf_' . $this->custom_field->id() => 'custom field']);
|
||||
}
|
||||
|
||||
function testItValidatesDataWithEmptyCustomField() {
|
||||
$validator = new RequiredCustomFieldValidator();
|
||||
$this->setExpectedException('Exception');
|
||||
$validator->validate([$this->custom_field->id() => '']);
|
||||
}
|
||||
|
||||
function testItValidatesDataWithEmptyCustomFieldAsCFId() {
|
||||
$validator = new RequiredCustomFieldValidator();
|
||||
$this->setExpectedException('Exception');
|
||||
$validator->validate(['cf_' . $this->custom_field->id() => '']);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user