From c3aad1b47df9f81b0fd8bd505d59b44a67a422cf Mon Sep 17 00:00:00 2001 From: Antonio Ramirez Date: Fri, 9 Dec 2016 01:39:55 +0100 Subject: [PATCH] add resend functionality --- lib/User/Controller/AdminController.php | 4 +- lib/User/Controller/RecoveryController.php | 15 +- .../Controller/RegistrationController.php | 181 ++++++++++++++++++ lib/User/Event/FormEvent.php | 2 + lib/User/Event/SocialNetworkConnectEvent.php | 3 + lib/User/Factory/MailFactory.php | 25 ++- lib/User/Factory/TokenFactory.php | 33 ++++ lib/User/Form/ResendForm.php | 52 ++--- lib/User/Query/SocialNetworkAccountQuery.php | 5 + lib/User/Query/UserQuery.php | 5 + .../Service/ResendConfirmationService.php | 38 ++++ 11 files changed, 310 insertions(+), 53 deletions(-) create mode 100644 lib/User/Controller/RegistrationController.php create mode 100644 lib/User/Factory/TokenFactory.php create mode 100644 lib/User/Service/ResendConfirmationService.php diff --git a/lib/User/Controller/AdminController.php b/lib/User/Controller/AdminController.php index 9e5cb75..cb6fe6d 100644 --- a/lib/User/Controller/AdminController.php +++ b/lib/User/Controller/AdminController.php @@ -12,7 +12,6 @@ use Da\User\Service\UserBlockService; use Da\User\Service\UserConfirmationService; use Da\User\Service\UserCreateService; use Da\User\Traits\ContainerTrait; -use Da\User\Traits\ModuleTrait; use Da\User\Validator\AjaxRequestModelValidator; use Yii; use yii\base\Module; @@ -25,7 +24,6 @@ use yii\web\Controller; class AdminController extends Controller { - use ModuleTrait; use ContainerTrait; /** @@ -165,6 +163,7 @@ class AdminController extends Controller /** @var UserEvent $event */ $event = $this->make(UserEvent::class, [$user]); $this->make(AjaxRequestModelValidator::class, [$user])->validate(); + $this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event); if ($profile->load(Yii::$app->request->post()) && $profile->save()) { @@ -215,6 +214,7 @@ class AdminController extends Controller $user = $this->userQuery->where(['id' => $id])->one(); /** @var UserEvent $event */ $event = $this->make(UserEvent::class, [$user]); + $this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event); if ($this->make(UserConfirmationService::class, [$user])->run()) { Yii::$app->getSession()->setFlash('success', Yii::t('user', 'User has been confirmed')); diff --git a/lib/User/Controller/RecoveryController.php b/lib/User/Controller/RecoveryController.php index 377b9fa..c2736b8 100644 --- a/lib/User/Controller/RecoveryController.php +++ b/lib/User/Controller/RecoveryController.php @@ -11,17 +11,15 @@ 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; use Yii; -use yii\base\Module; +use Da\User\Module; use yii\filters\AccessControl; use yii\web\Controller; use yii\web\NotFoundHttpException; class RecoveryController extends Controller { - use ModuleTrait; use ContainerTrait; protected $userQuery; @@ -70,7 +68,8 @@ class RecoveryController extends Controller */ public function actionRequest() { - if (!$this->getModule()->allowPasswordRecovery) { + + if (!$this->module->allowPasswordRecovery) { throw new NotFoundHttpException(); } @@ -93,7 +92,7 @@ class RecoveryController extends Controller 'message', [ 'title' => Yii::t('user', 'Recovery message sent'), - 'module' => $this->getModule(), + 'module' => $this->module, ] ); } @@ -113,7 +112,7 @@ class RecoveryController extends Controller */ public function actionReset($id, $code) { - if (!$this->getModule()->allowPasswordRecovery) { + if (!$this->module->allowPasswordRecovery) { throw new NotFoundHttpException(); } /** @var Token $token */ @@ -133,7 +132,7 @@ class RecoveryController extends Controller 'message', [ 'title' => Yii::t('user', 'Invalid or expired link'), - 'module' => $this->getModule(), + 'module' => $this->module, ] ); } @@ -152,7 +151,7 @@ class RecoveryController extends Controller 'message', [ 'title' => Yii::t('user', 'Password has been changed'), - 'module' => $this->getModule(), + 'module' => $this->module, ] ); } diff --git a/lib/User/Controller/RegistrationController.php b/lib/User/Controller/RegistrationController.php new file mode 100644 index 0000000..ade5263 --- /dev/null +++ b/lib/User/Controller/RegistrationController.php @@ -0,0 +1,181 @@ +userQuery = $userQuery; + $this->socialNetworkAccountQuery = $socialNetworkAccountQuery; + parent::__construct($id, $module, $config); + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return [ + 'access' => [ + 'class' => AccessControl::className(), + 'rules' => [ + [ + 'allow' => true, + 'actions' => ['register', 'connect'], + 'roles' => ['?'] + ], + [ + 'allow' => true, + 'actions' => ['confirm', 'resend'], + 'roles' => ['?', '@'] + ], + ], + ], + ]; + } + + public function actionConnect($code) + { + /** @var SocialNetworkAccount $account */ + $account = $this->socialNetworkAccountQuery->whereCode($code)->one(); + if ($account === null || $account->getIsConnected()) { + throw new NotFoundHttpException(); + } + + /** @var User $user */ + $user = $this->make( + User::class, + ['scenario' => 'connect', 'username' => $account->username, 'email' => $account->email] + ); + $event = $this->make(SocialNetworkConnectEvent::class, [$user, $account]); + + $this->make(AjaxRequestModelValidator::class, [$user])->validate(); + + $this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_CONNECT, $event); + + if ($user->load(Yii::$app->request->post())) { + $mailService = MailFactory::makeWelcomeMailerService($user); + if ($this->make(UserCreateService::class, [$user, $mailService])->run()) { + $account->connect($user); + $this->trigger(SocialNetworkConnectEvent::EVENT_AFTER_CONNECT, $event); + + Yii::$app->user->login($user, $this->module->rememberLoginLifespan); + + return $this->goBack(); + } + } + + return $this->render( + 'connect', + [ + 'model' => $user, + 'account' => $account, + ] + ); + } + + public function actionConfirm($id, $code) + { + $user = $this->userQuery->whereId($id)->one(); + + if ($user === null || $this->module->enableEmailConfirmation === false) { + throw new NotFoundHttpException(); + } + + /** @var UserEvent $event */ + $event = $this->make(UserEvent::class, [$user]); + + $this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event); + + // TODO ATTEMPT CONFIRMATION + + $this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event); + + return $this->render( + 'message', + [ + 'title' => Yii::t('user', 'Account confirmation'), + 'module' => $this->module, + ] + ); + } + + public function actionResend() + { + if ($this->module->enableEmailConfirmation === false) { + throw new NotFoundHttpException(); + } + /** @var ResendForm $form */ + $form = $this->make(ResendForm::class); + $event = $this->make(FormEvent::class, [$form]); + + $this->make(AjaxRequestModelValidator::class, [$form])->validate(); + + $this->trigger(FormEvent::EVENT_BEFORE_RESEND, $event); + if ($form->load(Yii::$app->request->post()) && $form->validate()) { + /** @var User $user */ + $user = $this->userQuery->whereEmail($form->email)->one(); + $mailService = MailFactory::makeConfirmationMailerService($user); + if ($this->make(ResendConfirmationService::class, [$user, $mailService])->run()) { + $this->trigger(FormEvent::EVENT_AFTER_RESEND, $event); + Yii::$app->session->setFlash( + 'info', + Yii::t( + 'user', + 'A message has been sent to your email address. It contains a confirmation link that you must + click to complete registration.' + ) + ); + } else { + Yii::$app->session->setFlash( + 'danger', + Yii::t( + 'user', + 'We couldn\'t re-send the mail to confirm your address. Please, verify is the correct email.' + ) + ); + } + } + } +} diff --git a/lib/User/Event/FormEvent.php b/lib/User/Event/FormEvent.php index 1750572..091dd37 100644 --- a/lib/User/Event/FormEvent.php +++ b/lib/User/Event/FormEvent.php @@ -8,6 +8,8 @@ class FormEvent extends Event { const EVENT_BEFORE_REQUEST = 'beforeRequest'; const EVENT_AFTER_REQUEST = 'afterRequest'; + const EVENT_BEFORE_RESEND = 'beforeResend'; + const EVENT_AFTER_RESEND = 'afterResend'; protected $form; diff --git a/lib/User/Event/SocialNetworkConnectEvent.php b/lib/User/Event/SocialNetworkConnectEvent.php index 8f79d1f..07c2c9b 100644 --- a/lib/User/Event/SocialNetworkConnectEvent.php +++ b/lib/User/Event/SocialNetworkConnectEvent.php @@ -8,6 +8,9 @@ use yii\base\Event; class SocialNetworkConnectEvent extends Event { + const EVENT_BEFORE_CONNECT = 'beforeConnect'; + const EVENT_AFTER_CONNECT = 'afterConnect'; + protected $user; protected $account; diff --git a/lib/User/Factory/MailFactory.php b/lib/User/Factory/MailFactory.php index 1ebd67a..cbf7227 100644 --- a/lib/User/Factory/MailFactory.php +++ b/lib/User/Factory/MailFactory.php @@ -37,15 +37,36 @@ class MailFactory * * @return MailService */ - public static function makeRecoveryMailerService($email, Token $token = null) { + public static function makeRecoveryMailerService($email, Token $token = null) + { /** @var Module $module */ $module = Yii::$app->getModule('user'); $to = $email; $from = $module->mailParams['fromEmail']; $subject = $module->mailParams['recoveryMailSubject']; + $params = [ + 'user' => $token && $token->user ? $token->user : null, + 'token' => $token + ]; - return static::makeMailerService($from, $to, $subject, 'recovery'); + return static::makeMailerService($from, $to, $subject, 'recovery', $params); } + + public static function makeConfirmationMailerService(User $user, Token $token = null) + { + /** @var Module $module */ + $module = Yii::$app->getModule('user'); + $to = $user->email; + $from = $module->mailParams['fromEmail']; + $subject = $module->mailParams['confirmationMailSubject']; + $params = [ + 'user' => $token && $token->user ? $token->user : null, + 'token' => $token + ]; + + return static::makeMailerService($from, $to, $subject, 'recovery', $params); + } + /** * Builds a MailerService * diff --git a/lib/User/Factory/TokenFactory.php b/lib/User/Factory/TokenFactory.php new file mode 100644 index 0000000..94ac442 --- /dev/null +++ b/lib/User/Factory/TokenFactory.php @@ -0,0 +1,33 @@ + $userId, 'type' => Token::TYPE_CONFIRMATION]); + + $token->save(false); + + return $token; + + } + + protected static function make($class, $params = []) + { + return Yii::$container->get($class, $params); + } + +} diff --git a/lib/User/Form/ResendForm.php b/lib/User/Form/ResendForm.php index 97e89d9..9532d20 100644 --- a/lib/User/Form/ResendForm.php +++ b/lib/User/Form/ResendForm.php @@ -1,52 +1,28 @@ - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace dektrium\user\models; - -use dektrium\user\Finder; -use dektrium\user\Mailer; +use Da\User\Query\UserQuery; +use Yii; use yii\base\Model; -/** - * ResendForm gets user email address and if user with given email is registered it sends new confirmation message - * to him in case he did not validate his email. - * - * @author Dmitry Erofeev - */ class ResendForm extends Model { /** * @var string */ public $email; - /** - * @var Mailer + * @var UserQuery */ - protected $mailer; + protected $userQuery; /** - * @var Finder - */ - protected $finder; - - /** - * @param Mailer $mailer - * @param Finder $finder + * @param UserQuery $userQuery * @param array $config */ - public function __construct(Mailer $mailer, Finder $finder, $config = []) + public function __construct(UserQuery $userQuery, $config = []) { - $this->mailer = $mailer; - $this->finder = $finder; + $this->userQuery = $userQuery; parent::__construct($config); } @@ -67,18 +43,10 @@ class ResendForm extends Model public function attributeLabels() { return [ - 'email' => \Yii::t('user', 'Email'), + 'email' => Yii::t('user', 'Email'), ]; } - /** - * @inheritdoc - */ - public function formName() - { - return 'resend-form'; - } - /** * Creates new confirmation token and sends it to the user. * @@ -90,6 +58,8 @@ class ResendForm extends Model return false; } + $user = $this->userQuery->whereEmail($this->email)->one(); + $user = $this->finder->findUserByEmail($this->email); if ($user instanceof User && !$user->isConfirmed) { diff --git a/lib/User/Query/SocialNetworkAccountQuery.php b/lib/User/Query/SocialNetworkAccountQuery.php index 95c9dc8..f36f9a5 100644 --- a/lib/User/Query/SocialNetworkAccountQuery.php +++ b/lib/User/Query/SocialNetworkAccountQuery.php @@ -15,4 +15,9 @@ class SocialNetworkAccountQuery extends ActiveQuery ] ); } + + public function whereCode($code) + { + return $this->andWhere(['code' => md5($code)]); + } } diff --git a/lib/User/Query/UserQuery.php b/lib/User/Query/UserQuery.php index 452c734..4ebe09f 100644 --- a/lib/User/Query/UserQuery.php +++ b/lib/User/Query/UserQuery.php @@ -22,4 +22,9 @@ class UserQuery extends ActiveQuery { return $this->andWhere(['username' => $username]); } + + public function whereId($id) + { + return $this->andWhere(['id' => $id]); + } } diff --git a/lib/User/Service/ResendConfirmationService.php b/lib/User/Service/ResendConfirmationService.php new file mode 100644 index 0000000..ff686fd --- /dev/null +++ b/lib/User/Service/ResendConfirmationService.php @@ -0,0 +1,38 @@ +model = $model; + $this->mailService = $mailService; + $this->logger = $logger; + } + + public function run() + { + if($this->model && !$this->model->getIsConfirmed()) { + $token = TokenFactory::makeConfirmationToken($this->model->id); + $this->mailService->setViewParam('token', $token); + + return $this->mailService->run(); + } + + return false; + } + +}