diff --git a/api/controllers/AuthenticationController.php b/api/controllers/AuthenticationController.php index 5d0ba23..4aab302 100644 --- a/api/controllers/AuthenticationController.php +++ b/api/controllers/AuthenticationController.php @@ -1,7 +1,9 @@ [ - 'except' => ['login'], + 'except' => ['login', 'forgot-password'], ], 'access' => [ 'class' => AccessControl::class, 'rules' => [ [ - 'actions' => ['login'], + 'actions' => ['login', 'forgot-password'], 'allow' => true, 'roles' => ['?'], ], @@ -29,6 +31,7 @@ class AuthenticationController extends Controller { public function verbs() { return [ 'login' => ['POST'], + 'forgot-password' => ['POST'], ]; } @@ -54,4 +57,40 @@ class AuthenticationController extends Controller { ]; } + public function actionForgotPassword() { + $model = new ForgotPasswordForm(); + $model->load(Yii::$app->request->post()); + if ($model->forgotPassword() === false) { + $data = [ + 'success' => false, + 'errors' => $this->normalizeModelErrors($model->getErrors()), + ]; + + if (ArrayHelper::getValue($data['errors'], 'login') === 'error.email_frequency') { + $emailActivation = $model->getEmailActivation(); + $data['data'] = [ + 'canRepeatIn' => $emailActivation->canRepeatIn(), + 'repeatFrequency' => $emailActivation->repeatTimeout, + ]; + } + + return $data; + } + + $emailActivation = $model->getEmailActivation(); + $response = [ + 'success' => true, + 'data' => [ + 'canRepeatIn' => $emailActivation->canRepeatIn(), + 'repeatFrequency' => $emailActivation->repeatTimeout, + ], + ]; + + if ($model->getLoginAttribute() !== 'email') { + $response['data']['emailMask'] = StringHelper::getEmailMask($model->getAccount()->email); + } + + return $response; + } + } diff --git a/common/helpers/StringHelper.php b/common/helpers/StringHelper.php new file mode 100644 index 0000000..d81186a --- /dev/null +++ b/common/helpers/StringHelper.php @@ -0,0 +1,24 @@ +route = ['authentication/login']; + $this->actor->sendPOST($this->getUrl(), [ + 'login' => $login, + 'password' => $password, + ]); + } + + public function forgotPassword($login = '') { + $this->route = ['authentication/forgot-password']; + $this->actor->sendPOST($this->getUrl(), [ + 'login' => $login, + ]); + } + +} diff --git a/tests/codeception/api/_support/FunctionalTester.php b/tests/codeception/api/_support/FunctionalTester.php index 3ec280b..3747e15 100644 --- a/tests/codeception/api/_support/FunctionalTester.php +++ b/tests/codeception/api/_support/FunctionalTester.php @@ -1,7 +1,7 @@ login('Admin', 'password_0'); $I->canSeeResponseIsJson(); $I->canSeeResponseJsonMatchesJsonPath('$.jwt'); diff --git a/tests/codeception/api/functional/AccountsChangePasswordCest.php b/tests/codeception/api/functional/AccountsChangePasswordCest.php index 957f253..099d809 100644 --- a/tests/codeception/api/functional/AccountsChangePasswordCest.php +++ b/tests/codeception/api/functional/AccountsChangePasswordCest.php @@ -4,7 +4,7 @@ namespace tests\codeception\api\functional; use Codeception\Specify; use common\models\Account; use tests\codeception\api\_pages\AccountsRoute; -use tests\codeception\api\_pages\LoginRoute; +use tests\codeception\api\_pages\AuthenticationRoute; use tests\codeception\api\FunctionalTester; class AccountsChangePasswordCest { @@ -38,7 +38,7 @@ class AccountsChangePasswordCest { $I->notLoggedIn(); - $loginRoute = new LoginRoute($I); + $loginRoute = new AuthenticationRoute($I); $loginRoute->login('Admin', 'new-password'); $I->canSeeResponseCodeIs(200); $I->canSeeResponseContainsJson([ diff --git a/tests/codeception/api/functional/ForgotPasswordCest.php b/tests/codeception/api/functional/ForgotPasswordCest.php new file mode 100644 index 0000000..c39662d --- /dev/null +++ b/tests/codeception/api/functional/ForgotPasswordCest.php @@ -0,0 +1,49 @@ +wantTo('create new password recover request by passing email'); + $route->forgotPassword('admin@ely.by'); + $I->canSeeResponseContainsJson([ + 'success' => true, + ]); + $I->canSeeResponseJsonMatchesJsonPath('$.data.canRepeatIn'); + $I->canSeeResponseJsonMatchesJsonPath('$.data.repeatFrequency'); + } + + public function testForgotPasswordByUsername(FunctionalTester $I) { + $route = new AuthenticationRoute($I); + + $I->wantTo('create new password recover request by passing username'); + $route->forgotPassword('Admin'); + $I->canSeeResponseContainsJson([ + 'success' => true, + ]); + $I->canSeeResponseJsonMatchesJsonPath('$.data.canRepeatIn'); + $I->canSeeResponseJsonMatchesJsonPath('$.data.repeatFrequency'); + $I->canSeeResponseJsonMatchesJsonPath('$.data.emailMask'); + } + + public function testDataForFrequencyError(FunctionalTester $I) { + $route = new AuthenticationRoute($I); + + $I->wantTo('get info about time to repeat recover password request'); + $route->forgotPassword('Notch'); + $I->canSeeResponseContainsJson([ + 'success' => false, + 'errors' => [ + 'login' => 'error.email_frequency', + ], + ]); + $I->canSeeResponseJsonMatchesJsonPath('$.data.canRepeatIn'); + $I->canSeeResponseJsonMatchesJsonPath('$.data.repeatFrequency'); + } + +} diff --git a/tests/codeception/api/functional/LoginCest.php b/tests/codeception/api/functional/LoginCest.php index 73c6eb8..de5b79a 100644 --- a/tests/codeception/api/functional/LoginCest.php +++ b/tests/codeception/api/functional/LoginCest.php @@ -1,12 +1,12 @@ wantTo('see error.login_required expected if login is not set'); $route->login(); @@ -61,7 +61,7 @@ class LoginCest { } public function testLoginPassword(FunctionalTester $I) { - $route = new LoginRoute($I); + $route = new AuthenticationRoute($I); $I->wantTo('see password doesn\'t have errors if email or username not set'); $route->login(); @@ -104,7 +104,7 @@ class LoginCest { } public function testLoginByUsernameCorrect(FunctionalTester $I) { - $route = new LoginRoute($I); + $route = new AuthenticationRoute($I); $I->wantTo('login into account using correct username and password'); $route->login('Admin', 'password_0'); @@ -116,7 +116,7 @@ class LoginCest { } public function testLoginByEmailCorrect(FunctionalTester $I) { - $route = new LoginRoute($I); + $route = new AuthenticationRoute($I); $I->wantTo('login into account using correct email and password'); $route->login('admin@ely.by', 'password_0'); @@ -127,7 +127,7 @@ class LoginCest { } public function testLoginInAccWithPasswordMethod(FunctionalTester $I) { - $route = new LoginRoute($I); + $route = new AuthenticationRoute($I); $I->wantTo('login into account with old password hash function using correct username and password'); $route->login('AccWithOldPassword', '12345678'); diff --git a/tests/codeception/common/unit/helpers/StringHelperTest.php b/tests/codeception/common/unit/helpers/StringHelperTest.php new file mode 100644 index 0000000..872331d --- /dev/null +++ b/tests/codeception/common/unit/helpers/StringHelperTest.php @@ -0,0 +1,16 @@ +assertEquals('**@ely.by', StringHelper::getEmailMask('e@ely.by')); + $this->assertEquals('e**@ely.by', StringHelper::getEmailMask('es@ely.by')); + $this->assertEquals('e**i@ely.by', StringHelper::getEmailMask('eri@ely.by')); + $this->assertEquals('er**ch@ely.by', StringHelper::getEmailMask('erickskrauch@ely.by')); + $this->assertEquals('эр**уч@елу.бел', StringHelper::getEmailMask('эрикскрауч@елу.бел')); + } + +}