Образован валидатор EmailValidator

This commit is contained in:
ErickSkrauch 2016-11-01 23:57:42 +03:00
parent 94a8e21f27
commit 91df81f97d
6 changed files with 184 additions and 92 deletions

View File

@ -9,6 +9,7 @@ use common\models\Account;
use common\models\confirmations\RegistrationConfirmation; use common\models\confirmations\RegistrationConfirmation;
use common\models\EmailActivation; use common\models\EmailActivation;
use common\models\UsernameHistory; use common\models\UsernameHistory;
use common\validators\EmailValidator;
use common\validators\LanguageValidator; use common\validators\LanguageValidator;
use common\validators\PasswordValidate; use common\validators\PasswordValidate;
use common\validators\UsernameValidator; use common\validators\UsernameValidator;
@ -42,7 +43,7 @@ class RegistrationForm extends ApiForm {
['rulesAgreement', 'required', 'message' => E::RULES_AGREEMENT_REQUIRED], ['rulesAgreement', 'required', 'message' => E::RULES_AGREEMENT_REQUIRED],
['username', UsernameValidator::class], ['username', UsernameValidator::class],
['email', 'validateEmail', 'skipOnEmpty' => false], ['email', EmailValidator::class],
['password', 'required', 'message' => E::PASSWORD_REQUIRED], ['password', 'required', 'message' => E::PASSWORD_REQUIRED],
['rePassword', 'required', 'message' => E::RE_PASSWORD_REQUIRED], ['rePassword', 'required', 'message' => E::RE_PASSWORD_REQUIRED],
@ -54,14 +55,6 @@ class RegistrationForm extends ApiForm {
]; ];
} }
public function validateEmail() {
$account = new Account();
$account->email = $this->email;
if (!$account->validate(['email'])) {
$this->addErrors($account->getErrors());
}
}
public function validatePasswordAndRePasswordMatch($attribute) { public function validatePasswordAndRePasswordMatch($attribute) {
if (!$this->hasErrors()) { if (!$this->hasErrors()) {
if ($this->password !== $this->rePassword) { if ($this->password !== $this->rePassword) {

View File

@ -2,10 +2,10 @@
namespace api\models\profile\ChangeEmail; namespace api\models\profile\ChangeEmail;
use api\models\base\KeyConfirmationForm; use api\models\base\KeyConfirmationForm;
use common\helpers\Error as E;
use common\models\Account; use common\models\Account;
use common\models\confirmations\NewEmailConfirmation; use common\models\confirmations\NewEmailConfirmation;
use common\models\EmailActivation; use common\models\EmailActivation;
use common\validators\EmailValidator;
use Yii; use Yii;
use yii\base\ErrorException; use yii\base\ErrorException;
use yii\base\Exception; use yii\base\Exception;
@ -25,26 +25,14 @@ class NewEmailForm extends KeyConfirmationForm {
parent::__construct($config); parent::__construct($config);
} }
/**
* @return Account
*/
public function getAccount() {
return $this->account;
}
public function rules() { public function rules() {
return array_merge(parent::rules(), [ return array_merge(parent::rules(), [
['email', 'required', 'message' => E::EMAIL_REQUIRED], ['email', EmailValidator::class],
['email', 'validateEmail'],
]); ]);
} }
public function validateEmail() { public function getAccount() : Account {
$account = new Account(); return $this->account;
$account->email = $this->email;
if (!$account->validate(['email'])) {
$this->addErrors($account->getErrors());
}
} }
public function sendNewEmailConfirmation() { public function sendNewEmailConfirmation() {

View File

@ -1,9 +1,7 @@
<?php <?php
namespace common\models; namespace common\models;
use common\helpers\Error as E;
use common\components\UserPass; use common\components\UserPass;
use Ely\Yii2\TempmailValidator;
use Yii; use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\behaviors\TimestampBehavior; use yii\behaviors\TimestampBehavior;
@ -59,17 +57,6 @@ class Account extends ActiveRecord {
]; ];
} }
public function rules() {
return [
[['email'], 'filter', 'filter' => 'trim'],
[['email'], 'required', 'message' => E::EMAIL_REQUIRED],
[['email'], 'string', 'max' => 255, 'tooLong' => E::EMAIL_TOO_LONG],
[['email'], 'email', 'checkDNS' => true, 'enableIDN' => true, 'message' => E::EMAIL_INVALID],
[['email'], TempmailValidator::class, 'message' => E::EMAIL_IS_TEMPMAIL],
[['email'], 'unique', 'message' => E::EMAIL_NOT_AVAILABLE],
];
}
/** /**
* Validates password * Validates password
* *

View File

@ -0,0 +1,64 @@
<?php
namespace common\validators;
use common\helpers\Error as E;
use common\models\Account;
use Ely\Yii2\TempmailValidator;
use yii\base\Model;
use yii\db\QueryInterface;
use yii\validators;
use yii\validators\Validator;
class EmailValidator extends Validator {
/**
* @var \Closure функция должна возвращать id аккаунта, относительно которого проводится
* текущая валидация. Позволяет пропустить проверку email для текущего аккаунта.
*/
public $accountCallback;
public $skipOnEmpty = false;
public function validateAttribute($model, $attribute) {
$filter = new validators\FilterValidator(['filter' => 'trim']);
$required = new validators\RequiredValidator();
$required->message = E::EMAIL_REQUIRED;
$length = new validators\StringValidator();
$length->max = 255;
$length->tooLong = E::EMAIL_TOO_LONG;
$email = new validators\EmailValidator();
$email->checkDNS = true;
$email->enableIDN = true;
$email->message = E::EMAIL_INVALID;
$tempmail = new TempmailValidator();
$tempmail->message = E::EMAIL_IS_TEMPMAIL;
$unique = new validators\UniqueValidator();
$unique->message = E::EMAIL_NOT_AVAILABLE;
$unique->targetClass = Account::class;
$unique->targetAttribute = 'email';
if ($this->accountCallback !== null) {
$unique->filter = function(QueryInterface $query) {
$query->andWhere(['NOT', ['id' => ($this->accountCallback)()]]);
};
}
$this->executeValidation($filter, $model, $attribute) &&
$this->executeValidation($required, $model, $attribute) &&
$this->executeValidation($length, $model, $attribute) &&
$this->executeValidation($email, $model, $attribute) &&
$this->executeValidation($tempmail, $model, $attribute) &&
$this->executeValidation($unique, $model, $attribute);
}
protected function executeValidation(Validator $validator, Model $model, string $attribute) {
$validator->validateAttribute($model, $attribute);
return !$model->hasErrors($attribute);
}
}

View File

@ -4,8 +4,6 @@ namespace tests\codeception\common\unit\models;
use Codeception\Specify; use Codeception\Specify;
use common\components\UserPass; use common\components\UserPass;
use common\models\Account; use common\models\Account;
use tests\codeception\common\fixtures\AccountFixture;
use tests\codeception\common\fixtures\MojangUsernameFixture;
use tests\codeception\common\unit\TestCase; use tests\codeception\common\unit\TestCase;
use Yii; use Yii;
use const common\LATEST_RULES_VERSION; use const common\LATEST_RULES_VERSION;
@ -13,59 +11,12 @@ use const common\LATEST_RULES_VERSION;
class AccountTest extends TestCase { class AccountTest extends TestCase {
use Specify; use Specify;
public function _fixtures() {
return [
'accounts' => AccountFixture::class,
'mojangAccounts' => MojangUsernameFixture::class,
];
}
public function testValidateEmail() {
// TODO: пропускать этот тест, если падает ошибка с недостпуностью интернет соединения
$this->specify('email required', function() {
$model = new Account(['email' => null]);
expect($model->validate(['email']))->false();
expect($model->getErrors('email'))->equals(['error.email_required']);
});
$this->specify('email should be not more 255 symbols (I hope it\'s impossible to register)', function() {
$model = new Account([
'email' => 'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'emailemail', // = 256 symbols
]);
expect($model->validate(['email']))->false();
expect($model->getErrors('email'))->equals(['error.email_too_long']);
});
$this->specify('email should be email (it test can fail, if you don\'t have internet connection)', function() {
$model = new Account(['email' => 'invalid_email']);
expect($model->validate(['email']))->false();
expect($model->getErrors('email'))->equals(['error.email_invalid']);
});
$this->specify('email should be not tempmail', function() {
$model = new Account(['email' => 'ibrpycwyjdnt@dropmail.me']);
expect($model->validate(['email']))->false();
expect($model->getErrors('email'))->equals(['error.email_is_tempmail']);
});
$this->specify('email should be unique', function() {
$model = new Account(['email' => $this->tester->grabFixture('accounts', 'admin')['email']]);
expect($model->validate('email'))->false();
expect($model->getErrors('email'))->equals(['error.email_not_available']);
});
}
public function testSetPassword() { public function testSetPassword() {
$this->specify('calling method should change password and set latest password hash algorithm', function() {
$model = new Account(); $model = new Account();
$model->setPassword('12345678'); $model->setPassword('12345678');
expect('hash should be set', $model->password_hash)->notEmpty(); $this->assertNotEmpty($model->password_hash, 'hash should be set');
expect('validation should be passed', $model->validatePassword('12345678'))->true(); $this->assertTrue($model->validatePassword('12345678'), 'validation should be passed');
expect('latest password hash should be used', $model->password_hash_strategy)->equals(Account::PASS_HASH_STRATEGY_YII2); $this->assertEquals(Account::PASS_HASH_STRATEGY_YII2, $model->password_hash_strategy, 'latest password hash should be used');
});
} }
public function testValidatePassword() { public function testValidatePassword() {

View File

@ -0,0 +1,109 @@
<?php
namespace codeception\common\unit\validators;
use common\validators\EmailValidator;
use tests\codeception\common\fixtures\AccountFixture;
use tests\codeception\common\unit\TestCase;
use yii\base\Model;
class EmailValidatorTest extends TestCase {
/**
* @var EmailValidator
*/
private $validator;
public function _before() {
parent::_before();
$this->validator = new EmailValidator();
}
public function testValidateAttributeRequired() {
$model = $this->createModel('');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_required'], $model->getErrors('field'));
$model = $this->createModel('email');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_required'], $model->getErrors('field'));
}
public function testValidateAttributeLength() {
$model = $this->createModel(
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'@gmail.com' // = 256 symbols
);
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_too_long'], $model->getErrors('field'));
$model = $this->createModel('some-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_too_long'], $model->getErrors('field'));
}
public function testValidateAttributeEmail() {
$model = $this->createModel('non-email');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_invalid'], $model->getErrors('field'));
$model = $this->createModel('non-email@etot-domen-ne-suschestrvyet.de');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_invalid'], $model->getErrors('field'));
$model = $this->createModel('valid-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_invalid'], $model->getErrors('field'));
}
public function testValidateAttributeTempmail() {
$model = $this->createModel('ibrpycwyjdnt@dropmail.me');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_is_tempmail'], $model->getErrors('field'));
$model = $this->createModel('valid-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_is_tempmail'], $model->getErrors('field'));
}
public function testValidateAttributeUnique() {
$this->tester->haveFixtures([
'accounts' => AccountFixture::class,
]);
/** @var \common\models\Account $accountFixture */
$accountFixture = $this->tester->grabFixture('accounts', 'admin');
$model = $this->createModel($accountFixture->email);
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_not_available'], $model->getErrors('field'));
$model = $this->createModel($accountFixture->email);
$this->validator->accountCallback = function() use ($accountFixture) {
return $accountFixture->id;
};
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_not_available'], $model->getErrors('field'));
$this->validator->accountCallback = null;
$model = $this->createModel('some-unique-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_not_available'], $model->getErrors('field'));
}
/**
* @param string $fieldValue
* @return Model
*/
private function createModel(string $fieldValue) : Model {
$class = new class extends Model {
public $field;
};
$class->field = $fieldValue;
return $class;
}
}