Упразднён контроллер PasswordProtectedController и заменён на валидатор PasswordRequiredValidator

Реорганизованы тесты для ChangeUsernameFormTest
This commit is contained in:
ErickSkrauch 2016-07-25 14:07:14 +03:00
parent a4dad11be5
commit 31679b84cb
9 changed files with 121 additions and 105 deletions

View File

@ -1,31 +0,0 @@
<?php
namespace api\models\base;
use common\helpers\Error as E;
use Yii;
class PasswordProtectedForm extends ApiForm {
public $password;
public function rules() {
return [
[['password'], 'required', 'message' => E::PASSWORD_REQUIRED],
[['password'], 'validatePassword'],
];
}
public function validatePassword() {
if (!$this->getAccount()->validatePassword($this->password)) {
$this->addError('password', E::PASSWORD_INVALID);
}
}
/**
* @return \common\models\Account
*/
protected function getAccount() {
return Yii::$app->user->identity;
}
}

View File

@ -1,7 +1,8 @@
<?php <?php
namespace api\models\profile\ChangeEmail; namespace api\models\profile\ChangeEmail;
use api\models\base\PasswordProtectedForm; use api\models\base\ApiForm;
use api\validators\PasswordRequiredValidator;
use common\helpers\Error as E; use common\helpers\Error as E;
use common\models\Account; use common\models\Account;
use common\models\confirmations\CurrentEmailConfirmation; use common\models\confirmations\CurrentEmailConfirmation;
@ -11,10 +12,12 @@ use yii\base\ErrorException;
use yii\base\Exception; use yii\base\Exception;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
class InitStateForm extends PasswordProtectedForm { class InitStateForm extends ApiForm {
public $email; public $email;
public $password;
private $account; private $account;
public function __construct(Account $account, array $config = []) { public function __construct(Account $account, array $config = []) {
@ -28,9 +31,10 @@ class InitStateForm extends PasswordProtectedForm {
} }
public function rules() { public function rules() {
return array_merge(parent::rules(), [ return [
['email', 'validateFrequency'], ['email', 'validateFrequency'],
]); ['password', PasswordRequiredValidator::class, 'account' => $this->account],
];
} }
public function validateFrequency($attribute) { public function validateFrequency($attribute) {
@ -90,7 +94,6 @@ class InitStateForm extends PasswordProtectedForm {
} }
public function sendCode(EmailActivation $code) { public function sendCode(EmailActivation $code) {
/** @var \yii\swiftmailer\Mailer $mailer */
$mailer = Yii::$app->mailer; $mailer = Yii::$app->mailer;
$fromEmail = Yii::$app->params['fromEmail']; $fromEmail = Yii::$app->params['fromEmail'];
if (!$fromEmail) { if (!$fromEmail) {
@ -98,7 +101,6 @@ class InitStateForm extends PasswordProtectedForm {
} }
$acceptor = $code->account; $acceptor = $code->account;
/** @var \yii\swiftmailer\Message $message */
$message = $mailer->compose([ $message = $mailer->compose([
'html' => '@app/mails/current-email-confirmation-html', 'html' => '@app/mails/current-email-confirmation-html',
'text' => '@app/mails/current-email-confirmation-text', 'text' => '@app/mails/current-email-confirmation-text',

View File

@ -1,7 +1,8 @@
<?php <?php
namespace api\models\profile; namespace api\models\profile;
use api\models\base\PasswordProtectedForm; use api\models\base\ApiForm;
use api\validators\PasswordRequiredValidator;
use common\helpers\Error as E; use common\helpers\Error as E;
use common\models\Account; use common\models\Account;
use common\validators\PasswordValidate; use common\validators\PasswordValidate;
@ -9,7 +10,7 @@ use Yii;
use yii\base\ErrorException; use yii\base\ErrorException;
use yii\helpers\ArrayHelper; use yii\helpers\ArrayHelper;
class ChangePasswordForm extends PasswordProtectedForm { class ChangePasswordForm extends ApiForm {
public $newPassword; public $newPassword;
@ -17,6 +18,8 @@ class ChangePasswordForm extends PasswordProtectedForm {
public $logoutAll; public $logoutAll;
public $password;
/** /**
* @var \common\models\Account * @var \common\models\Account
*/ */
@ -37,6 +40,7 @@ class ChangePasswordForm extends PasswordProtectedForm {
['newPassword', PasswordValidate::class], ['newPassword', PasswordValidate::class],
['newRePassword', 'validatePasswordAndRePasswordMatch'], ['newRePassword', 'validatePasswordAndRePasswordMatch'],
['logoutAll', 'boolean'], ['logoutAll', 'boolean'],
['password', PasswordRequiredValidator::class, 'account' => $this->_account],
]); ]);
} }
@ -49,7 +53,8 @@ class ChangePasswordForm extends PasswordProtectedForm {
} }
/** /**
* @return boolean * @return bool
* @throws ErrorException
*/ */
public function changePassword() : bool { public function changePassword() : bool {
if (!$this->validate()) { if (!$this->validate()) {

View File

@ -1,7 +1,9 @@
<?php <?php
namespace api\models\profile; namespace api\models\profile;
use api\models\base\PasswordProtectedForm; use api\models\AccountIdentity;
use api\models\base\ApiForm;
use api\validators\PasswordRequiredValidator;
use common\helpers\Error; use common\helpers\Error;
use common\helpers\Amqp; use common\helpers\Amqp;
use common\models\amqp\UsernameChanged; use common\models\amqp\UsernameChanged;
@ -10,17 +12,19 @@ use Exception;
use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Message\AMQPMessage;
use Yii; use Yii;
use yii\base\ErrorException; use yii\base\ErrorException;
use yii\helpers\ArrayHelper;
class ChangeUsernameForm extends PasswordProtectedForm { class ChangeUsernameForm extends ApiForm {
public $username; public $username;
public $password;
public function rules() { public function rules() {
return ArrayHelper::merge(parent::rules(), [ return [
['username', 'required', 'message' => Error::USERNAME_REQUIRED], ['username', 'required', 'message' => Error::USERNAME_REQUIRED],
['username', 'validateUsername'], ['username', 'validateUsername'],
]); ['password', PasswordRequiredValidator::class],
];
} }
public function validateUsername($attribute) { public function validateUsername($attribute) {
@ -84,4 +88,8 @@ class ChangeUsernameForm extends PasswordProtectedForm {
Amqp::sendToEventsExchange('accounts.username-changed', $message); Amqp::sendToEventsExchange('accounts.username-changed', $message);
} }
protected function getAccount() : AccountIdentity {
return Yii::$app->user->identity;
}
} }

View File

@ -0,0 +1,45 @@
<?php
namespace api\validators;
use common\helpers\Error as E;
use common\models\Account;
use Yii;
use yii\base\InvalidConfigException;
use yii\validators\Validator;
class PasswordRequiredValidator extends Validator {
/**
* @var Account
*/
public $account;
/**
* @inheritdoc
*/
public $skipOnEmpty = false;
public function init() {
parent::init();
if ($this->account === null) {
$this->account = Yii::$app->user->identity;
}
if (!$this->account instanceof Account) {
throw new InvalidConfigException('account should be instance of ' . Account::class);
}
}
protected function validateValue($value) {
if (empty($value)) {
return [E::PASSWORD_REQUIRED, []];
}
if ($this->account->validatePassword($value) === false) {
return [E::PASSWORD_INVALID, []];
}
return null;
}
}

View File

@ -89,7 +89,7 @@ class Account extends ActiveRecord {
* @return bool if password provided is valid for current user * @return bool if password provided is valid for current user
* @throws InvalidConfigException * @throws InvalidConfigException
*/ */
public function validatePassword($password, $passwordHashStrategy = NULL) { public function validatePassword($password, $passwordHashStrategy = NULL) : bool {
if ($passwordHashStrategy === NULL) { if ($passwordHashStrategy === NULL) {
$passwordHashStrategy = $this->password_hash_strategy; $passwordHashStrategy = $this->password_hash_strategy;
} }

View File

@ -1,38 +0,0 @@
<?php
namespace tests\codeception\api\models\base;
use api\models\base\PasswordProtectedForm;
use Codeception\Specify;
use common\models\Account;
use tests\codeception\api\unit\TestCase;
class PasswordProtectedFormTest extends TestCase {
use Specify;
public function testValidatePassword() {
$this->specify('error.password_invalid on passing invalid account password', function() {
$model = new DummyBasePasswordProtectedForm();
$model->password = 'some-invalid-password';
$model->validatePassword();
expect($model->getErrors('password'))->equals(['error.password_invalid']);
});
$this->specify('no errors on passing valid account password', function() {
$model = new DummyBasePasswordProtectedForm();
$model->password = 'password_0';
$model->validatePassword();
expect($model->getErrors('password'))->isEmpty();
});
}
}
class DummyBasePasswordProtectedForm extends PasswordProtectedForm {
protected function getAccount() {
return new Account([
'password' => 'password_0',
]);
}
}

View File

@ -1,6 +1,7 @@
<?php <?php
namespace tests\codeception\api\models\profile; namespace tests\codeception\api\models\profile;
use api\models\AccountIdentity;
use api\models\profile\ChangeUsernameForm; use api\models\profile\ChangeUsernameForm;
use Codeception\Specify; use Codeception\Specify;
use common\models\Account; use common\models\Account;
@ -8,6 +9,7 @@ use common\models\UsernameHistory;
use tests\codeception\api\unit\DbTestCase; use tests\codeception\api\unit\DbTestCase;
use tests\codeception\common\fixtures\AccountFixture; use tests\codeception\common\fixtures\AccountFixture;
use tests\codeception\common\fixtures\UsernameHistoryFixture; use tests\codeception\common\fixtures\UsernameHistoryFixture;
use Yii;
/** /**
* @property AccountFixture $accounts * @property AccountFixture $accounts
@ -22,9 +24,15 @@ class ChangeUsernameFormTest extends DbTestCase {
]; ];
} }
public function setUp() {
parent::setUp();
$account = AccountIdentity::findOne($this->getAccountId());
Yii::$app->user->setIdentity($account);
}
public function testChange() { public function testChange() {
$this->specify('successfully change username to new one', function() { $this->specify('successfully change username to new one', function() {
$model = $this->createModel([ $model = new ChangeUsernameForm([
'password' => 'password_0', 'password' => 'password_0',
'username' => 'my_new_nickname', 'username' => 'my_new_nickname',
]); ]);
@ -36,7 +44,7 @@ class ChangeUsernameFormTest extends DbTestCase {
public function testChangeWithoutChange() { public function testChangeWithoutChange() {
$this->specify('no new UsernameHistory record, if we don\'t change nickname', function() { $this->specify('no new UsernameHistory record, if we don\'t change nickname', function() {
$model = $this->createModel([ $model = new ChangeUsernameForm([
'password' => 'password_0', 'password' => 'password_0',
'username' => $this->accounts['admin']['username'], 'username' => $this->accounts['admin']['username'],
]); ]);
@ -53,7 +61,7 @@ class ChangeUsernameFormTest extends DbTestCase {
public function testChangeCase() { public function testChangeCase() {
$this->specify('username should change, if we change case of some letters', function() { $this->specify('username should change, if we change case of some letters', function() {
$newUsername = mb_strtoupper($this->accounts['admin']['username']); $newUsername = mb_strtoupper($this->accounts['admin']['username']);
$model = $this->createModel([ $model = new ChangeUsernameForm([
'password' => 'password_0', 'password' => 'password_0',
'username' => $newUsername, 'username' => $newUsername,
]); ]);
@ -65,7 +73,7 @@ class ChangeUsernameFormTest extends DbTestCase {
public function testValidateUsername() { public function testValidateUsername() {
$this->specify('error.username_not_available expected if username is already taken', function() { $this->specify('error.username_not_available expected if username is already taken', function() {
$model = $this->createModel([ $model = new ChangeUsernameForm([
'password' => 'password_0', 'password' => 'password_0',
'username' => 'Jon', 'username' => 'Jon',
]); ]);
@ -74,7 +82,7 @@ class ChangeUsernameFormTest extends DbTestCase {
}); });
$this->specify('error.username_not_available is NOT expected if username is already taken by CURRENT user', function() { $this->specify('error.username_not_available is NOT expected if username is already taken by CURRENT user', function() {
$model = $this->createModel([ $model = new ChangeUsernameForm([
'password' => 'password_0', 'password' => 'password_0',
'username' => $this->accounts['admin']['username'], 'username' => $this->accounts['admin']['username'],
]); ]);
@ -84,27 +92,12 @@ class ChangeUsernameFormTest extends DbTestCase {
} }
public function testCreateTask() { public function testCreateTask() {
$model = $this->createModel(); $model = new ChangeUsernameForm();
$model->createEventTask('1', 'test1', 'test'); $model->createEventTask('1', 'test1', 'test');
// TODO: у меня пока нет идей о том, чтобы это как-то успешно протестировать, увы // TODO: у меня пока нет идей о том, чтобы это как-то успешно протестировать, увы
// но по крайней мере можно убедиться, что оно не падает где-то на этом шаге // но по крайней мере можно убедиться, что оно не падает где-то на этом шаге
} }
private function createModel(array $params = []) : ChangeUsernameForm {
/** @noinspection PhpUnusedLocalVariableInspection */
$params = array_merge($params, [
'accountId' => $this->getAccountId(),
]);
return new class($params) extends ChangeUsernameForm {
public $accountId;
protected function getAccount() {
return Account::findOne($this->accountId);
}
};
}
private function getAccountId() { private function getAccountId() {
return $this->accounts['admin']['id']; return $this->accounts['admin']['id'];
} }

View File

@ -0,0 +1,32 @@
<?php
namespace codeception\api\unit\validators;
use api\validators\PasswordRequiredValidator;
use Codeception\Specify;
use common\models\Account;
use tests\codeception\api\unit\DbTestCase;
use tests\codeception\common\_support\ProtectedCaller;
class PasswordRequiredValidatorTest extends DbTestCase {
use Specify;
use ProtectedCaller;
public function testValidateValue() {
$account = new Account(['password' => '12345678']);
$this->specify('get error.password_required if password is empty', function () use ($account) {
$model = new PasswordRequiredValidator(['account' => $account]);
expect($this->callProtected($model, 'validateValue', ''))->equals(['error.password_required', []]);
});
$this->specify('get error.password_invalid if password is incorrect', function () use ($account) {
$model = new PasswordRequiredValidator(['account' => $account]);
expect($this->callProtected($model, 'validateValue', '87654321'))->equals(['error.password_invalid', []]);
});
$this->specify('no errors, if password is correct for provided account', function () use ($account) {
$model = new PasswordRequiredValidator(['account' => $account]);
expect($this->callProtected($model, 'validateValue', '12345678'))->null();
});
}
}