diff --git a/lib/User/Controller/AdminController.php b/lib/User/Controller/AdminController.php index cb6fe6d..3f50115 100644 --- a/lib/User/Controller/AdminController.php +++ b/lib/User/Controller/AdminController.php @@ -112,10 +112,10 @@ class AdminController extends Controller $this->make(AjaxRequestModelValidator::class, [$user])->validate(); - $this->trigger(UserEvent::EVENT_BEFORE_CREATE, $event); - if ($user->load(Yii::$app->request->post())) { + $this->trigger(UserEvent::EVENT_BEFORE_CREATE, $event); + $mailService = MailFactory::makeWelcomeMailerService($user); if ($this->make(UserCreateService::class, [$user, $mailService])->run()) { @@ -139,13 +139,15 @@ class AdminController extends Controller $this->make(AjaxRequestModelValidator::class, [$user])->validate(); - $this->trigger(ActiveRecord::EVENT_BEFORE_UPDATE, $event); + if ($user->load(Yii::$app->request->post())) { + $this->trigger(ActiveRecord::EVENT_BEFORE_UPDATE, $event); - if ($user->load(Yii::$app->request->post()) && $user->save()) { - Yii::$app->getSession()->setFlash('success', Yii::t('user', 'Account details have been updated')); - $this->trigger(ActiveRecord::EVENT_AFTER_UPDATE, $event); + if ($user->save()) { + Yii::$app->getSession()->setFlash('success', Yii::t('user', 'Account details have been updated')); + $this->trigger(ActiveRecord::EVENT_AFTER_UPDATE, $event); - return $this->refresh(); + return $this->refresh(); + } } return $this->render('_account', ['user' => $user]); @@ -162,15 +164,17 @@ 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())) { + if($profile->save()) { + $this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event); + Yii::$app->getSession()->setFlash('success', Yii::t('user', 'Profile details have been updated')); + $this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event); - if ($profile->load(Yii::$app->request->post()) && $profile->save()) { - Yii::$app->getSession()->setFlash('success', Yii::t('user', 'Profile details have been updated')); - $this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event); - - return $this->refresh(); + return $this->refresh(); + } } return $this->render( @@ -216,9 +220,11 @@ class AdminController extends Controller $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')); $this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event); + } else { Yii::$app->getSession()->setFlash('warning', Yii::t('user', 'Unable to confirm user. Please, try again.')); } @@ -236,9 +242,11 @@ class AdminController extends Controller /** @var UserEvent $event */ $event = $this->make(UserEvent::class, [$user]); $this->trigger(ActiveRecord::EVENT_BEFORE_DELETE, $event); + if ($user->delete()) { Yii::$app->getSession()->setFlash('success', \Yii::t('user', 'User has been deleted')); $this->trigger(ActiveRecord::EVENT_AFTER_DELETE, $event); + } else { Yii::$app->getSession()->setFlash( 'warning', diff --git a/lib/User/Controller/RecoveryController.php b/lib/User/Controller/RecoveryController.php index c2736b8..fbe893b 100644 --- a/lib/User/Controller/RecoveryController.php +++ b/lib/User/Controller/RecoveryController.php @@ -80,9 +80,10 @@ class RecoveryController extends Controller $this->make(AjaxRequestModelValidator::class, $form)->validate(); - $this->trigger(FormEvent::EVENT_BEFORE_REQUEST, $event); - if ($form->load(Yii::$app->request->post())) { + + $this->trigger(FormEvent::EVENT_BEFORE_REQUEST, $event); + $mailService = MailFactory::makeRecoveryMailerService($form->email); if ($this->make(PasswordRecoveryService::class, [$form->email, $mailService])->run()) { diff --git a/lib/User/Controller/RegistrationController.php b/lib/User/Controller/RegistrationController.php index ade5263..8f54106 100644 --- a/lib/User/Controller/RegistrationController.php +++ b/lib/User/Controller/RegistrationController.php @@ -5,13 +5,17 @@ use Da\User\Event\FormEvent; use Da\User\Event\SocialNetworkConnectEvent; use Da\User\Event\UserEvent; use Da\User\Factory\MailFactory; +use Da\User\Form\RegistrationForm; use Da\User\Form\ResendForm; use Da\User\Model\SocialNetworkAccount; use Da\User\Model\User; use Da\User\Query\SocialNetworkAccountQuery; use Da\User\Query\UserQuery; +use Da\User\Service\EmailConfirmationService; use Da\User\Service\ResendConfirmationService; +use Da\User\Service\UserConfirmationService; use Da\User\Service\UserCreateService; +use Da\User\Service\UserRegisterService; use Da\User\Traits\ContainerTrait; use Da\User\Traits\ModuleTrait; use Da\User\Validator\AjaxRequestModelValidator; @@ -75,6 +79,45 @@ class RegistrationController extends Controller ]; } + public function actionRegister() + { + if(!$this->module->enableRegistration) { + throw new NotFoundHttpException(); + } + /** @var RegistrationForm $form */ + $form = $this->make(RegistrationForm::class); + /** @var FormEvent $event */ + $event = $this->make(FormEvent::class, [$form]); + + $this->make(AjaxRequestModelValidator::class, [$form])->validate(); + + if($form->load(Yii::$app->request->post()) && $form->validate()) { + $this->trigger(UserEvent::EVENT_BEFORE_REGISTER, $event); + + $user = $this->make(User::class, [$form->attributes]); + $user->setScenario('register'); + $mailService = MailFactory::makeWelcomeMailerService($user); + + if($this->make(UserRegisterService::class, [$user, $mailService])->run()) { + Yii::$app->session->setFlash( + 'info', + Yii::t( + 'user', + 'Your account has been created and a message with further instructions has been sent to your email' + ) + ); + return $this->render('message', [ + 'title' => Yii::t('user', 'Your account has been created') + ]); + } + + return $this->render('register', [ + 'model' => $form, + 'module' => $this->module, + ]); + } + } + public function actionConnect($code) { /** @var SocialNetworkAccount $account */ @@ -92,9 +135,10 @@ class RegistrationController extends Controller $this->make(AjaxRequestModelValidator::class, [$user])->validate(); - $this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_CONNECT, $event); - if ($user->load(Yii::$app->request->post())) { + + $this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_CONNECT, $event); + $mailService = MailFactory::makeWelcomeMailerService($user); if ($this->make(UserCreateService::class, [$user, $mailService])->run()) { $account->connect($user); @@ -125,12 +169,21 @@ class RegistrationController extends Controller /** @var UserEvent $event */ $event = $this->make(UserEvent::class, [$user]); + $userConfirmationService = $this->make(UserConfirmationService::class, [$user]); $this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event); - // TODO ATTEMPT CONFIRMATION + if ($this->make(EmailConfirmationService::class, [$code, $user, $userConfirmationService])->run()) { + Yii::$app->user->login($user, $this->module->rememberLoginLifespan); + Yii::$app->session->setFlash('success', Yii::t('user', 'Thank you, registration is now complete.')); - $this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event); + $this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event); + } else { + Yii::$app->session->setFlash( + 'danger', + Yii::t('user', 'The confirmation link is invalid or expired. Please try requesting a new one.') + ); + } return $this->render( 'message', @@ -152,8 +205,8 @@ class RegistrationController extends Controller $this->make(AjaxRequestModelValidator::class, [$form])->validate(); - $this->trigger(FormEvent::EVENT_BEFORE_RESEND, $event); if ($form->load(Yii::$app->request->post()) && $form->validate()) { + $this->trigger(FormEvent::EVENT_BEFORE_RESEND, $event); /** @var User $user */ $user = $this->userQuery->whereEmail($form->email)->one(); $mailService = MailFactory::makeConfirmationMailerService($user); diff --git a/lib/User/Factory/TokenFactory.php b/lib/User/Factory/TokenFactory.php index 94ac442..bc71bab 100644 --- a/lib/User/Factory/TokenFactory.php +++ b/lib/User/Factory/TokenFactory.php @@ -17,7 +17,7 @@ class TokenFactory */ public static function makeConfirmationToken($userId) { - $token = self::make(Token::class, ['user_id' => $userId, 'type' => Token::TYPE_CONFIRMATION]); + $token = self::make($userId, Token::TYPE_CONFIRMATION); $token->save(false); @@ -25,9 +25,43 @@ class TokenFactory } - protected static function make($class, $params = []) + /** + * @param $userId + * + * @return Token + */ + public static function makeConfirmNewMailToken($userId) { - return Yii::$container->get($class, $params); + $token = self::make($userId, Token::TYPE_CONFIRM_NEW_EMAIL); + + $token->save(false); + + return $token; + } + + /** + * @param $userId + * + * @return Token + */ + public static function makeRecoveryToken($userId) + { + $token = self::make($userId, Token::TYPE_RECOVERY); + + $token->save(false); + + return $token; + } + + /** + * @param $userId + * @param $type + * + * @return Token + */ + protected static function make($userId, $type) + { + return Yii::$container->get(Token::class, ['user_id' => $userId, 'type' => $type]); } } diff --git a/lib/User/Form/RegistrationForm.php b/lib/User/Form/RegistrationForm.php index 1738ff2..54860f6 100644 --- a/lib/User/Form/RegistrationForm.php +++ b/lib/User/Form/RegistrationForm.php @@ -1,38 +1,27 @@ - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace dektrium\user\models; +namespace Da\User\Form; +use Da\User\Model\User; +use Da\User\Traits\ContainerTrait; use dektrium\user\traits\ModuleTrait; use Yii; use yii\base\Model; -/** - * Registration form collects user input on registration process, validates it and creates new User model. - * - * @author Dmitry Erofeev - */ + class RegistrationForm extends Model { use ModuleTrait; + use ContainerTrait; + /** * @var string User email address */ public $email; - /** * @var string Username */ public $username; - /** * @var string Password */ @@ -43,25 +32,26 @@ class RegistrationForm extends Model */ public function rules() { - $user = $this->module->modelMap['User']; + /** @var User $user */ + $user = $this->getClassMap()->get(User::class); return [ // username rules - 'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255], - 'usernameTrim' => ['username', 'filter', 'filter' => 'trim'], - 'usernamePattern' => ['username', 'match', 'pattern' => $user::$usernameRegexp], + 'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255], + 'usernameTrim' => ['username', 'filter', 'filter' => 'trim'], + 'usernamePattern' => ['username', 'match', 'pattern' => $user->usernameRegex], 'usernameRequired' => ['username', 'required'], - 'usernameUnique' => [ + 'usernameUnique' => [ 'username', 'unique', 'targetClass' => $user, 'message' => Yii::t('user', 'This username has already been taken') ], // email rules - 'emailTrim' => ['email', 'filter', 'filter' => 'trim'], + 'emailTrim' => ['email', 'filter', 'filter' => 'trim'], 'emailRequired' => ['email', 'required'], - 'emailPattern' => ['email', 'email'], - 'emailUnique' => [ + 'emailPattern' => ['email', 'email'], + 'emailUnique' => [ 'email', 'unique', 'targetClass' => $user, @@ -69,7 +59,7 @@ class RegistrationForm extends Model ], // password rules 'passwordRequired' => ['password', 'required', 'skipOnEmpty' => $this->module->enableGeneratingPassword], - 'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72], + 'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72], ]; } @@ -79,20 +69,12 @@ class RegistrationForm extends Model public function attributeLabels() { return [ - 'email' => Yii::t('user', 'Email'), + 'email' => Yii::t('user', 'Email'), 'username' => Yii::t('user', 'Username'), 'password' => Yii::t('user', 'Password'), ]; } - /** - * @inheritdoc - */ - public function formName() - { - return 'register-form'; - } - /** * Registers a new user account. If registration was successful it will set flash message. * diff --git a/lib/User/Form/ResendForm.php b/lib/User/Form/ResendForm.php index 9532d20..b207ca3 100644 --- a/lib/User/Form/ResendForm.php +++ b/lib/User/Form/ResendForm.php @@ -46,41 +46,4 @@ class ResendForm extends Model 'email' => Yii::t('user', 'Email'), ]; } - - /** - * Creates new confirmation token and sends it to the user. - * - * @return bool - */ - public function resend() - { - if (!$this->validate()) { - return false; - } - - $user = $this->userQuery->whereEmail($this->email)->one(); - - $user = $this->finder->findUserByEmail($this->email); - - if ($user instanceof User && !$user->isConfirmed) { - /** @var Token $token */ - $token = \Yii::createObject([ - 'class' => Token::className(), - 'user_id' => $user->id, - 'type' => Token::TYPE_CONFIRMATION, - ]); - $token->save(false); - $this->mailer->sendConfirmationMessage($user, $token); - } - - \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.' - ) - ); - - return true; - } } diff --git a/lib/User/Form/SettingsForm.php b/lib/User/Form/SettingsForm.php index 2b78fa1..9620def 100644 --- a/lib/User/Form/SettingsForm.php +++ b/lib/User/Form/SettingsForm.php @@ -11,6 +11,7 @@ namespace dektrium\user\models; +use Da\User\Factory\TokenFactory; use dektrium\user\helpers\Password; use dektrium\user\Mailer; use dektrium\user\Module; @@ -160,12 +161,8 @@ class SettingsForm extends Model { $this->user->unconfirmed_email = $this->email; /** @var Token $token */ - $token = Yii::createObject([ - 'class' => Token::className(), - 'user_id' => $this->user->id, - 'type' => Token::TYPE_CONFIRM_NEW_EMAIL, - ]); - $token->save(false); + $token = TokenFactory::makeConfirmNewMailToken($this->user->id); + $this->mailer->sendReconfirmationMessage($this->user, $token); Yii::$app->session->setFlash( 'info', diff --git a/lib/User/Model/Profile.php b/lib/User/Model/Profile.php index 2509b50..43c6202 100644 --- a/lib/User/Model/Profile.php +++ b/lib/User/Model/Profile.php @@ -138,7 +138,7 @@ class Profile extends ActiveRecord */ public function getUser() { - return $this->hasOne($this->getClassMap()->get('User'), ['id' => 'user_id']); + return $this->hasOne($this->getClassMap()->get(User::class), ['id' => 'user_id']); } /** diff --git a/lib/User/Model/SocialNetworkAccount.php b/lib/User/Model/SocialNetworkAccount.php index 5738956..37efba1 100644 --- a/lib/User/Model/SocialNetworkAccount.php +++ b/lib/User/Model/SocialNetworkAccount.php @@ -96,7 +96,7 @@ class SocialNetworkAccount extends ActiveRecord */ public function getUser() { - return $this->hasOne($this->getClassMap()->get('User'), ['id' => 'user_id']); + return $this->hasOne($this->getClassMap()->get(User::class), ['id' => 'user_id']); } /** diff --git a/lib/User/Model/Token.php b/lib/User/Model/Token.php index 99d9fbe..feec772 100644 --- a/lib/User/Model/Token.php +++ b/lib/User/Model/Token.php @@ -74,7 +74,7 @@ class Token extends ActiveRecord */ public function getUser() { - return $this->hasOne($this->getClassMap()->get('User'), ['id' => 'user_id']); + return $this->hasOne($this->getClassMap()->get(User::class), ['id' => 'user_id']); } /** diff --git a/lib/User/Model/User.php b/lib/User/Model/User.php index 07a25ca..3a46bb4 100644 --- a/lib/User/Model/User.php +++ b/lib/User/Model/User.php @@ -236,7 +236,7 @@ class User extends ActiveRecord implements IdentityInterface */ public function getProfile() { - return $this->hasOne($this->getClassMap()->get('Profile'), ['user_id' => 'id']); + return $this->hasOne($this->getClassMap()->get(Profile::class), ['user_id' => 'id']); } /** @@ -246,7 +246,9 @@ class User extends ActiveRecord implements IdentityInterface { if ($this->connectedAccounts == null) { /** @var SocialNetworkAccount[] $accounts */ - $accounts = $this->hasMany($this->getClassMap()->get('Account'), ['user_id' => 'id'])->all(); + $accounts = $this->hasMany($this->getClassMap() + ->get(SocialNetworkAccount::class), ['user_id' => 'id']) + ->all(); foreach ($accounts as $account) { $this->connectedAccounts[$account->provider] = $account; diff --git a/lib/User/Query/TokenQuery.php b/lib/User/Query/TokenQuery.php index bdc89eb..19e970c 100644 --- a/lib/User/Query/TokenQuery.php +++ b/lib/User/Query/TokenQuery.php @@ -10,4 +10,9 @@ class TokenQuery extends ActiveQuery { return $this->andWhere(['user_id' => $userId, 'code' => $code, 'type' => Token::TYPE_RECOVERY]); } + + public function whereIsConfirmationType($userId, $code) + { + return $this->andWhere(['user_id' => $userId, 'code' => $code, 'type' => Token::TYPE_CONFIRM_NEW_EMAIL]); + } } diff --git a/lib/User/Service/EmailConfirmationService.php b/lib/User/Service/EmailConfirmationService.php new file mode 100644 index 0000000..8a071fc --- /dev/null +++ b/lib/User/Service/EmailConfirmationService.php @@ -0,0 +1,43 @@ +code = $code; + $this->model = $model; + $this->tokenQuery = $tokenQuery; + $this->userConfirmationService = $userConfirmationService; + } + + public function run() + { + $token = $this->tokenQuery->whereIsConfirmationType($this->model->id, $this->code)->one(); + + if ($token instanceof Token && !$token->getIsExpired()) { + $token->delete(); + + return $this->userConfirmationService->run(); + } + + return false; + } + +} diff --git a/lib/User/Service/PasswordRecoveryService.php b/lib/User/Service/PasswordRecoveryService.php index 06297be..d1d1cf8 100644 --- a/lib/User/Service/PasswordRecoveryService.php +++ b/lib/User/Service/PasswordRecoveryService.php @@ -2,6 +2,7 @@ namespace Da\User\Service; use Da\User\Contracts\ServiceInterface; +use Da\User\Factory\TokenFactory; use Da\User\Model\Token; use Da\User\Model\User; use Da\User\Query\UserQuery; @@ -31,16 +32,10 @@ class PasswordRecoveryService implements ServiceInterface try { /** @var User $user */ $user = $this->query->whereEmail($this->email)->one(); - /** @var Token $token */ - $token = Yii::createObject( - [ - 'class' => Token::class, - 'user_id' => $user->id, - 'type' => Token::TYPE_RECOVERY - ] - ); - if (!$token->save(false)) { + $token = TokenFactory::makeRecoveryToken($user->id); + + if (!$token) { return false; } diff --git a/lib/User/Service/ResendConfirmationService.php b/lib/User/Service/ResendConfirmationService.php index ff686fd..566c12a 100644 --- a/lib/User/Service/ResendConfirmationService.php +++ b/lib/User/Service/ResendConfirmationService.php @@ -4,10 +4,7 @@ namespace Da\User\Service; use Da\User\Contracts\ServiceInterface; use Da\User\Factory\TokenFactory; -use Da\User\Helper\SecurityHelper; -use Da\User\Model\Token; use Da\User\Model\User; -use Da\User\Query\UserQuery; use yii\log\Logger; class ResendConfirmationService implements ServiceInterface diff --git a/lib/User/Service/UserConfirmationService.php b/lib/User/Service/UserConfirmationService.php index c6d9b5c..9d255c9 100644 --- a/lib/User/Service/UserConfirmationService.php +++ b/lib/User/Service/UserConfirmationService.php @@ -17,9 +17,11 @@ class UserConfirmationService implements ServiceInterface public function run() { $this->model->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION); - $result = (bool) $this->model->updateAttributes(['confirmed_at' => time()]); - $this->model->trigger(UserEvent::EVENT_AFTER_CONFIRMATION); + if ((bool)$this->model->updateAttributes(['confirmed_at' => time()])) { + $this->model->trigger(UserEvent::EVENT_AFTER_CONFIRMATION); - return $result; + return true; + } + return false; } } diff --git a/lib/User/Service/UserRegisterService.php b/lib/User/Service/UserRegisterService.php index a8a6a56..d66e1d6 100644 --- a/lib/User/Service/UserRegisterService.php +++ b/lib/User/Service/UserRegisterService.php @@ -3,6 +3,7 @@ namespace Da\User\Service; use Da\User\Contracts\ServiceInterface; use Da\User\Event\UserEvent; +use Da\User\Factory\TokenFactory; use Da\User\Helper\SecurityHelper; use Da\User\Model\Token; use Da\User\Model\User; @@ -50,10 +51,12 @@ class UserRegisterService implements ServiceInterface } if($model->module->enableEmailConfirmation) { - $token = $model->make(Token::class, ['type' => Token::TYPE_CONFIRMATION]); - $token->link('user', $model); + $token = TokenFactory::makeConfirmationToken($model->id); } + if(isset($token)) { + $this->mailService->setViewParam('token', $token); + } $this->mailService->run(); $model->trigger(UserEvent::EVENT_AFTER_REGISTER);