diff --git a/api/models/authentication/ConfirmEmailForm.php b/api/models/authentication/ConfirmEmailForm.php index 0c46680..587ac7d 100644 --- a/api/models/authentication/ConfirmEmailForm.php +++ b/api/models/authentication/ConfirmEmailForm.php @@ -3,6 +3,7 @@ namespace api\models\authentication; use api\models\AccountIdentity; use api\models\base\KeyConfirmationForm; +use api\models\profile\ChangeUsernameForm; use common\models\Account; use common\models\EmailActivation; use Yii; @@ -34,6 +35,9 @@ class ConfirmEmailForm extends KeyConfirmationForm { throw new ErrorException('Unable activate user account.'); } + $changeUsernameForm = new ChangeUsernameForm(); + $changeUsernameForm->createEventTask($account->id, $account->username, null); + $transaction->commit(); } catch (ErrorException $e) { $transaction->rollBack(); diff --git a/api/models/authentication/RegistrationForm.php b/api/models/authentication/RegistrationForm.php index 41e71ee..fea1245 100644 --- a/api/models/authentication/RegistrationForm.php +++ b/api/models/authentication/RegistrationForm.php @@ -4,7 +4,6 @@ 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; use common\models\confirmations\RegistrationConfirmation; @@ -17,6 +16,7 @@ use Ramsey\Uuid\Uuid; use Yii; use yii\base\ErrorException; use yii\base\InvalidConfigException; +use yii\helpers\ArrayHelper; use const common\LATEST_RULES_VERSION; class RegistrationForm extends ApiForm { @@ -49,6 +49,7 @@ class RegistrationForm extends ApiForm { ['rePassword', 'validatePasswordAndRePasswordMatch'], ['lang', LanguageValidator::class], + ['lang', 'default', 'value' => 'en'], ]; } @@ -81,7 +82,7 @@ class RegistrationForm extends ApiForm { * @throws Exception */ public function signup() { - if (!$this->validate()) { + if (!$this->validate() && !$this->canContinue($this->getFirstErrors())) { return null; } @@ -96,7 +97,7 @@ class RegistrationForm extends ApiForm { $account->status = Account::STATUS_REGISTERED; $account->rules_agreement_version = LATEST_RULES_VERSION; $account->setRegistrationIp(Yii::$app->request->getUserIP()); - if (!$account->save()) { + if (!$account->save(false)) { throw new ErrorException('Account not created.'); } @@ -118,9 +119,6 @@ class RegistrationForm extends ApiForm { $this->sendMail($emailActivation, $account); - $changeUsernameForm = new ChangeUsernameForm(); - $changeUsernameForm->createEventTask($account->id, $account->username, null); - $transaction->commit(); } catch (Exception $e) { $transaction->rollBack(); @@ -161,4 +159,43 @@ class RegistrationForm extends ApiForm { } } + /** + * Метод проверяет, можно ли занять указанный при регистрации ник или e-mail. Так случается, + * что пользователи вводят неправильный e-mail или ник, после замечают это и пытаются вновь + * выпонить регистрацию. Мы не будем им мешать и просто удаляем существующие недозарегистрированные + * аккаунты, позволяя им зарегистрироваться. + * + * @param array $errors массив, где ключ - это поле, а значение - первая ошибка из нашего + * стандартного словаря ошибок + * + * @return bool + */ + protected function canContinue(array $errors) : bool { + if (ArrayHelper::getValue($errors, 'username') === E::USERNAME_NOT_AVAILABLE) { + $duplicatedUsername = Account::findOne([ + 'username' => $this->username, + 'status' => Account::STATUS_REGISTERED, + ]); + + if ($duplicatedUsername !== null) { + $duplicatedUsername->delete(); + unset($errors['username']); + } + } + + if (ArrayHelper::getValue($errors, 'email') === E::EMAIL_NOT_AVAILABLE) { + $duplicatedEmail = Account::findOne([ + 'email' => $this->email, + 'status' => Account::STATUS_REGISTERED, + ]); + + if ($duplicatedEmail !== null) { + $duplicatedEmail->delete(); + unset($errors['email']); + } + } + + return empty($errors); + } + } diff --git a/api/models/profile/ChangeLanguageForm.php b/api/models/profile/ChangeLanguageForm.php index fa44d26..391687a 100644 --- a/api/models/profile/ChangeLanguageForm.php +++ b/api/models/profile/ChangeLanguageForm.php @@ -31,7 +31,7 @@ class ChangeLanguageForm extends ApiForm { $account = $this->getAccount(); $account->lang = $this->lang; - if (!$account->save()) { + if (!$account->save(false)) { throw new ErrorException('Cannot change user language'); } diff --git a/api/models/profile/ChangeUsernameForm.php b/api/models/profile/ChangeUsernameForm.php index ef7f069..81f7957 100644 --- a/api/models/profile/ChangeUsernameForm.php +++ b/api/models/profile/ChangeUsernameForm.php @@ -30,7 +30,10 @@ class ChangeUsernameForm extends ApiForm { public function validateUsername($attribute) { $account = new Account(); + $account->id = $this->getAccount()->id; $account->username = $this->$attribute; + // Это чтобы unique validator учёл, что ник может быть забит на текущий аккаунт + $account->setIsNewRecord(false); if (!$account->validate(['username'])) { $this->addErrors($account->getErrors()); } @@ -46,7 +49,7 @@ class ChangeUsernameForm extends ApiForm { $oldNickname = $account->username; try { $account->username = $this->username; - if (!$account->save()) { + if (!$account->save(false)) { throw new ErrorException('Cannot save account model with new username'); } diff --git a/common/models/Account.php b/common/models/Account.php index 4227e9d..4c94f08 100644 --- a/common/models/Account.php +++ b/common/models/Account.php @@ -3,7 +3,6 @@ namespace common\models; use common\helpers\Error as E; use common\components\UserPass; -use common\validators\LanguageValidator; use Ely\Yii2\TempmailValidator; use Yii; use yii\base\InvalidConfigException; @@ -79,9 +78,6 @@ class Account extends ActiveRecord { [['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'], ]; } diff --git a/tests/codeception/api/functional/RegisterCest.php b/tests/codeception/api/functional/RegisterCest.php index 210afb3..4730d8f 100644 --- a/tests/codeception/api/functional/RegisterCest.php +++ b/tests/codeception/api/functional/RegisterCest.php @@ -1,7 +1,6 @@ true, 'lang' => 'ru', ]); + $this->assertSuccessRegistration($I); + } + + public function testUserCorrectRegistrationWithReassignUsername(FunctionalTester $I) { + $route = new SignupRoute($I); + + $I->wantTo('ensure that signup allow reassign not finished registration username'); + $route->register([ + 'username' => 'howe.garnett', + 'email' => 'custom-email@gmail.com', + 'password' => 'some_password', + 'rePassword' => 'some_password', + 'rulesAgreement' => true, + 'lang' => 'ru', + ]); + $this->assertSuccessRegistration($I); + } + + public function testUserCorrectRegistrationWithReassignEmail(FunctionalTester $I) { + $route = new SignupRoute($I); + + $I->wantTo('ensure that signup allow reassign not finished registration email'); + $route->register([ + 'username' => 'CustomUsername', + 'email' => 'achristiansen@gmail.com', + 'password' => 'some_password', + 'rePassword' => 'some_password', + 'rulesAgreement' => true, + 'lang' => 'ru', + ]); + $this->assertSuccessRegistration($I); + } + + private function assertSuccessRegistration(FunctionalTester $I) { $I->canSeeResponseCodeIs(200); $I->canSeeResponseIsJson(); $I->canSeeResponseContainsJson(['success' => true]);