diff --git a/lib/User/Controller/RecoveryController.php b/lib/User/Controller/RecoveryController.php index 203932b..377b9fa 100644 --- a/lib/User/Controller/RecoveryController.php +++ b/lib/User/Controller/RecoveryController.php @@ -2,12 +2,14 @@ namespace Da\User\Controller; use Da\User\Event\FormEvent; +use Da\User\Event\ResetPasswordEvent; use Da\User\Factory\MailFactory; use Da\User\Form\RecoveryForm; use Da\User\Model\Token; use Da\User\Query\TokenQuery; use Da\User\Query\UserQuery; use Da\User\Service\PasswordRecoveryService; +use Da\User\Service\ResetPasswordService; use Da\User\Traits\ContainerTrait; use Da\User\Traits\ModuleTrait; use Da\User\Validator\AjaxRequestModelValidator; @@ -60,6 +62,12 @@ class RecoveryController extends Controller ]; } + /** + * Displays / handles user password recovery request. + * + * @return string + * @throws NotFoundHttpException + */ public function actionRequest() { if (!$this->getModule()->allowPasswordRecovery) { @@ -93,4 +101,63 @@ class RecoveryController extends Controller return $this->render('request', ['model' => $form,]); } + + /** + * Displays / handles user password reset. + * + * @param $id + * @param $code + * + * @return string + * @throws NotFoundHttpException + */ + public function actionReset($id, $code) + { + if (!$this->getModule()->allowPasswordRecovery) { + throw new NotFoundHttpException(); + } + /** @var Token $token */ + $token = $this->tokenQuery->whereIsRecoveryType($id, $code)->one(); + /** @var ResetPasswordEvent $event */ + $event = $this->make(ResetPasswordEvent::class, [$token]); + + $this->trigger(ResetPasswordEvent::EVENT_BEFORE_TOKEN_VALIDATE, $event); + + if ($token === null || $token->getIsExpired() || $token->user === null) { + Yii::$app->session->setFlash( + 'danger', + Yii::t('user', 'Recovery link is invalid or expired. Please try requesting a new one.') + ); + + return $this->render( + 'message', + [ + 'title' => Yii::t('user', 'Invalid or expired link'), + 'module' => $this->getModule(), + ] + ); + } + + /** @var RecoveryForm $form */ + $form = $this->make(RecoveryForm::class, ['scenario' => RecoveryForm::SCENARIO_RESET]); + $event = $event->updateForm($form); + + $this->make(AjaxRequestModelValidator::class, [$form])->validate(); + + if ($form->load(Yii::$app->getRequest()->post())) { + if ($this->make(ResetPasswordService::class, [$form->password, $token->user])->run()) { + $this->trigger(ResetPasswordEvent::EVENT_AFTER_RESET, $event); + + return $this->render( + 'message', + [ + 'title' => Yii::t('user', 'Password has been changed'), + 'module' => $this->getModule(), + ] + ); + } + } + + return $this->render('reset', ['model' => $form,]); + } } diff --git a/lib/User/Event/ResetPasswordEvent.php b/lib/User/Event/ResetPasswordEvent.php index f81cab1..4403801 100644 --- a/lib/User/Event/ResetPasswordEvent.php +++ b/lib/User/Event/ResetPasswordEvent.php @@ -16,7 +16,7 @@ class ResetPasswordEvent extends Event protected $form; protected $token; - public function __construct(RecoveryForm $form, Token $token, array $config = []) + public function __construct(Token $token, RecoveryForm $form, array $config = []) { $this->form = $form; $this->token = $token; @@ -33,4 +33,9 @@ class ResetPasswordEvent extends Event { return $this->token; } + + public function updateForm(RecoveryForm $form) + { + return new static($this->getToken(), $form); + } } diff --git a/lib/User/Query/TokenQuery.php b/lib/User/Query/TokenQuery.php index d70da8a..bdc89eb 100644 --- a/lib/User/Query/TokenQuery.php +++ b/lib/User/Query/TokenQuery.php @@ -1,9 +1,13 @@ andWhere(['user_id' => $userId, 'code' => $code, 'type' => Token::TYPE_RECOVERY]); + } } diff --git a/lib/User/Service/ResetPasswordService.php b/lib/User/Service/ResetPasswordService.php index 3c3b28d..6eaf318 100644 --- a/lib/User/Service/ResetPasswordService.php +++ b/lib/User/Service/ResetPasswordService.php @@ -21,11 +21,12 @@ class ResetPasswordService implements ServiceInterface public function run() { - return (bool)$this->model->updateAttributes( - [ - 'password_hash' => $this->securityHelper->generatePasswordHash($this->password) - ] - ); + + return $this->model && (bool)$this->model->updateAttributes( + [ + 'password_hash' => $this->securityHelper->generatePasswordHash($this->password) + ] + ); } }