added email change strategies
This commit is contained in:
9
lib/User/Contracts/MailChangeStrategyInterface.php
Normal file
9
lib/User/Contracts/MailChangeStrategyInterface.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace Da\User\Contracts;
|
||||
|
||||
interface MailChangeStrategyInterface extends StrategyInterface
|
||||
{
|
||||
const TYPE_INSECURE = 0;
|
||||
const TYPE_DEFAULT = 1;
|
||||
const TYPE_SECURE = 2;
|
||||
}
|
||||
@ -1,15 +1,10 @@
|
||||
<?php
|
||||
namespace Da\User\Contracts;
|
||||
|
||||
/**
|
||||
*
|
||||
* StrategyInterface.php
|
||||
*
|
||||
* Date: 3/12/16
|
||||
* Time: 16:23
|
||||
* @author Antonio Ramirez <hola@2amigos.us>
|
||||
*/
|
||||
interface StrategyInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function run();
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ class RecoveryController extends Controller
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
/** @var Token $token */
|
||||
$token = $this->tokenQuery->whereIsRecoveryType($id, $code)->one();
|
||||
$token = $this->tokenQuery->whereUserId($id)->whereCode($code)->whereIsRecoveryType()->one();
|
||||
/** @var ResetPasswordEvent $event */
|
||||
$event = $this->make(ResetPasswordEvent::class, [$token]);
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ use Da\User\Model\SocialNetworkAccount;
|
||||
use Da\User\Model\User;
|
||||
use Da\User\Query\SocialNetworkAccountQuery;
|
||||
use Da\User\Query\UserQuery;
|
||||
use Da\User\Service\AccountConfirmationService;
|
||||
use Da\User\Service\EmailConfirmationService;
|
||||
use Da\User\Service\ResendConfirmationService;
|
||||
use Da\User\Service\UserConfirmationService;
|
||||
@ -172,7 +173,7 @@ class RegistrationController extends Controller
|
||||
|
||||
$this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event);
|
||||
|
||||
if ($this->make(EmailConfirmationService::class, [$code, $user, $userConfirmationService])->run()) {
|
||||
if ($this->make(AccountConfirmationService::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.'));
|
||||
|
||||
|
||||
160
lib/User/Controller/SettingsController.php
Normal file
160
lib/User/Controller/SettingsController.php
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
namespace Da\User\Controller;
|
||||
|
||||
use Da\User\Contracts\MailChangeStrategyInterface;
|
||||
use Da\User\Event\FormEvent;
|
||||
use Da\User\Event\ProfileEvent;
|
||||
use Da\User\Event\UserEvent;
|
||||
use Da\User\Form\SettingsForm;
|
||||
use Da\User\Model\Profile;
|
||||
use Da\User\Module;
|
||||
use Da\User\Query\ProfileQuery;
|
||||
use Da\User\Query\SocialNetworkAccountQuery;
|
||||
use Da\User\Query\UserQuery;
|
||||
use Da\User\Service\EmailChangeService;
|
||||
use Da\User\Traits\ContainerTrait;
|
||||
use Da\User\Validator\AjaxRequestModelValidator;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\filters\VerbFilter;
|
||||
use yii\web\Controller;
|
||||
use Yii;
|
||||
use yii\web\NotFoundHttpException;
|
||||
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
use ContainerTrait;
|
||||
|
||||
protected $profileQuery;
|
||||
protected $userQuery;
|
||||
protected $socialNetworkAccountQuery;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $defaultAction = 'profile';
|
||||
|
||||
/**
|
||||
* SettingsController constructor.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Module $module
|
||||
* @param ProfileQuery $profileQuery
|
||||
* @param UserQuery $userQuery
|
||||
* @param SocialNetworkAccountQuery $socialNetworkAccountQuery
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(
|
||||
$id,
|
||||
Module $module,
|
||||
ProfileQuery $profileQuery,
|
||||
UserQuery $userQuery,
|
||||
SocialNetworkAccountQuery $socialNetworkAccountQuery,
|
||||
array $config
|
||||
) {
|
||||
$this->profileQuery = $profileQuery;
|
||||
$this->userQuery = $userQuery;
|
||||
$this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
|
||||
parent::__construct($id, $module, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'verbs' => [
|
||||
'class' => VerbFilter::className(),
|
||||
'actions' => [
|
||||
'disconnect' => ['post'],
|
||||
'delete' => ['post'],
|
||||
],
|
||||
],
|
||||
'access' => [
|
||||
'class' => AccessControl::className(),
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => ['profile', 'account', 'networks', 'disconnect', 'delete'],
|
||||
'roles' => ['@'],
|
||||
],
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => ['confirm'],
|
||||
'roles' => ['?', '@'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function actionProfile()
|
||||
{
|
||||
$profile = $this->profileQuery->whereId(Yii::$app->user->identity->getId())->one();
|
||||
|
||||
if ($profile === null) {
|
||||
$profile = $this->make(Profile::class);
|
||||
$profile->link('user', Yii::$app->user->identity);
|
||||
}
|
||||
|
||||
$event = $this->make(ProfileEvent::class, [$profile]);
|
||||
|
||||
$this->make(AjaxRequestModelValidator::class, [$profile])->validate();
|
||||
|
||||
if ($profile->load(Yii::$app->request->post())) {
|
||||
$this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event);
|
||||
if ($profile->save()) {
|
||||
Yii::$app->getSession()->setFlash('success', Yii::t('user', 'Your profile has been updated'));
|
||||
$this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event);
|
||||
|
||||
return $this->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
'profile',
|
||||
[
|
||||
'model' => $profile,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function actionAccount()
|
||||
{
|
||||
$form = $this->make(SettingsForm::class);
|
||||
$event = $this->make(FormEvent::class, [$form]);
|
||||
|
||||
$this->make(AjaxRequestModelValidator::class, [$form])->validate();
|
||||
|
||||
if($form->load(Yii::$app->request->post())) {
|
||||
$this->trigger(UserEvent::EVENT_BEFORE_ACCOUNT_UPDATE, $event);
|
||||
if($form->save()) {
|
||||
Yii::$app->getSession()->setFlash('success', Yii::t('user', 'Your account details have been updated-'));
|
||||
$this->trigger(UserEvent::EVENT_AFTER_ACCOUNT_UPDATE, $event);
|
||||
|
||||
return $this->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('account', [
|
||||
'model' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
public function actionConfirm($id, $code) {
|
||||
$user = $this->userQuery->whereId($id)->one();
|
||||
|
||||
if ($user === null || $this->module->emailChangeStrategy == MailChangeStrategyInterface::TYPE_INSECURE) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$event = $this->make(UserEvent::class, [$user]);
|
||||
|
||||
$this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event);
|
||||
if($this->make(EmailChangeService::class, [$code, $user])->run()) {
|
||||
$this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event);
|
||||
}
|
||||
|
||||
return $this->redirect(['account']);
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,8 @@ class UserEvent extends Event
|
||||
const EVENT_AFTER_CREATE = 'afterCreate';
|
||||
const EVENT_BEFORE_REGISTER = 'beforeRegister';
|
||||
const EVENT_AFTER_REGISTER = 'afterRegister';
|
||||
const EVENT_BEFORE_ACCOUNT_UPDATE = 'beforeAccountUpdate';
|
||||
const EVENT_AFTER_ACCOUNT_UPDATE = 'afterAccountUpdate';
|
||||
const EVENT_BEFORE_PROFILE_UPDATE = 'beforeProfileUpdate';
|
||||
const EVENT_AFTER_PROFILE_UPDATE = 'afterProfileUpdate';
|
||||
const EVENT_BEFORE_CONFIRMATION = 'beforeConfirmation';
|
||||
|
||||
67
lib/User/Factory/EmailChangeStrategyFactory.php
Normal file
67
lib/User/Factory/EmailChangeStrategyFactory.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace Da\User\Factory;
|
||||
|
||||
use Da\User\Contracts\MailChangeStrategyInterface;
|
||||
use Da\User\Contracts\StrategyInterface;
|
||||
use Da\User\Form\SettingsForm;
|
||||
use Da\User\Strategy\DefaultEmailChangeStrategy;
|
||||
use Da\User\Strategy\InsecureEmailChangeStrategy;
|
||||
use Da\User\Strategy\SecureEmailChangeStrategy;
|
||||
use Yii;
|
||||
use Exception;
|
||||
|
||||
class EmailChangeStrategyFactory
|
||||
{
|
||||
|
||||
protected static $map = [
|
||||
MailChangeStrategyInterface::TYPE_INSECURE => InsecureEmailChangeStrategy::class,
|
||||
MailChangeStrategyInterface::TYPE_DEFAULT => DefaultEmailChangeStrategy::class,
|
||||
MailChangeStrategyInterface::TYPE_SECURE => SecureEmailChangeStrategy::class
|
||||
];
|
||||
|
||||
/**
|
||||
* @param $strategy
|
||||
* @param SettingsForm $form
|
||||
*
|
||||
* @return MailChangeStrategyInterface
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function makeByStrategyType($strategy, SettingsForm $form)
|
||||
{
|
||||
if (array_key_exists($strategy, static::$map)) {
|
||||
return Yii::createObject(static::$map[$strategy], [$form]);
|
||||
}
|
||||
|
||||
throw new Exception('Unknown strategy type');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SettingsForm $form
|
||||
*
|
||||
* @return DefaultEmailChangeStrategy
|
||||
*/
|
||||
public static function makeDefaultEmailChangeStrategy(SettingsForm $form)
|
||||
{
|
||||
return Yii::createObject(static::$map[MailChangeStrategyInterface::TYPE_DEFAULT], [$form]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SettingsForm $form
|
||||
*
|
||||
* @return InsecureEmailChangeStrategy
|
||||
*/
|
||||
public static function makeInsecureEmailChangeStrategy(SettingsForm $form)
|
||||
{
|
||||
return Yii::createObject(static::$map[MailChangeStrategyInterface::TYPE_INSECURE], [$form]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SettingsForm $form
|
||||
*
|
||||
* @return SecureEmailChangeStrategy
|
||||
*/
|
||||
public static function makeSecureEmailChangeStrategy(SettingsForm $form)
|
||||
{
|
||||
return Yii::createObject(static::$map[MailChangeStrategyInterface::TYPE_SECURE], [$form]);
|
||||
}
|
||||
}
|
||||
@ -52,6 +52,12 @@ class MailFactory
|
||||
return static::makeMailerService($from, $to, $subject, 'recovery', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param Token|null $token
|
||||
*
|
||||
* @return MailService
|
||||
*/
|
||||
public static function makeConfirmationMailerService(User $user, Token $token = null)
|
||||
{
|
||||
/** @var Module $module */
|
||||
@ -67,6 +73,29 @@ class MailFactory
|
||||
return static::makeMailerService($from, $to, $subject, 'recovery', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param Token $token
|
||||
*
|
||||
* @return MailService
|
||||
*/
|
||||
public static function makeReconfirmationMailerService(User $user, Token $token) {
|
||||
/** @var Module $module */
|
||||
$module = Yii::$app->getModule('user');
|
||||
$to = $token->type === Token::TYPE_CONFIRM_NEW_EMAIL
|
||||
? $user->unconfirmed_email
|
||||
: $user->email;
|
||||
|
||||
$from = $module->mailParams['fromEmail'];
|
||||
$subject = $module->mailParams['reconfirmationMailSubject'];
|
||||
$params = [
|
||||
'user' => $token && $token->user ? $token->user : null,
|
||||
'token' => $token
|
||||
];
|
||||
|
||||
return static::makeMailerService($from, $to, $subject, 'recovery', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a MailerService
|
||||
*
|
||||
|
||||
@ -37,6 +37,20 @@ class TokenFactory
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $userId
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public static function makeConfirmOldMailToken($userId)
|
||||
{
|
||||
$token = self::make($userId, Token::TYPE_CONFIRM_OLD_EMAIL);
|
||||
|
||||
$token->save(false);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $userId
|
||||
*
|
||||
|
||||
@ -1,113 +1,107 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Dektrium project.
|
||||
*
|
||||
* (c) Dektrium project <http://github.com/dektrium/>
|
||||
*
|
||||
* 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\Factory\TokenFactory;
|
||||
use dektrium\user\helpers\Password;
|
||||
use dektrium\user\Mailer;
|
||||
use dektrium\user\Module;
|
||||
use dektrium\user\traits\ModuleTrait;
|
||||
use Da\User\Helper\SecurityHelper;
|
||||
use Da\User\Model\User;
|
||||
use Da\User\Traits\ContainerTrait;
|
||||
use Da\User\Traits\ModuleTrait;
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
|
||||
/**
|
||||
* SettingsForm gets user's username, email and password and changes them.
|
||||
*
|
||||
* @property User $user
|
||||
*
|
||||
* @author Dmitry Erofeev <dmeroff@gmail.com>
|
||||
*/
|
||||
class SettingsForm extends Model
|
||||
{
|
||||
use ModuleTrait;
|
||||
use ContainerTrait;
|
||||
|
||||
/** @var string */
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/** @var string */
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $username;
|
||||
|
||||
/** @var string */
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $new_password;
|
||||
|
||||
/** @var string */
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $current_password;
|
||||
|
||||
/** @var Mailer */
|
||||
protected $mailer;
|
||||
/**
|
||||
* @var SecurityHelper
|
||||
*/
|
||||
protected $securityHelper;
|
||||
|
||||
/** @var User */
|
||||
private $_user;
|
||||
private $user;
|
||||
|
||||
/** @return User */
|
||||
public function getUser()
|
||||
public function __construct(SecurityHelper $securityHelper, array $config)
|
||||
{
|
||||
if ($this->_user == null) {
|
||||
$this->_user = Yii::$app->user->identity;
|
||||
}
|
||||
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function __construct(Mailer $mailer, $config = [])
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
$this->setAttributes([
|
||||
'username' => $this->user->username,
|
||||
'email' => $this->user->unconfirmed_email ?: $this->user->email,
|
||||
], false);
|
||||
$this->securityHelper = $securityHelper;
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'usernameRequired' => ['username', 'required'],
|
||||
'usernameTrim' => ['username', 'filter', 'filter' => 'trim'],
|
||||
'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255],
|
||||
'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255],
|
||||
'usernamePattern' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@]+$/'],
|
||||
'emailRequired' => ['email', 'required'],
|
||||
'emailTrim' => ['email', 'filter', 'filter' => 'trim'],
|
||||
'emailPattern' => ['email', 'email'],
|
||||
'emailUsernameUnique' => [['email', 'username'], 'unique', 'when' => function ($model, $attribute) {
|
||||
return $this->user->$attribute != $model->$attribute;
|
||||
}, 'targetClass' => $this->module->modelMap['User']],
|
||||
'emailUsernameUnique' => [
|
||||
['email', 'username'],
|
||||
'unique',
|
||||
'when' => function ($model, $attribute) {
|
||||
return $this->user->$attribute != $model->$attribute;
|
||||
},
|
||||
'targetClass' => $this->getClassMap()[User::class]
|
||||
],
|
||||
'newPasswordLength' => ['new_password', 'string', 'max' => 72, 'min' => 6],
|
||||
'currentPasswordRequired' => ['current_password', 'required'],
|
||||
'currentPasswordValidate' => ['current_password', function ($attr) {
|
||||
if (!Password::validate($this->$attr, $this->user->password_hash)) {
|
||||
$this->addError($attr, Yii::t('user', 'Current password is not valid'));
|
||||
'currentPasswordValidate' => [
|
||||
'current_password',
|
||||
function ($attribute) {
|
||||
if (!$this->securityHelper->validatePassword($this->$attribute, $this->user->password_hash)) {
|
||||
$this->addError($attribute, Yii::t('user', 'Current password is not valid'));
|
||||
}
|
||||
}
|
||||
}],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return [
|
||||
'email' => Yii::t('user', 'Email'),
|
||||
'username' => Yii::t('user', 'Username'),
|
||||
'new_password' => Yii::t('user', 'New password'),
|
||||
'email' => Yii::t('user', 'Email'),
|
||||
'username' => Yii::t('user', 'Username'),
|
||||
'new_password' => Yii::t('user', 'New password'),
|
||||
'current_password' => Yii::t('user', 'Current password'),
|
||||
];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function formName()
|
||||
/**
|
||||
* @return User|null|\yii\web\IdentityInterface
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return 'settings-form';
|
||||
if ($this->user == null) {
|
||||
$this->user = Yii::$app->user->identity;
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,11 +173,13 @@ class SettingsForm extends Model
|
||||
{
|
||||
$this->defaultEmailChange();
|
||||
/** @var Token $token */
|
||||
$token = Yii::createObject([
|
||||
'class' => Token::className(),
|
||||
'user_id' => $this->user->id,
|
||||
'type' => Token::TYPE_CONFIRM_OLD_EMAIL,
|
||||
]);
|
||||
$token = Yii::createObject(
|
||||
[
|
||||
'class' => Token::className(),
|
||||
'user_id' => $this->user->id,
|
||||
'type' => Token::TYPE_CONFIRM_OLD_EMAIL,
|
||||
]
|
||||
);
|
||||
$token->save(false);
|
||||
$this->mailer->sendReconfirmationMessage($this->user, $token);
|
||||
|
||||
|
||||
@ -24,11 +24,13 @@ use yii\web\IdentityInterface;
|
||||
* @property integer $id
|
||||
* @property string $username
|
||||
* @property string $email
|
||||
* @property string $unconfirmed_email
|
||||
* @property string $password_hash
|
||||
* @property string $auth_key
|
||||
* @property integer $registration_ip
|
||||
* @property integer $confirmed_at
|
||||
* @property integer $blocked_at
|
||||
* @property integer $flags
|
||||
* @property integer $created_at
|
||||
* @property integer $updated_at
|
||||
*
|
||||
@ -41,6 +43,10 @@ class User extends ActiveRecord implements IdentityInterface
|
||||
use ModuleTrait;
|
||||
use ContainerTrait;
|
||||
|
||||
// following constants are used on secured email changing process
|
||||
const OLD_EMAIL_CONFIRMED = 0b1;
|
||||
const NEW_EMAIL_CONFIRMED = 0b10;
|
||||
|
||||
/**
|
||||
* @var string default user name regular expression.
|
||||
*/
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Da\User;
|
||||
|
||||
use Da\User\Strategy\DefaultEmailChangeStrategy;
|
||||
use Da\User\Contracts\MailChangeStrategyInterface;
|
||||
|
||||
class Module extends \yii\base\Module
|
||||
{
|
||||
@ -29,7 +29,7 @@ class Module extends \yii\base\Module
|
||||
/**
|
||||
* @var string the class name of the strategy class to handle user's email change.
|
||||
*/
|
||||
public $emailChangeStrategy = DefaultEmailChangeStrategy::class;
|
||||
public $emailChangeStrategy = MailChangeStrategyInterface::TYPE_DEFAULT;
|
||||
/**
|
||||
* @var int the time user will be auto logged in.
|
||||
*/
|
||||
|
||||
@ -6,13 +6,49 @@ use yii\db\ActiveQuery;
|
||||
|
||||
class TokenQuery extends ActiveQuery
|
||||
{
|
||||
public function whereIsRecoveryType($userId, $code)
|
||||
/**
|
||||
* @param $userId
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereUserId($userId)
|
||||
{
|
||||
return $this->andWhere(['user_id' => $userId, 'code' => $code, 'type' => Token::TYPE_RECOVERY]);
|
||||
return $this->andWhere(['user_id' => $userId]);
|
||||
}
|
||||
|
||||
public function whereIsConfirmationType($userId, $code)
|
||||
/**
|
||||
* @param $code
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereCode($code)
|
||||
{
|
||||
return $this->andWhere(['user_id' => $userId, 'code' => $code, 'type' => Token::TYPE_CONFIRM_NEW_EMAIL]);
|
||||
return $this->andWhere(['code' => $code]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function whereIsRecoveryType()
|
||||
{
|
||||
return $this->andWhere(['type' => Token::TYPE_RECOVERY]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function whereIsConfirmationType()
|
||||
{
|
||||
return $this->andWhere(['type' => Token::TYPE_CONFIRM_NEW_EMAIL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereIsTypes(array $types)
|
||||
{
|
||||
return $this->andWhere(['in', 'type', $types]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,11 @@ use yii\db\ActiveQuery;
|
||||
|
||||
class UserQuery extends ActiveQuery
|
||||
{
|
||||
/**
|
||||
* @param $usernameOrEmail
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereUsernameOrEmail($usernameOrEmail)
|
||||
{
|
||||
return filter_var($usernameOrEmail, FILTER_VALIDATE_EMAIL)
|
||||
@ -13,18 +18,44 @@ class UserQuery extends ActiveQuery
|
||||
: $this->whereUsername($usernameOrEmail);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $email
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereEmail($email)
|
||||
{
|
||||
return $this->andWhere(['email' => $email]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $username
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereUsername($username)
|
||||
{
|
||||
return $this->andWhere(['username' => $username]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereId($id)
|
||||
{
|
||||
return $this->andWhere(['id' => $id]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function whereNotId($id)
|
||||
{
|
||||
return $this->andWhere(['<>', 'id', $id]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ use Da\User\Model\Token;
|
||||
use Da\User\Model\User;
|
||||
use Da\User\Query\TokenQuery;
|
||||
|
||||
class EmailConfirmationService implements ServiceInterface
|
||||
class AccountConfirmationService implements ServiceInterface
|
||||
{
|
||||
protected $model;
|
||||
protected $code;
|
||||
@ -29,7 +29,11 @@ class EmailConfirmationService implements ServiceInterface
|
||||
|
||||
public function run()
|
||||
{
|
||||
$token = $this->tokenQuery->whereIsConfirmationType($this->model->id, $this->code)->one();
|
||||
$token = $this->tokenQuery
|
||||
->whereUserId($this->model->id)
|
||||
->whereCode($this->code)
|
||||
->whereIsConfirmationType()
|
||||
->one();
|
||||
|
||||
if ($token instanceof Token && !$token->getIsExpired()) {
|
||||
$token->delete();
|
||||
87
lib/User/Service/EmailChangeService.php
Normal file
87
lib/User/Service/EmailChangeService.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
namespace Da\User\Service;
|
||||
|
||||
use Da\User\Contracts\MailChangeStrategyInterface;
|
||||
use Da\User\Contracts\ServiceInterface;
|
||||
use Da\User\Model\Token;
|
||||
use Da\User\Model\User;
|
||||
use Da\User\Query\TokenQuery;
|
||||
use Da\User\Query\UserQuery;
|
||||
use Da\User\Traits\ModuleTrait;
|
||||
use Yii;
|
||||
|
||||
class EmailChangeService implements ServiceInterface
|
||||
{
|
||||
use ModuleTrait;
|
||||
|
||||
protected $code;
|
||||
protected $model;
|
||||
protected $tokenQuery;
|
||||
protected $userQuery;
|
||||
|
||||
public function __construct($code, User $model, TokenQuery $tokenQuery, UserQuery $userQuery)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->model = $model;
|
||||
$this->tokenQuery = $tokenQuery;
|
||||
$this->userQuery = $userQuery;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
/** @var Token $token */
|
||||
$token = $this->tokenQuery
|
||||
->whereUserId($this->model->id)
|
||||
->whereCode($this->code)
|
||||
->whereIsTypes([Token::TYPE_CONFIRM_NEW_EMAIL, Token::TYPE_CONFIRM_OLD_EMAIL])
|
||||
->one();
|
||||
|
||||
if ($token === null || $token->getIsExpired()) {
|
||||
Yii::$app->session->setFlash('danger', Yii::t('user', 'Your confirmation token is invalid or expired'));
|
||||
|
||||
return false;
|
||||
} else {
|
||||
$token->delete();
|
||||
if (empty($this->model->unconfirmed_email)) {
|
||||
Yii::$app->session->setFlash('danger', Yii::t('user', 'An error occurred processing your request'));
|
||||
|
||||
} elseif ($this->userQuery->whereEmail($this->model->unconfirmed_email)->exists() === false) {
|
||||
|
||||
if ($this->getModule()->emailChangeStrategy === MailChangeStrategyInterface::TYPE_SECURE) {
|
||||
if ($token->type === Token::TYPE_CONFIRM_NEW_EMAIL) {
|
||||
$this->model->flags |= User::NEW_EMAIL_CONFIRMED;
|
||||
Yii::$app->session->setFlash(
|
||||
'success',
|
||||
Yii::t(
|
||||
'user',
|
||||
'Awesome, almost there. ' .
|
||||
'Now you need to click the confirmation link sent to your old email address.'
|
||||
)
|
||||
);
|
||||
} elseif ($token->type === Token::TYPE_CONFIRM_OLD_EMAIL) {
|
||||
$this->model->flags |= User::OLD_EMAIL_CONFIRMED;
|
||||
Yii::$app->session->setFlash(
|
||||
'success',
|
||||
Yii::t(
|
||||
'user',
|
||||
'Awesome, almost there. ' .
|
||||
'Now you need to click the confirmation link sent to your new email address.'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($this->getModule()->emailChangeStrategy === MailChangeStrategyInterface::TYPE_DEFAULT
|
||||
|| ($this->model->flags & User::NEW_EMAIL_CONFIRMED & $this->model->flags & User::OLD_EMAIL_CONFIRMED)
|
||||
) {
|
||||
$this->model->email = $this->model->unconfirmed_email;
|
||||
$this->model->unconfirmed_email = null;
|
||||
Yii::$app->session->setFlash('success', Yii::t('user', 'Your email address has been changed'));
|
||||
}
|
||||
|
||||
return $this->model->save(false);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,17 +1,43 @@
|
||||
<?php
|
||||
namespace Da\User\Strategy;
|
||||
|
||||
use Da\User\Contracts\StrategyInterface;
|
||||
use Da\User\Contracts\MailChangeStrategyInterface;
|
||||
use Da\User\Factory\MailFactory;
|
||||
use Da\User\Factory\TokenFactory;
|
||||
use Da\User\Form\SettingsForm;
|
||||
use Da\User\Traits\ContainerTrait;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
*
|
||||
* DefaultEmailChangeStrategy.php
|
||||
*
|
||||
* Date: 3/12/16
|
||||
* Time: 16:22
|
||||
* @author Antonio Ramirez <hola@2amigos.us>
|
||||
*/
|
||||
class DefaultEmailChangeStrategy implements StrategyInterface
|
||||
class DefaultEmailChangeStrategy implements MailChangeStrategyInterface
|
||||
{
|
||||
use ContainerTrait;
|
||||
|
||||
protected $form;
|
||||
|
||||
public function __construct(SettingsForm $form)
|
||||
{
|
||||
$this->form = $form;
|
||||
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->form->getUser()->unconfirmed_email = $this->form->email;
|
||||
|
||||
$token = TokenFactory::makeConfirmNewMailToken($this->form->getUser()->id);
|
||||
|
||||
$mailService = MailFactory::makeReconfirmationMailerService($this->form->getUser(), $token);
|
||||
|
||||
if ($mailService->run()) {
|
||||
Yii::$app
|
||||
->session
|
||||
->setFlash('info', Yii::t('user', 'A confirmation message has been sent to your new email address'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,17 +1,23 @@
|
||||
<?php
|
||||
namespace Da\User\Strategy;
|
||||
|
||||
use Da\User\Contracts\StrategyInterface;
|
||||
use Da\User\Contracts\MailChangeStrategyInterface;
|
||||
use Da\User\Form\SettingsForm;
|
||||
|
||||
/**
|
||||
*
|
||||
* InsecuredEmailChangeStrategy.php
|
||||
*
|
||||
* Date: 3/12/16
|
||||
* Time: 16:21
|
||||
* @author Antonio Ramirez <hola@2amigos.us>
|
||||
*/
|
||||
class InsecureEmailChangeStrategy implements StrategyInterface
|
||||
|
||||
class InsecureEmailChangeStrategy implements MailChangeStrategyInterface
|
||||
{
|
||||
protected $form;
|
||||
|
||||
public function __construct(SettingsForm $form)
|
||||
{
|
||||
$this->form = $form;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->form->getUser()->email = $this->form->email;
|
||||
return $this->form->getUser()->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,17 +1,55 @@
|
||||
<?php
|
||||
namespace Da\User\Strategy;
|
||||
|
||||
use Da\User\Contracts\StrategyInterface;
|
||||
use Da\User\Contracts\MailChangeStrategyInterface;
|
||||
use Da\User\Factory\MailFactory;
|
||||
use Da\User\Factory\TokenFactory;
|
||||
use Da\User\Form\SettingsForm;
|
||||
use Da\User\Model\User;
|
||||
use Da\User\Traits\ContainerTrait;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
*
|
||||
* SecuredEmailChangeStrategy.php
|
||||
*
|
||||
* Date: 3/12/16
|
||||
* Time: 16:20
|
||||
* @author Antonio Ramirez <hola@2amigos.us>
|
||||
*/
|
||||
class SecureEmailChangeStrategy implements StrategyInterface
|
||||
class SecureEmailChangeStrategy implements MailChangeStrategyInterface
|
||||
{
|
||||
use ContainerTrait;
|
||||
|
||||
protected $form;
|
||||
|
||||
public function __construct(SettingsForm $form)
|
||||
{
|
||||
$this->form = $form;
|
||||
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
if ($this->make(DefaultEmailChangeStrategy::class, [$this->form])->run()) {
|
||||
|
||||
$token = TokenFactory::makeConfirmOldMailToken($this->form->getUser()->id);
|
||||
$mailService = MailFactory::makeReconfirmationMailerService($this->form->getUser(), $token);
|
||||
|
||||
if ($mailService->run()) {
|
||||
// unset flags if they exist
|
||||
$this->form->getUser()->flags &= ~User::NEW_EMAIL_CONFIRMED;
|
||||
$this->form->getUser()->flags &= ~User::OLD_EMAIL_CONFIRMED;
|
||||
if ($this->form->getUser()->save(false)) {
|
||||
Yii::$app
|
||||
->session
|
||||
->setFlash(
|
||||
'info',
|
||||
Yii::t(
|
||||
'user',
|
||||
'We have sent confirmation links to both old and new email addresses. ' .
|
||||
'You must click both links to complete your request.'
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user