diff --git a/apps/advanced/backend/controllers/SiteController.php b/apps/advanced/backend/controllers/SiteController.php index ecf684c..6a9ff5c 100644 --- a/apps/advanced/backend/controllers/SiteController.php +++ b/apps/advanced/backend/controllers/SiteController.php @@ -1,18 +1,24 @@ <?php - namespace backend\controllers; use Yii; +use yii\web\AccessControl; use yii\web\Controller; -use common\models\LoginForm; +use common\models\forms\LoginForm; +/** + * Site controller + */ class SiteController extends Controller { + /** + * @inheritdoc + */ public function behaviors() { return [ 'access' => [ - 'class' => \yii\web\AccessControl::className(), + 'class' => AccessControl::className(), 'rules' => [ [ 'actions' => ['login', 'error'], @@ -28,6 +34,9 @@ class SiteController extends Controller ]; } + /** + * @inheritdoc + */ public function actions() { return [ diff --git a/apps/advanced/backend/views/site/login.php b/apps/advanced/backend/views/site/login.php index 1326203..92d3d79 100644 --- a/apps/advanced/backend/views/site/login.php +++ b/apps/advanced/backend/views/site/login.php @@ -5,7 +5,7 @@ use yii\widgets\ActiveForm; /** * @var yii\web\View $this * @var yii\widgets\ActiveForm $form - * @var common\models\LoginForm $model + * @var common\models\forms\LoginForm $model */ $this->title = 'Login'; $this->params['breadcrumbs'][] = $this->title; diff --git a/apps/advanced/common/models/User.php b/apps/advanced/common/models/User.php index af3c997..0630c5b 100644 --- a/apps/advanced/common/models/User.php +++ b/apps/advanced/common/models/User.php @@ -6,8 +6,7 @@ use yii\helpers\Security; use yii\web\IdentityInterface; /** - * Class User - * @package common\models + * User model * * @property integer $id * @property string $username @@ -22,16 +21,14 @@ use yii\web\IdentityInterface; */ class User extends ActiveRecord implements IdentityInterface { - /** - * @var string the raw password. Used to collect password input and isn't saved in database - */ - public $password; - const STATUS_DELETED = 0; const STATUS_ACTIVE = 10; const ROLE_USER = 10; + /** + * @inheritdoc + */ public function behaviors() { return [ @@ -46,10 +43,7 @@ class User extends ActiveRecord implements IdentityInterface } /** - * Finds an identity by the given ID. - * - * @param string|integer $id the ID to be looked for - * @return IdentityInterface|null the identity object that matches the given ID. + * @inheritdoc */ public static function findIdentity($id) { @@ -68,7 +62,7 @@ class User extends ActiveRecord implements IdentityInterface } /** - * @return int|string|array current user ID + * @inheritdoc */ public function getId() { @@ -76,7 +70,7 @@ class User extends ActiveRecord implements IdentityInterface } /** - * @return string current user auth key + * @inheritdoc */ public function getAuthKey() { @@ -84,8 +78,7 @@ class User extends ActiveRecord implements IdentityInterface } /** - * @param string $authKey - * @return boolean if auth key is valid for current user + * @inheritdoc */ public function validateAuthKey($authKey) { @@ -93,6 +86,8 @@ class User extends ActiveRecord implements IdentityInterface } /** + * Validates password + * * @param string $password password to validate * @return bool if password provided is valid for current user */ @@ -101,13 +96,13 @@ class User extends ActiveRecord implements IdentityInterface return Security::validatePassword($password, $this->password_hash); } + /** + * @inheritdoc + */ public function rules() { return [ - ['status', 'default', 'value' => self::STATUS_ACTIVE], ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], - - ['role', 'default', 'value' => self::ROLE_USER], ['role', 'in', 'range' => [self::ROLE_USER]], ['username', 'filter', 'filter' => 'trim'], @@ -117,34 +112,7 @@ class User extends ActiveRecord implements IdentityInterface ['email', 'filter', 'filter' => 'trim'], ['email', 'required'], ['email', 'email'], - ['email', 'unique', 'message' => 'This email address has already been taken.', 'on' => 'signup'], - ['email', 'exist', 'message' => 'There is no user with such email.', 'on' => 'requestPasswordResetToken'], - - ['password', 'required'], - ['password', 'string', 'min' => 6], + ['email', 'unique'], ]; } - - public function scenarios() - { - return [ - 'signup' => ['username', 'email', 'password', '!status', '!role'], - 'resetPassword' => ['password'], - 'requestPasswordResetToken' => ['email'], - ]; - } - - public function beforeSave($insert) - { - if (parent::beforeSave($insert)) { - if (($this->isNewRecord || $this->getScenario() === 'resetPassword') && !empty($this->password)) { - $this->password_hash = Security::generatePasswordHash($this->password); - } - if ($this->isNewRecord) { - $this->auth_key = Security::generateRandomKey(); - } - return true; - } - return false; - } } diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/forms/LoginForm.php similarity index 94% rename from apps/advanced/common/models/LoginForm.php rename to apps/advanced/common/models/forms/LoginForm.php index 38888d9..c69050f 100644 --- a/apps/advanced/common/models/LoginForm.php +++ b/apps/advanced/common/models/forms/LoginForm.php @@ -1,12 +1,12 @@ <?php +namespace common\models\forms; -namespace common\models; - -use Yii; +use common\models\User; use yii\base\Model; +use Yii; /** - * LoginForm is the model behind the login form. + * Login form */ class LoginForm extends Model { @@ -17,7 +17,7 @@ class LoginForm extends Model private $_user = false; /** - * @return array the validation rules. + * @inheritdoc */ public function rules() { diff --git a/apps/advanced/common/models/forms/PasswordResetRequestForm.php b/apps/advanced/common/models/forms/PasswordResetRequestForm.php new file mode 100644 index 0000000..552445b --- /dev/null +++ b/apps/advanced/common/models/forms/PasswordResetRequestForm.php @@ -0,0 +1,55 @@ +<?php +namespace common\models\forms; + +use common\models\User; +use yii\base\Model; +use yii\helpers\Security; + +/** + * Password reset request form + */ +class PasswordResetRequestForm extends Model +{ + public $email; + + /** + * @inheritdoc + */ + public function rules() + { + return [ + ['email', 'filter', 'filter' => 'trim'], + ['email', 'required'], + ['email', 'email'], + ['email', 'exist', 'targetClass' => 'User', 'message' => 'There is no user with such email.'], + ]; + } + + /** + * + * @return boolean sends an email + */ + public function sendEmail() + { + $user = User::find([ + 'status' => User::STATUS_ACTIVE, + 'email' => $this->email, + ]); + + if (!$user) { + return false; + } + + $user->password_reset_token = Security::generateRandomKey(); + if ($user->save()) { + return \Yii::$app->mail->compose('passwordResetToken', ['user' => $user]) + ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot']) + ->setTo($this->email) + ->setSubject('Password reset for ' . \Yii::$app->name) + ->send(); + } + + return false; + } +} + \ No newline at end of file diff --git a/apps/advanced/common/models/forms/ResetPasswordForm.php b/apps/advanced/common/models/forms/ResetPasswordForm.php new file mode 100644 index 0000000..b6ad043 --- /dev/null +++ b/apps/advanced/common/models/forms/ResetPasswordForm.php @@ -0,0 +1,69 @@ +<?php +namespace common\models\forms; + +use common\models\User; +use yii\base\InvalidParamException; +use yii\base\Model; +use yii\helpers\Security; +use Yii; + +/** + * Password reset form + */ +class ResetPasswordForm extends Model +{ + public $password; + + /** + * @var \common\models\User + */ + private $_user; + + /** + * Creates a form model given a token + * + * @param string $token + * @throws \yii\base\InvalidParamException if token is empty or not valid + */ + public function __construct($token) + { + if (empty($token) || !is_string($token)) { + throw new InvalidParamException('Password reset token cannot be blank.'); + } + $this->_user = User::find([ + 'password_reset_token' => $token, + 'status' => User::STATUS_ACTIVE, + ]); + if (!$this->_user) { + throw new InvalidParamException('Wrong password reset token.'); + } + } + + /** + * @return array the validation rules. + */ + public function rules() + { + return [ + ['password', 'required'], + ['password', 'string', 'min' => 6], + ]; + } + + /** + * Resets password. + * @return boolean if password was reset. + */ + public function resetPassword() + { + $user = $this->_user; + if ($user->validate()) { + $user->password_hash = Security::generatePasswordHash($this->password); + $user->password_reset_token = ''; + return $user->save(); + } else { + return false; + } + } +} + \ No newline at end of file diff --git a/apps/advanced/common/models/forms/SignupForm.php b/apps/advanced/common/models/forms/SignupForm.php new file mode 100644 index 0000000..ef3ad79 --- /dev/null +++ b/apps/advanced/common/models/forms/SignupForm.php @@ -0,0 +1,59 @@ +<?php +namespace common\models\forms; + +use common\models\User; +use yii\base\Model; +use yii\helpers\Security; +use Yii; + +/** + * Signup form + */ +class SignupForm extends Model +{ + public $username; + public $email; + public $password; + + /** + * @inheritdoc + */ + public function rules() + { + return [ + ['username', 'filter', 'filter' => 'trim'], + ['username', 'required'], + ['username', 'string', 'min' => 2, 'max' => 255], + + ['email', 'filter', 'filter' => 'trim'], + ['email', 'required'], + ['email', 'email'], + ['email', 'unique', 'targetClass' => 'User', 'message' => 'This email address has already been taken.'], + + ['password', 'required'], + ['password', 'string', 'min' => 6], + ]; + } + + /** + * Signs user up. + * @return User saved model + */ + public function signup() + { + if ($this->validate()) { + $user = new User(); + $user->username = $this->username; + $user->email = $this->email; + $user->password_hash = Security::generatePasswordHash($this->password); + $user->auth_key = Security::generateRandomKey(); + $user->role = User::ROLE_USER; + $user->status = USer::STATUS_ACTIVE; + if ($user->save()) { + return $user; + } + } + return null; + } +} + \ No newline at end of file diff --git a/apps/advanced/frontend/controllers/SiteController.php b/apps/advanced/frontend/controllers/SiteController.php index 649d1f3..2f45db5 100644 --- a/apps/advanced/frontend/controllers/SiteController.php +++ b/apps/advanced/frontend/controllers/SiteController.php @@ -1,17 +1,24 @@ <?php - namespace frontend\controllers; -use Yii; -use yii\web\Controller; -use common\models\LoginForm; +use common\models\forms\LoginForm; +use common\models\forms\PasswordResetRequestForm; +use common\models\forms\ResetPasswordForm; +use common\models\forms\SignupForm; use frontend\models\ContactForm; -use common\models\User; +use yii\base\InvalidParamException; use yii\web\BadRequestHttpException; -use yii\helpers\Security; +use yii\web\Controller; +use Yii; +/** + * Site controller + */ class SiteController extends Controller { + /** + * @inheritdoc + */ public function behaviors() { return [ @@ -34,6 +41,9 @@ class SiteController extends Controller ]; } + /** + * @inheritdoc + */ public function actions() { return [ @@ -59,7 +69,7 @@ class SiteController extends Controller } $model = new LoginForm(); - if ($model->load($_POST) && $model->login()) { + if ($model->load(Yii::$app->request->post()) && $model->login()) { return $this->goBack(); } else { return $this->render('login', [ @@ -94,11 +104,13 @@ class SiteController extends Controller public function actionSignup() { - $model = new User(); - $model->setScenario('signup'); - if ($model->load($_POST) && $model->save()) { - if (Yii::$app->getUser()->login($model)) { - return $this->goHome(); + $model = new SignupForm(); + if ($model->load(Yii::$app->request->post())) { + $user = $model->signup(); + if ($user) { + if (Yii::$app->getUser()->login($user)) { + return $this->goHome(); + } } } @@ -109,16 +121,14 @@ class SiteController extends Controller public function actionRequestPasswordReset() { - $model = new User(); - $model->scenario = 'requestPasswordResetToken'; - if ($model->load($_POST) && $model->validate()) { - if ($this->sendPasswordResetEmail($model->email)) { - Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.'); - return $this->goHome(); - } else { - Yii::$app->getSession()->setFlash('error', 'There was an error sending email.'); - } + $model = new PasswordResetRequestForm(); + if ($model->load(Yii::$app->request->post()) && $model->sendEmail()) { + Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.'); + return $this->goHome(); + } else { + Yii::$app->getSession()->setFlash('error', 'There was an error sending email.'); } + return $this->render('requestPasswordResetToken', [ 'model' => $model, ]); @@ -126,21 +136,13 @@ class SiteController extends Controller public function actionResetPassword($token) { - if (empty($token) || is_array($token)) { - throw new BadRequestHttpException('Invalid password reset token.'); - } - - $model = User::find([ - 'password_reset_token' => $token, - 'status' => User::STATUS_ACTIVE, - ]); - - if ($model === null) { - throw new BadRequestHttpException('Wrong password reset token.'); + try { + $model = new ResetPasswordForm($token); + } catch (InvalidParamException $e) { + throw new BadRequestHttpException($e->getMessage()); } - $model->scenario = 'resetPassword'; - if ($model->load($_POST) && $model->save()) { + if ($model->load($_POST) && $model->resetPassword()) { Yii::$app->getSession()->setFlash('success', 'New password was saved.'); return $this->goHome(); } @@ -149,27 +151,4 @@ class SiteController extends Controller 'model' => $model, ]); } - - private function sendPasswordResetEmail($email) - { - $user = User::find([ - 'status' => User::STATUS_ACTIVE, - 'email' => $email, - ]); - - if (!$user) { - return false; - } - - $user->password_reset_token = Security::generateRandomKey(); - if ($user->save(false)) { - return \Yii::$app->mail->compose('passwordResetToken', ['user' => $user]) - ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot']) - ->setTo($email) - ->setSubject('Password reset for ' . \Yii::$app->name) - ->send(); - } - - return false; - } } diff --git a/apps/advanced/frontend/views/site/login.php b/apps/advanced/frontend/views/site/login.php index 635b9ae..4892065 100644 --- a/apps/advanced/frontend/views/site/login.php +++ b/apps/advanced/frontend/views/site/login.php @@ -5,7 +5,7 @@ use yii\widgets\ActiveForm; /** * @var yii\web\View $this * @var yii\widgets\ActiveForm $form - * @var common\models\LoginForm $model + * @var common\models\forms\LoginForm $model */ $this->title = 'Login'; $this->params['breadcrumbs'][] = $this->title; diff --git a/apps/advanced/frontend/views/site/requestPasswordResetToken.php b/apps/advanced/frontend/views/site/requestPasswordResetToken.php index bb13a5f..9cbddf5 100644 --- a/apps/advanced/frontend/views/site/requestPasswordResetToken.php +++ b/apps/advanced/frontend/views/site/requestPasswordResetToken.php @@ -5,7 +5,7 @@ use yii\widgets\ActiveForm; /** * @var yii\web\View $this * @var yii\widgets\ActiveForm $form - * @var common\models\User $model + * @var common\models\forms\PasswordResetRequestForm $model */ $this->title = 'Request password reset'; $this->params['breadcrumbs'][] = $this->title; diff --git a/apps/advanced/frontend/views/site/resetPassword.php b/apps/advanced/frontend/views/site/resetPassword.php index ec9f949..b2b8f33 100644 --- a/apps/advanced/frontend/views/site/resetPassword.php +++ b/apps/advanced/frontend/views/site/resetPassword.php @@ -5,7 +5,7 @@ use yii\widgets\ActiveForm; /** * @var yii\web\View $this * @var yii\widgets\ActiveForm $form - * @var common\models\User $model + * @var common\models\forms\ResetPasswordForm $model */ $this->title = 'Reset password'; $this->params['breadcrumbs'][] = $this->title; diff --git a/apps/advanced/frontend/views/site/signup.php b/apps/advanced/frontend/views/site/signup.php index 3bb57fc..c45f378 100644 --- a/apps/advanced/frontend/views/site/signup.php +++ b/apps/advanced/frontend/views/site/signup.php @@ -5,7 +5,7 @@ use yii\widgets\ActiveForm; /** * @var yii\web\View $this * @var yii\widgets\ActiveForm $form - * @var common\models\User $model + * @var common\models\forms\SignupForm $model */ $this->title = 'Signup'; $this->params['breadcrumbs'][] = $this->title;