mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Merge branch 'normalization_of_errors'
This commit is contained in:
		@@ -5,6 +5,7 @@ use api\models\authentication\ForgotPasswordForm;
 | 
			
		||||
use api\models\authentication\LoginForm;
 | 
			
		||||
use api\models\authentication\RecoverPasswordForm;
 | 
			
		||||
use api\models\authentication\RefreshTokenForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\helpers\StringHelper;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\filters\AccessControl;
 | 
			
		||||
@@ -48,7 +49,7 @@ class AuthenticationController extends Controller {
 | 
			
		||||
                'errors' => $this->normalizeModelErrors($model->getErrors()),
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            if (ArrayHelper::getValue($data['errors'], 'login') === 'error.account_not_activated') {
 | 
			
		||||
            if (ArrayHelper::getValue($data['errors'], 'login') === E::ACCOUNT_NOT_ACTIVATED) {
 | 
			
		||||
                $data['data']['email'] = $model->getAccount()->email;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +70,7 @@ class AuthenticationController extends Controller {
 | 
			
		||||
                'errors' => $this->normalizeModelErrors($model->getErrors()),
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            if (ArrayHelper::getValue($data['errors'], 'login') === 'error.email_frequency') {
 | 
			
		||||
            if (ArrayHelper::getValue($data['errors'], 'login') === E::RECENTLY_SENT_MESSAGE) {
 | 
			
		||||
                $emailActivation = $model->getEmailActivation();
 | 
			
		||||
                $data['data'] = [
 | 
			
		||||
                    'canRepeatIn' => $emailActivation->canRepeatIn(),
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ namespace api\controllers;
 | 
			
		||||
use api\models\authentication\ConfirmEmailForm;
 | 
			
		||||
use api\models\authentication\RepeatAccountActivationForm;
 | 
			
		||||
use api\models\authentication\RegistrationForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\filters\AccessControl;
 | 
			
		||||
use yii\helpers\ArrayHelper;
 | 
			
		||||
@@ -60,7 +61,7 @@ class SignupController extends Controller {
 | 
			
		||||
                'errors' => $this->normalizeModelErrors($model->getErrors()),
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            if ($response['errors']['email'] === 'error.recently_sent_message') {
 | 
			
		||||
            if ($response['errors']['email'] === E::RECENTLY_SENT_MESSAGE) {
 | 
			
		||||
                $activation = $model->getActivation();
 | 
			
		||||
                $response['data'] = [
 | 
			
		||||
                    'canRepeatIn' => $activation->canRepeatIn(),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\models;
 | 
			
		||||
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use api\models\base\ApiForm;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\base\ErrorException;
 | 
			
		||||
@@ -18,9 +19,11 @@ class FeedbackForm extends ApiForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['subject', 'email', 'message'], 'required', 'message' => 'error.{attribute}_required'],
 | 
			
		||||
            ['subject', 'required', 'message' => E::SUBJECT_REQUIRED],
 | 
			
		||||
            ['email', 'required', 'message' => E::EMAIL_REQUIRED],
 | 
			
		||||
            ['message', 'required', 'message' => E::MESSAGE_REQUIRED],
 | 
			
		||||
            [['subject'], 'string', 'max' => 255],
 | 
			
		||||
            [['email'], 'email'],
 | 
			
		||||
            [['email'], 'email', 'message' => E::EMAIL_INVALID],
 | 
			
		||||
            [['message'], 'string', 'max' => 65535],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
namespace api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\models\base\ApiForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use api\traits\AccountFinder;
 | 
			
		||||
use common\components\UserFriendlyRandomKey;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
@@ -18,7 +19,7 @@ class ForgotPasswordForm extends ApiForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            ['login', 'required', 'message' => 'error.login_required'],
 | 
			
		||||
            ['login', 'required', 'message' => E::LOGIN_REQUIRED],
 | 
			
		||||
            ['login', 'validateLogin'],
 | 
			
		||||
            ['login', 'validateActivity'],
 | 
			
		||||
            ['login', 'validateFrequency'],
 | 
			
		||||
@@ -28,7 +29,7 @@ class ForgotPasswordForm extends ApiForm {
 | 
			
		||||
    public function validateLogin($attribute) {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            if ($this->getAccount() === null) {
 | 
			
		||||
                $this->addError($attribute, 'error.' . $attribute . '_not_exist');
 | 
			
		||||
                $this->addError($attribute, E::LOGIN_NOT_EXIST);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -37,7 +38,7 @@ class ForgotPasswordForm extends ApiForm {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            $account = $this->getAccount();
 | 
			
		||||
            if ($account->status !== Account::STATUS_ACTIVE) {
 | 
			
		||||
                $this->addError($attribute, 'error.account_not_activated');
 | 
			
		||||
                $this->addError($attribute, E::ACCOUNT_NOT_ACTIVATED);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -46,7 +47,7 @@ class ForgotPasswordForm extends ApiForm {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            $emailConfirmation = $this->getEmailActivation();
 | 
			
		||||
            if ($emailConfirmation !== null && !$emailConfirmation->canRepeat()) {
 | 
			
		||||
                $this->addError($attribute, 'error.email_frequency');
 | 
			
		||||
                $this->addError($attribute, E::RECENTLY_SENT_MESSAGE);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ namespace api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\models\base\ApiForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use api\traits\AccountFinder;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use Yii;
 | 
			
		||||
@@ -19,12 +20,12 @@ class LoginForm extends ApiForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            ['login', 'required', 'message' => 'error.login_required'],
 | 
			
		||||
            ['login', 'required', 'message' => E::LOGIN_REQUIRED],
 | 
			
		||||
            ['login', 'validateLogin'],
 | 
			
		||||
 | 
			
		||||
            ['password', 'required', 'when' => function(self $model) {
 | 
			
		||||
                return !$model->hasErrors();
 | 
			
		||||
            }, 'message' => 'error.password_required'],
 | 
			
		||||
            }, 'message' => E::PASSWORD_REQUIRED],
 | 
			
		||||
            ['password', 'validatePassword'],
 | 
			
		||||
 | 
			
		||||
            ['login', 'validateActivity'],
 | 
			
		||||
@@ -36,7 +37,7 @@ class LoginForm extends ApiForm {
 | 
			
		||||
    public function validateLogin($attribute) {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            if ($this->getAccount() === null) {
 | 
			
		||||
                $this->addError($attribute, 'error.' . $attribute . '_not_exist');
 | 
			
		||||
                $this->addError($attribute, E::LOGIN_NOT_EXIST);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -45,7 +46,7 @@ class LoginForm extends ApiForm {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            $account = $this->getAccount();
 | 
			
		||||
            if ($account === null || !$account->validatePassword($this->password)) {
 | 
			
		||||
                $this->addError($attribute, 'error.' . $attribute . '_incorrect');
 | 
			
		||||
                $this->addError($attribute, E::PASSWORD_INCORRECT);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -54,7 +55,7 @@ class LoginForm extends ApiForm {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            $account = $this->getAccount();
 | 
			
		||||
            if ($account->status !== Account::STATUS_ACTIVE) {
 | 
			
		||||
                $this->addError($attribute, 'error.account_not_activated');
 | 
			
		||||
                $this->addError($attribute, E::ACCOUNT_NOT_ACTIVATED);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ namespace api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\models\base\KeyConfirmationForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
use common\validators\PasswordValidate;
 | 
			
		||||
use Yii;
 | 
			
		||||
@@ -16,7 +17,8 @@ class RecoverPasswordForm extends KeyConfirmationForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return array_merge(parent::rules(), [
 | 
			
		||||
            [['newPassword', 'newRePassword'], 'required', 'message' => 'error.{attribute}_required'],
 | 
			
		||||
            ['newPassword', 'required', 'message' => E::NEW_PASSWORD_REQUIRED],
 | 
			
		||||
            ['newRePassword', 'required', 'message' => E::NEW_RE_PASSWORD_REQUIRED],
 | 
			
		||||
            ['newPassword', PasswordValidate::class],
 | 
			
		||||
            ['newRePassword', 'validatePasswordAndRePasswordMatch'],
 | 
			
		||||
        ]);
 | 
			
		||||
@@ -25,7 +27,7 @@ class RecoverPasswordForm extends KeyConfirmationForm {
 | 
			
		||||
    public function validatePasswordAndRePasswordMatch($attribute) {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            if ($this->newPassword !== $this->newRePassword) {
 | 
			
		||||
                $this->addError($attribute, 'error.rePassword_does_not_match');
 | 
			
		||||
                $this->addError($attribute, E::NEW_RE_PASSWORD_DOES_NOT_MATCH);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
namespace api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\models\base\ApiForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
@@ -16,7 +17,7 @@ class RefreshTokenForm extends ApiForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            ['refresh_token', 'required'],
 | 
			
		||||
            ['refresh_token', 'required', 'message' => E::REFRESH_TOKEN_REQUIRED],
 | 
			
		||||
            ['refresh_token', 'validateRefreshToken'],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
@@ -25,7 +26,7 @@ class RefreshTokenForm extends ApiForm {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            /** @var AccountSession|null $token */
 | 
			
		||||
            if ($this->getSession() === null) {
 | 
			
		||||
                $this->addError('refresh_token', 'error.refresh_token_not_exist');
 | 
			
		||||
                $this->addError('refresh_token', E::REFRESH_TOKEN_NOT_EXISTS);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ namespace api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\components\ReCaptcha\Validator as ReCaptchaValidator;
 | 
			
		||||
use api\models\base\ApiForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use api\models\profile\ChangeUsernameForm;
 | 
			
		||||
use common\components\UserFriendlyRandomKey;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
@@ -26,14 +27,14 @@ class RegistrationForm extends ApiForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [[], ReCaptchaValidator::class, 'message' => 'error.captcha_invalid', 'when' => !YII_ENV_TEST],
 | 
			
		||||
            ['rulesAgreement', 'required', 'message' => 'error.you_must_accept_rules'],
 | 
			
		||||
            [[], ReCaptchaValidator::class, 'message' => E::CAPTCHA_INVALID, 'when' => !YII_ENV_TEST],
 | 
			
		||||
            ['rulesAgreement', 'required', 'message' => E::RULES_AGREEMENT_REQUIRED],
 | 
			
		||||
 | 
			
		||||
            ['username', 'validateUsername', 'skipOnEmpty' => false],
 | 
			
		||||
            ['email', 'validateEmail', 'skipOnEmpty' => false],
 | 
			
		||||
 | 
			
		||||
            ['password', 'required', 'message' => 'error.password_required'],
 | 
			
		||||
            ['rePassword', 'required', 'message' => 'error.rePassword_required'],
 | 
			
		||||
            ['password', 'required', 'message' => E::PASSWORD_REQUIRED],
 | 
			
		||||
            ['rePassword', 'required', 'message' => E::RE_PASSWORD_REQUIRED],
 | 
			
		||||
            ['password', PasswordValidate::class],
 | 
			
		||||
            ['rePassword', 'validatePasswordAndRePasswordMatch'],
 | 
			
		||||
 | 
			
		||||
@@ -60,7 +61,7 @@ class RegistrationForm extends ApiForm {
 | 
			
		||||
    public function validatePasswordAndRePasswordMatch($attribute) {
 | 
			
		||||
        if (!$this->hasErrors()) {
 | 
			
		||||
            if ($this->password !== $this->rePassword) {
 | 
			
		||||
                $this->addError($attribute, "error.rePassword_does_not_match");
 | 
			
		||||
                $this->addError($attribute, E::RE_PASSWORD_DOES_NOT_MATCH);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
namespace api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\models\base\ApiForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\components\UserFriendlyRandomKey;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\confirmations\RegistrationConfirmation;
 | 
			
		||||
@@ -18,7 +19,7 @@ class RepeatAccountActivationForm extends ApiForm {
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            ['email', 'filter', 'filter' => 'trim'],
 | 
			
		||||
            ['email', 'required', 'message' => 'error.email_required'],
 | 
			
		||||
            ['email', 'required', 'message' => E::EMAIL_REQUIRED],
 | 
			
		||||
            ['email', 'validateEmailForAccount'],
 | 
			
		||||
            ['email', 'validateExistsActivation'],
 | 
			
		||||
        ];
 | 
			
		||||
@@ -28,12 +29,12 @@ class RepeatAccountActivationForm extends ApiForm {
 | 
			
		||||
        if (!$this->hasErrors($attribute)) {
 | 
			
		||||
            $account = $this->getAccount();
 | 
			
		||||
            if ($account === null) {
 | 
			
		||||
                $this->addError($attribute, "error.{$attribute}_not_found");
 | 
			
		||||
                $this->addError($attribute, E::EMAIL_NOT_FOUND);
 | 
			
		||||
            } elseif ($account->status === Account::STATUS_ACTIVE) {
 | 
			
		||||
                $this->addError($attribute, "error.account_already_activated");
 | 
			
		||||
                $this->addError($attribute, E::ACCOUNT_ALREADY_ACTIVATED);
 | 
			
		||||
            } elseif ($account->status !== Account::STATUS_REGISTERED) {
 | 
			
		||||
                // TODO: такие аккаунты следует логировать за попытку к саботажу
 | 
			
		||||
                $this->addError($attribute, "error.account_cannot_resend_message");
 | 
			
		||||
                $this->addError($attribute, E::ACCOUNT_CANNOT_RESEND_MESSAGE);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -42,7 +43,7 @@ class RepeatAccountActivationForm extends ApiForm {
 | 
			
		||||
        if (!$this->hasErrors($attribute)) {
 | 
			
		||||
            $activation = $this->getActivation();
 | 
			
		||||
            if ($activation !== null && !$activation->canRepeat()) {
 | 
			
		||||
                $this->addError($attribute, 'error.recently_sent_message');
 | 
			
		||||
                $this->addError($attribute, E::RECENTLY_SENT_MESSAGE);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\models\base;
 | 
			
		||||
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use api\validators\EmailActivationKeyValidator;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
 | 
			
		||||
@@ -13,7 +14,7 @@ class KeyConfirmationForm extends ApiForm {
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            // TODO: нужно провалидировать количество попыток ввода кода для определённого IP адреса и в случае чего запросить капчу
 | 
			
		||||
            ['key', 'required', 'message' => 'error.key_is_required'],
 | 
			
		||||
            ['key', 'required', 'message' => E::KEY_REQUIRED],
 | 
			
		||||
            ['key', EmailActivationKeyValidator::class],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\models\base;
 | 
			
		||||
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
class PasswordProtectedForm extends ApiForm {
 | 
			
		||||
@@ -9,14 +10,14 @@ class PasswordProtectedForm extends ApiForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['password'], 'required', 'message' => 'error.password_required'],
 | 
			
		||||
            [['password'], 'required', 'message' => E::PASSWORD_REQUIRED],
 | 
			
		||||
            [['password'], 'validatePassword'],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function validatePassword() {
 | 
			
		||||
        if (!$this->getAccount()->validatePassword($this->password)) {
 | 
			
		||||
            $this->addError('password', 'error.password_invalid');
 | 
			
		||||
            $this->addError('password', E::PASSWORD_INVALID);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,11 +22,11 @@ class ConfirmNewEmailForm extends KeyConfirmationForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * @return Account
 | 
			
		||||
     */
 | 
			
		||||
    public function getAccount() {
 | 
			
		||||
    public function getAccount() : Account {
 | 
			
		||||
        return $this->account;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function changeEmail() {
 | 
			
		||||
    public function changeEmail() : bool {
 | 
			
		||||
        if (!$this->validate()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ class InitStateForm extends PasswordProtectedForm {
 | 
			
		||||
        parent::__construct($config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAccount() {
 | 
			
		||||
    public function getAccount() : Account {
 | 
			
		||||
        return $this->account;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +32,7 @@ class InitStateForm extends PasswordProtectedForm {
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function sendCurrentEmailConfirmation() {
 | 
			
		||||
    public function sendCurrentEmailConfirmation() : bool {
 | 
			
		||||
        if (!$this->validate()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -55,7 +55,7 @@ class InitStateForm extends PasswordProtectedForm {
 | 
			
		||||
     * @return CurrentEmailConfirmation
 | 
			
		||||
     * @throws ErrorException
 | 
			
		||||
     */
 | 
			
		||||
    public function createCode() {
 | 
			
		||||
    public function createCode() : CurrentEmailConfirmation {
 | 
			
		||||
        $account = $this->getAccount();
 | 
			
		||||
        $emailActivation = new CurrentEmailConfirmation();
 | 
			
		||||
        $emailActivation->account_id = $account->id;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
namespace api\models\profile\ChangeEmail;
 | 
			
		||||
 | 
			
		||||
use api\models\base\KeyConfirmationForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\confirmations\NewEmailConfirmation;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
@@ -33,7 +34,7 @@ class NewEmailForm extends KeyConfirmationForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return array_merge(parent::rules(), [
 | 
			
		||||
            ['email', 'required', 'message' => 'error.email_required'],
 | 
			
		||||
            ['email', 'required', 'message' => E::EMAIL_REQUIRED],
 | 
			
		||||
            ['email', 'validateEmail'],
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
namespace api\models\profile;
 | 
			
		||||
 | 
			
		||||
use api\models\base\PasswordProtectedForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\validators\PasswordValidate;
 | 
			
		||||
use Yii;
 | 
			
		||||
@@ -31,7 +32,8 @@ class ChangePasswordForm extends PasswordProtectedForm {
 | 
			
		||||
     */
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return ArrayHelper::merge(parent::rules(), [
 | 
			
		||||
            [['newPassword', 'newRePassword'], 'required', 'message' => 'error.{attribute}_required'],
 | 
			
		||||
            ['newPassword', 'required', 'message' => E::NEW_PASSWORD_REQUIRED],
 | 
			
		||||
            ['newRePassword', 'required', 'message' => E::NEW_RE_PASSWORD_REQUIRED],
 | 
			
		||||
            ['newPassword', PasswordValidate::class],
 | 
			
		||||
            ['newRePassword', 'validatePasswordAndRePasswordMatch'],
 | 
			
		||||
            ['logoutAll', 'boolean'],
 | 
			
		||||
@@ -41,7 +43,7 @@ class ChangePasswordForm extends PasswordProtectedForm {
 | 
			
		||||
    public function validatePasswordAndRePasswordMatch($attribute) {
 | 
			
		||||
        if (!$this->hasErrors($attribute)) {
 | 
			
		||||
            if ($this->newPassword !== $this->newRePassword) {
 | 
			
		||||
                $this->addError($attribute, 'error.newRePassword_does_not_match');
 | 
			
		||||
                $this->addError($attribute, E::NEW_RE_PASSWORD_DOES_NOT_MATCH);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -49,7 +51,7 @@ class ChangePasswordForm extends PasswordProtectedForm {
 | 
			
		||||
    /**
 | 
			
		||||
     * @return boolean
 | 
			
		||||
     */
 | 
			
		||||
    public function changePassword() {
 | 
			
		||||
    public function changePassword() : bool {
 | 
			
		||||
        if (!$this->validate()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -79,7 +81,7 @@ class ChangePasswordForm extends PasswordProtectedForm {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getAccount() {
 | 
			
		||||
    protected function getAccount() : Account {
 | 
			
		||||
        return $this->_account;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
namespace api\models\profile;
 | 
			
		||||
 | 
			
		||||
use api\models\base\PasswordProtectedForm;
 | 
			
		||||
use common\helpers\Error;
 | 
			
		||||
use common\helpers\Amqp;
 | 
			
		||||
use common\models\amqp\UsernameChanged;
 | 
			
		||||
use common\models\UsernameHistory;
 | 
			
		||||
@@ -16,8 +17,8 @@ class ChangeUsernameForm extends PasswordProtectedForm {
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return ArrayHelper::merge(parent::rules(), [
 | 
			
		||||
            [['username'], 'required', 'message' => 'error.{attribute}_required'],
 | 
			
		||||
            [['username'], 'validateUsername'],
 | 
			
		||||
            ['username', 'required', 'message' => Error::USERNAME_REQUIRED],
 | 
			
		||||
            ['username', 'validateUsername'],
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,15 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\validators;
 | 
			
		||||
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
use yii\validators\Validator;
 | 
			
		||||
 | 
			
		||||
class EmailActivationKeyValidator extends Validator {
 | 
			
		||||
 | 
			
		||||
    public $notExist = 'error.key_not_exists';
 | 
			
		||||
    public $notExist = E::KEY_NOT_EXISTS;
 | 
			
		||||
 | 
			
		||||
    public $expired = 'error.key_expire';
 | 
			
		||||
    public $expired = E::KEY_EXPIRE;
 | 
			
		||||
 | 
			
		||||
    public function validateValue($value) {
 | 
			
		||||
        if (($model = $this->findEmailActivationModel($value)) === null) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								common/helpers/Error.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								common/helpers/Error.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace common\helpers;
 | 
			
		||||
 | 
			
		||||
final class Error {
 | 
			
		||||
 | 
			
		||||
    const USERNAME_REQUIRED = 'error.username_required';
 | 
			
		||||
    const USERNAME_TOO_SHORT = 'error.username_too_short';
 | 
			
		||||
    const USERNAME_TOO_LONG = 'error.username_too_long';
 | 
			
		||||
    const USERNAME_INVALID = 'error.username_invalid';
 | 
			
		||||
    const USERNAME_NOT_AVAILABLE = 'error.username_not_available';
 | 
			
		||||
 | 
			
		||||
    const EMAIL_REQUIRED = 'error.email_required';
 | 
			
		||||
    const EMAIL_TOO_LONG = 'error.email_too_long';
 | 
			
		||||
    const EMAIL_INVALID = 'error.email_invalid';
 | 
			
		||||
    const EMAIL_IS_TEMPMAIL = 'error.email_is_tempmail';
 | 
			
		||||
    const EMAIL_NOT_AVAILABLE = 'error.email_not_available';
 | 
			
		||||
    const EMAIL_NOT_FOUND = 'error.email_not_found';
 | 
			
		||||
 | 
			
		||||
    const LOGIN_REQUIRED = 'error.login_required';
 | 
			
		||||
    const LOGIN_NOT_EXIST = 'error.login_not_exist';
 | 
			
		||||
 | 
			
		||||
    const PASSWORD_REQUIRED = 'error.password_required';
 | 
			
		||||
    const PASSWORD_INVALID = 'error.password_invalid';
 | 
			
		||||
    /**
 | 
			
		||||
     * TODO: На фронте с password_incorrect и password_invalid возникла неувязочка.
 | 
			
		||||
     * Один возникает у формы входа и там уместно предлагать восстановление пароля.
 | 
			
		||||
     * Другой возникает у паролезащищённой формы и там уже ничего предлагать не нужно.
 | 
			
		||||
     * Но по факту это ведь одна и та же ошибка.
 | 
			
		||||
     * @deprecated
 | 
			
		||||
     */
 | 
			
		||||
    const PASSWORD_INCORRECT = 'error.password_incorrect';
 | 
			
		||||
    const PASSWORD_TOO_SHORT = 'error.password_too_short';
 | 
			
		||||
 | 
			
		||||
    const KEY_REQUIRED = 'error.key_required';
 | 
			
		||||
    const KEY_NOT_EXISTS = 'error.key_not_exists';
 | 
			
		||||
    const KEY_EXPIRE = 'error.key_expire';
 | 
			
		||||
 | 
			
		||||
    const ACCOUNT_NOT_ACTIVATED = 'error.account_not_activated';
 | 
			
		||||
    const ACCOUNT_ALREADY_ACTIVATED = 'error.account_already_activated';
 | 
			
		||||
    const ACCOUNT_CANNOT_RESEND_MESSAGE = 'error.account_cannot_resend_message';
 | 
			
		||||
 | 
			
		||||
    const RECENTLY_SENT_MESSAGE = 'error.recently_sent_message';
 | 
			
		||||
 | 
			
		||||
    const NEW_PASSWORD_REQUIRED = 'error.newPassword_required';
 | 
			
		||||
    const NEW_RE_PASSWORD_REQUIRED = 'error.newRePassword_required';
 | 
			
		||||
    const NEW_RE_PASSWORD_DOES_NOT_MATCH = self::RE_PASSWORD_DOES_NOT_MATCH;
 | 
			
		||||
 | 
			
		||||
    const REFRESH_TOKEN_REQUIRED = 'error.refresh_token_required';
 | 
			
		||||
    const REFRESH_TOKEN_NOT_EXISTS = 'error.refresh_token_not_exist';
 | 
			
		||||
 | 
			
		||||
    const CAPTCHA_INVALID = 'error.captcha_invalid';
 | 
			
		||||
 | 
			
		||||
    const RULES_AGREEMENT_REQUIRED = 'error.rulesAgreement_required';
 | 
			
		||||
 | 
			
		||||
    const RE_PASSWORD_REQUIRED = 'error.rePassword_required';
 | 
			
		||||
    const RE_PASSWORD_DOES_NOT_MATCH = 'error.rePassword_does_not_match';
 | 
			
		||||
 | 
			
		||||
    const UNSUPPORTED_LANGUAGE = 'error.unsupported_language';
 | 
			
		||||
 | 
			
		||||
    const SUBJECT_REQUIRED = 'error.subject_required';
 | 
			
		||||
    const MESSAGE_REQUIRED = 'error.message_required';
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace common\models;
 | 
			
		||||
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\components\UserPass;
 | 
			
		||||
use common\validators\LanguageValidator;
 | 
			
		||||
use Ely\Yii2\TempmailValidator;
 | 
			
		||||
@@ -57,22 +58,22 @@ class Account extends ActiveRecord {
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['username'], 'filter', 'filter' => 'trim'],
 | 
			
		||||
            [['username'], 'required', 'message' => 'error.username_required'],
 | 
			
		||||
            [['username'], 'required', 'message' => E::USERNAME_REQUIRED],
 | 
			
		||||
            [['username'], 'string', 'min' => 3, 'max' => 21,
 | 
			
		||||
                'tooShort' => 'error.username_too_short',
 | 
			
		||||
                'tooLong' => 'error.username_too_long',
 | 
			
		||||
                'tooShort' => E::USERNAME_TOO_SHORT,
 | 
			
		||||
                'tooLong' => E::USERNAME_TOO_LONG,
 | 
			
		||||
            ],
 | 
			
		||||
            [['username'], 'match', 'pattern' => '/^[\p{L}\d-_\.!?#$%^&*()\[\]:;]+$/u',
 | 
			
		||||
                'message' => 'error.username_invalid',
 | 
			
		||||
                'message' => E::USERNAME_INVALID,
 | 
			
		||||
            ],
 | 
			
		||||
            [['username'], 'unique', 'message' => 'error.username_not_available'],
 | 
			
		||||
            [['username'], 'unique', 'message' => E::USERNAME_NOT_AVAILABLE],
 | 
			
		||||
 | 
			
		||||
            [['email'], 'filter', 'filter' => 'trim'],
 | 
			
		||||
            [['email'], 'required', 'message' => 'error.email_required'],
 | 
			
		||||
            [['email'], 'string', 'max' => 255, 'tooLong' => 'error.email_too_long'],
 | 
			
		||||
            [['email'], 'email', 'checkDNS' => true, 'enableIDN' => true, 'message' => 'error.email_invalid'],
 | 
			
		||||
            [['email'], TempmailValidator::class, 'message' => 'error.email_is_tempmail'],
 | 
			
		||||
            [['email'], 'unique', 'message' => 'error.email_not_available'],
 | 
			
		||||
            [['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],
 | 
			
		||||
 | 
			
		||||
            [['lang'], LanguageValidator::class],
 | 
			
		||||
            [['lang'], 'default', 'value' => 'en'],
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace common\validators;
 | 
			
		||||
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\validators\Validator;
 | 
			
		||||
 | 
			
		||||
class LanguageValidator extends Validator {
 | 
			
		||||
 | 
			
		||||
    public $message = 'error.unsupported_language';
 | 
			
		||||
    public $message = E::UNSUPPORTED_LANGUAGE;
 | 
			
		||||
 | 
			
		||||
    protected function validateValue($value) {
 | 
			
		||||
        if (empty($value)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace common\validators;
 | 
			
		||||
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use yii\validators\StringValidator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -10,6 +11,6 @@ class PasswordValidate extends StringValidator {
 | 
			
		||||
 | 
			
		||||
    public $min = 8;
 | 
			
		||||
 | 
			
		||||
    public $tooShort = 'error.password_too_short';
 | 
			
		||||
    public $tooShort = E::PASSWORD_TOO_SHORT;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ class EmailConfirmationCest {
 | 
			
		||||
        $I->canSeeResponseContainsJson([
 | 
			
		||||
            'success' => false,
 | 
			
		||||
            'errors' => [
 | 
			
		||||
                'key' => 'error.key_is_required',
 | 
			
		||||
                'key' => 'error.key_required',
 | 
			
		||||
            ],
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ class ForgotPasswordCest {
 | 
			
		||||
        $I->canSeeResponseContainsJson([
 | 
			
		||||
            'success' => false,
 | 
			
		||||
            'errors' => [
 | 
			
		||||
                'login' => 'error.email_frequency',
 | 
			
		||||
                'login' => 'error.recently_sent_message',
 | 
			
		||||
            ],
 | 
			
		||||
        ]);
 | 
			
		||||
        $I->canSeeResponseJsonMatchesJsonPath('$.data.canRepeatIn');
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ class RegisterCest {
 | 
			
		||||
    public function testIncorrectRegistration(FunctionalTester $I) {
 | 
			
		||||
        $route = new SignupRoute($I);
 | 
			
		||||
 | 
			
		||||
        $I->wantTo('get error.you_must_accept_rules if we don\'t accept rules');
 | 
			
		||||
        $I->wantTo('get error.rulesAgreement_required if we don\'t accept rules');
 | 
			
		||||
        $route->register([
 | 
			
		||||
            'username' => 'ErickSkrauch',
 | 
			
		||||
            'email' => 'erickskrauch@ely.by',
 | 
			
		||||
@@ -28,17 +28,17 @@ class RegisterCest {
 | 
			
		||||
        $I->canSeeResponseContainsJson([
 | 
			
		||||
            'success' => false,
 | 
			
		||||
            'errors' => [
 | 
			
		||||
                'rulesAgreement' => 'error.you_must_accept_rules',
 | 
			
		||||
                'rulesAgreement' => 'error.rulesAgreement_required',
 | 
			
		||||
            ],
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $I->wantTo('don\'t see error.you_must_accept_rules if we accept rules');
 | 
			
		||||
        $I->wantTo('don\'t see error.rulesAgreement_requireds if we accept rules');
 | 
			
		||||
        $route->register([
 | 
			
		||||
            'rulesAgreement' => true,
 | 
			
		||||
        ]);
 | 
			
		||||
        $I->cantSeeResponseContainsJson([
 | 
			
		||||
            'errors' => [
 | 
			
		||||
                'rulesAgreement' => 'error.you_must_accept_rules',
 | 
			
		||||
                'rulesAgreement' => 'error.rulesAgreement_required',
 | 
			
		||||
            ],
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ class ForgotPasswordFormTest extends DbTestCase {
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            $model->validateFrequency('login');
 | 
			
		||||
            expect($model->getErrors('login'))->equals(['error.email_frequency']);
 | 
			
		||||
            expect($model->getErrors('login'))->equals(['error.recently_sent_message']);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('empty errors if email was sent a long time ago', function() {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ class ChangePasswordFormTest extends DbTestCase {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testValidatePasswordAndRePasswordMatch() {
 | 
			
		||||
        $this->specify('error.newRePassword_does_not_match expected if passwords not match', function() {
 | 
			
		||||
        $this->specify('error.rePassword_does_not_match expected if passwords not match', function() {
 | 
			
		||||
            $account = new Account();
 | 
			
		||||
            $account->setPassword('12345678');
 | 
			
		||||
            $model = new ChangePasswordForm($account, [
 | 
			
		||||
@@ -36,7 +36,7 @@ class ChangePasswordFormTest extends DbTestCase {
 | 
			
		||||
                'newRePassword' => 'another-password',
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validatePasswordAndRePasswordMatch('newRePassword');
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->equals(['error.newRePassword_does_not_match']);
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->equals(['error.rePassword_does_not_match']);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('no errors expected if passwords are valid', function() {
 | 
			
		||||
@@ -51,7 +51,7 @@ class ChangePasswordFormTest extends DbTestCase {
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->isEmpty();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('error.newRePassword_does_not_match expected even if there are errors on other attributes', function() {
 | 
			
		||||
        $this->specify('error.rePassword_does_not_match expected even if there are errors on other attributes', function() {
 | 
			
		||||
            // this is very important, because password change flow may be combined of two steps
 | 
			
		||||
            // therefore we need to validate password sameness before we will validate current account password
 | 
			
		||||
            $account = new Account();
 | 
			
		||||
@@ -61,7 +61,7 @@ class ChangePasswordFormTest extends DbTestCase {
 | 
			
		||||
                'newRePassword' => 'another-password',
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validate();
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->equals(['error.newRePassword_does_not_match']);
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->equals(['error.rePassword_does_not_match']);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user