├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_REPLY_TEMPLATE.md ├── support.yml └── CONTRIBUTING.md ├── migrations ├── m160929_103127_add_last_login_at_to_user_table.php ├── m151218_234654_add_timezone_to_profile.php ├── m140830_171933_fix_ip_field.php ├── m140830_172703_change_account_table_name.php ├── m140504_130429_create_token_table.php ├── m140403_174025_create_account_table.php ├── m141222_135246_alter_username_length.php ├── m150623_212711_fix_username_notnull.php ├── m150614_103145_update_social_account_table.php ├── m141222_110026_update_ip_field.php ├── m140504_113157_update_tables.php ├── Migration.php └── m140209_132017_init.php ├── views ├── message.php ├── mail │ ├── layouts │ │ ├── text.php │ │ └── html.php │ ├── text │ │ ├── new_password.php │ │ ├── confirmation.php │ │ ├── reconfirmation.php │ │ ├── recovery.php │ │ └── welcome.php │ ├── new_password.php │ ├── confirmation.php │ ├── recovery.php │ ├── reconfirmation.php │ └── welcome.php ├── admin │ ├── _user.php │ ├── _assignments.php │ ├── _account.php │ ├── _profile.php │ ├── _info.php │ ├── _menu.php │ ├── create.php │ ├── update.php │ └── index.php ├── settings │ ├── _menu.php │ ├── networks.php │ ├── profile.php │ └── account.php ├── _alert.php ├── registration │ ├── resend.php │ ├── register.php │ └── connect.php ├── recovery │ ├── reset.php │ └── request.php ├── profile │ └── show.php └── security │ └── login.php ├── traits ├── ModuleTrait.php ├── AjaxValidationTrait.php └── EventTrait.php ├── codeception.yml ├── clients ├── ClientInterface.php ├── Facebook.php ├── LinkedIn.php ├── GitHub.php ├── Twitter.php ├── VKontakte.php ├── Yandex.php └── Google.php ├── widgets ├── Login.php ├── UserMenu.php ├── views │ └── login.php └── Connect.php ├── events ├── FormEvent.php ├── UserEvent.php ├── ProfileEvent.php ├── ConnectEvent.php ├── ResetPasswordEvent.php └── AuthEvent.php ├── LICENSE.md ├── messages └── message.php ├── filters ├── FrontendFilter.php ├── BackendFilter.php └── AccessRule.php ├── helpers ├── Timezone.php └── Password.php ├── composer.json ├── models ├── query │ └── AccountQuery.php ├── ResendForm.php ├── UserSearch.php ├── Token.php ├── RegistrationForm.php ├── RecoveryForm.php ├── Profile.php ├── LoginForm.php ├── Account.php └── SettingsForm.php ├── commands ├── ConfirmController.php ├── PasswordController.php ├── DeleteController.php └── CreateController.php ├── README.md ├── controllers ├── ProfileController.php └── RecoveryController.php ├── UPGRADE.md ├── Module.php ├── Bootstrap.php └── Finder.php /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### ATTENTION: THIS PROJECT HAS BEEN ABANDONED 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | | Q | A 2 | | ------------- | --- 3 | | Is bugfix? | yes/no 4 | | New feature? | yes/no 5 | | Breaks BC? | yes/no 6 | | Fixed issues | comma-separated list of tickets # fixed by the PR, if any -------------------------------------------------------------------------------- /.github/ISSUE_REPLY_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | This project is not being actively maintained and there is no one officially offering support or help. 2 | 3 | Only PRs are being evaluated (there is no deadline for evaluation). 4 | 5 | Read more here: https://github.com/dektrium/yii2-user/issues/903 6 | -------------------------------------------------------------------------------- /migrations/m160929_103127_add_last_login_at_to_user_table.php: -------------------------------------------------------------------------------- 1 | addColumn('{{%user}}', 'last_login_at', $this->integer()); 10 | 11 | } 12 | 13 | public function down() 14 | { 15 | $this->dropColumn('{{%user}}', 'last_login_at'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /views/message.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var yii\web\View $this 14 | * @var dektrium\user\Module $module 15 | */ 16 | 17 | $this->title = $title; 18 | ?> 19 | 20 | render('/_alert', ['module' => $module]); 21 | -------------------------------------------------------------------------------- /views/mail/layouts/text.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var string $content main view render result 14 | */ 15 | ?> 16 | 17 | beginPage() ?> 18 | beginBody() ?> 19 | 20 | endBody() ?> 21 | endPage() ?> 22 | -------------------------------------------------------------------------------- /traits/ModuleTrait.php: -------------------------------------------------------------------------------- 1 | getModule('user'); 21 | } 22 | 23 | /** 24 | * @return string 25 | */ 26 | public static function getDb() 27 | { 28 | return \Yii::$app->getModule('user')->getDb(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /views/admin/_user.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var yii\widgets\ActiveForm $form 14 | * @var dektrium\user\models\User $user 15 | */ 16 | ?> 17 | 18 | field($user, 'email')->textInput(['maxlength' => 255]) ?> 19 | field($user, 'username')->textInput(['maxlength' => 255]) ?> 20 | field($user, 'password')->passwordInput() ?> 21 | -------------------------------------------------------------------------------- /views/mail/text/new_password.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var dektrium\user\models\User 14 | */ 15 | ?> 16 | , 17 | 18 | name) ?>. 19 | : 20 | password ?> 21 | 22 | . 23 | -------------------------------------------------------------------------------- /migrations/m151218_234654_add_timezone_to_profile.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | class m151218_234654_add_timezone_to_profile extends Migration 15 | { 16 | public function up() 17 | { 18 | $this->addColumn('{{%profile}}', 'timezone', $this->string(40)->null()); 19 | } 20 | 21 | public function down() 22 | { 23 | $this->dropcolumn('{{%profile}}', 'timezone'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /migrations/m140830_171933_fix_ip_field.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | /** 15 | * @author Dmitry Erofeev 16 | */ 17 | class m140830_171933_fix_ip_field extends Migration 18 | { 19 | public function up() 20 | { 21 | $this->alterColumn('{{%user}}', 'registration_ip', $this->bigInteger()); 22 | } 23 | 24 | public function down() 25 | { 26 | $this->alterColumn('{{%user}}', 'registration_ip', $this->integer()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /migrations/m140830_172703_change_account_table_name.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | /** 15 | * @author Dmitry Erofeev 16 | */ 17 | class m140830_172703_change_account_table_name extends Migration 18 | { 19 | public function up() 20 | { 21 | $this->renameTable('{{%account}}', '{{%social_account}}'); 22 | } 23 | 24 | public function down() 25 | { 26 | $this->renameTable('{{%social_account}}', '{{%account}}'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /codeception.yml: -------------------------------------------------------------------------------- 1 | actor: Tester 2 | paths: 3 | tests: tests 4 | log: tests/_output 5 | data: tests/_data 6 | helpers: tests/_support 7 | settings: 8 | bootstrap: _bootstrap.php 9 | colors: true 10 | memory_limit: 1024M 11 | modules: 12 | config: 13 | Yii2: 14 | configFile: 'tests/_app/config/test.php' 15 | coverage: 16 | enabled: true 17 | include: 18 | - ../clients/* 19 | - ../controllers/* 20 | - ../events/* 21 | - ../filters/* 22 | - ../helpers/* 23 | - ../models/* 24 | - ../traits/* 25 | - ../views/* 26 | - ../widgets/* 27 | - ../Bootstrap.php 28 | - ../Module.php 29 | - ../Mailer.php 30 | - ../Finder.php -------------------------------------------------------------------------------- /clients/ClientInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use yii\authclient\ClientInterface as BaseInterface; 15 | 16 | /** 17 | * Enhances default yii client interface by adding methods that can be used to 18 | * get user's email and username. 19 | * 20 | * @author Dmitry Erofeev 21 | */ 22 | interface ClientInterface extends BaseInterface 23 | { 24 | /** @return string|null User's email */ 25 | public function getEmail(); 26 | 27 | /** @return string|null User's username */ 28 | public function getUsername(); 29 | } 30 | -------------------------------------------------------------------------------- /widgets/Login.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\widgets; 13 | 14 | use dektrium\user\models\LoginForm; 15 | use yii\base\Widget; 16 | 17 | /** 18 | * Login for widget. 19 | * 20 | * @author Dmitry Erofeev 21 | */ 22 | class Login extends Widget 23 | { 24 | /** 25 | * @var bool 26 | */ 27 | public $validate = true; 28 | 29 | /** 30 | * @inheritdoc 31 | */ 32 | public function run() 33 | { 34 | return $this->render('login', [ 35 | 'model' => \Yii::createObject(LoginForm::className()), 36 | ]); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /views/mail/text/confirmation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var dektrium\user\models\User $user 14 | * @var dektrium\user\models\Token $token 15 | */ 16 | ?> 17 | , 18 | 19 | name) ?>. 20 | . 21 | 22 | url ?> 23 | 24 | . 25 | 26 | . 27 | -------------------------------------------------------------------------------- /clients/Facebook.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use yii\authclient\clients\Facebook as BaseFacebook; 15 | 16 | /** 17 | * @author Dmitry Erofeev 18 | */ 19 | class Facebook extends BaseFacebook implements ClientInterface 20 | { 21 | /** @inheritdoc */ 22 | public function getEmail() 23 | { 24 | return isset($this->getUserAttributes()['email']) 25 | ? $this->getUserAttributes()['email'] 26 | : null; 27 | } 28 | 29 | /** @inheritdoc */ 30 | public function getUsername() 31 | { 32 | return; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /clients/LinkedIn.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use yii\authclient\clients\LinkedIn as BaseLinkedIn; 15 | 16 | /** 17 | * @author Sam Mousa 18 | */ 19 | class LinkedIn extends BaseLinkedIn implements ClientInterface 20 | { 21 | /** @inheritdoc */ 22 | public function getEmail() 23 | { 24 | return isset($this->getUserAttributes()['email-address']) 25 | ? $this->getUserAttributes()['email-address'] 26 | : null; 27 | } 28 | 29 | /** @inheritdoc */ 30 | public function getUsername() 31 | { 32 | return; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /views/admin/_assignments.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\rbac\widgets\Assignments; 13 | 14 | /** 15 | * @var yii\web\View $this 16 | * @var dektrium\user\models\User $user 17 | */ 18 | ?> 19 | 20 | beginContent('@dektrium/user/views/admin/update.php', ['user' => $user]) ?> 21 | 22 | [ 24 | 'class' => 'alert-info alert-dismissible', 25 | ], 26 | 'body' => Yii::t('user', 'You can assign multiple roles or permissions to user by using the form below'), 27 | ]) ?> 28 | 29 | $user->id]) ?> 30 | 31 | endContent() ?> 32 | -------------------------------------------------------------------------------- /views/mail/text/reconfirmation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var dektrium\user\models\Token $token 14 | */ 15 | ?> 16 | , 17 | 18 | name 22 | ) ?>. 23 | . 24 | 25 | url ?> 26 | 27 | . 28 | 29 | . 30 | -------------------------------------------------------------------------------- /views/mail/text/recovery.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var dektrium\user\models\User $user 14 | * @var dektrium\user\models\Token $token 15 | */ 16 | ?> 17 | , 18 | 19 | name) ?>. 20 | . 21 | 22 | url ?> 23 | 24 | . 25 | 26 | . 27 | -------------------------------------------------------------------------------- /events/FormEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\events; 13 | 14 | use yii\base\Event; 15 | use yii\base\Model; 16 | 17 | /** 18 | * @property Model $model 19 | * @author Dmitry Erofeev 20 | */ 21 | class FormEvent extends Event 22 | { 23 | /** 24 | * @var Model 25 | */ 26 | private $_form; 27 | 28 | /** 29 | * @return Model 30 | */ 31 | public function getForm() 32 | { 33 | return $this->_form; 34 | } 35 | 36 | /** 37 | * @param Model $form 38 | */ 39 | public function setForm(Model $form) 40 | { 41 | $this->_form = $form; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /events/UserEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\events; 13 | 14 | use dektrium\user\models\User; 15 | use yii\base\Event; 16 | 17 | /** 18 | * @property User $model 19 | * @author Dmitry Erofeev 20 | */ 21 | class UserEvent extends Event 22 | { 23 | /** 24 | * @var User 25 | */ 26 | private $_user; 27 | 28 | /** 29 | * @return User 30 | */ 31 | public function getUser() 32 | { 33 | return $this->_user; 34 | } 35 | 36 | /** 37 | * @param User $form 38 | */ 39 | public function setUser(User $form) 40 | { 41 | $this->_user = $form; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.github/support.yml: -------------------------------------------------------------------------------- 1 | # Configuration for support-requests - https://github.com/dessant/support-requests 2 | 3 | # Label used to mark issues as support requests 4 | supportLabel: support 5 | 6 | # Comment to post on issues marked as support requests, `{issue-author}` is an 7 | # optional placeholder. Set to `false` to disable 8 | supportComment: > 9 | :wave: @{issue-author}, this project is not being actively maintained and there is no one officially offering support or help. 10 | 11 | Only PRs are being evaluated (there is no deadline for evaluation). 12 | 13 | Read more here: https://github.com/dektrium/yii2-user/issues/903 14 | 15 | # Close issues marked as support requests 16 | close: true 17 | 18 | # Lock issues marked as support requests 19 | lock: false 20 | 21 | # Assign `off-topic` as the reason for locking. Set to `false` to disable 22 | setLockReason: true 23 | 24 | # Repository to extend settings from 25 | # _extends: repo 26 | -------------------------------------------------------------------------------- /events/ProfileEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\events; 13 | 14 | use dektrium\user\models\Profile; 15 | use yii\base\Event; 16 | 17 | /** 18 | * @property Profile $model 19 | * @author Dmitry Erofeev 20 | */ 21 | class ProfileEvent extends Event 22 | { 23 | /** 24 | * @var Profile 25 | */ 26 | private $_profile; 27 | 28 | /** 29 | * @return Profile 30 | */ 31 | public function getProfile() 32 | { 33 | return $this->_profile; 34 | } 35 | 36 | /** 37 | * @param Profile $form 38 | */ 39 | public function setProfile(Profile $form) 40 | { 41 | $this->_profile = $form; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /views/settings/_menu.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use dektrium\user\widgets\UserMenu; 14 | 15 | /** 16 | * @var dektrium\user\models\User $user 17 | */ 18 | 19 | $user = Yii::$app->user->identity; 20 | ?> 21 |
22 |
23 |

24 | profile->getAvatarUrl(24), [ 25 | 'class' => 'img-rounded', 26 | 'alt' => $user->username, 27 | ]) ?> 28 | username ?> 29 |

30 |
31 |
32 | 33 |
34 |
35 | -------------------------------------------------------------------------------- /clients/GitHub.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use yii\authclient\clients\GitHub as BaseGitHub; 15 | 16 | /** 17 | * @author Dmitry Erofeev 18 | */ 19 | class GitHub extends BaseGitHub implements ClientInterface 20 | { 21 | /** @inheritdoc */ 22 | public function getEmail() 23 | { 24 | return isset($this->getUserAttributes()['email']) 25 | ? $this->getUserAttributes()['email'] 26 | : null; 27 | } 28 | 29 | /** @inheritdoc */ 30 | public function getUsername() 31 | { 32 | return isset($this->getUserAttributes()['login']) 33 | ? $this->getUserAttributes()['login'] 34 | : null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /views/_alert.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\bootstrap\Alert; 13 | 14 | /** 15 | * @var dektrium\user\Module $module 16 | */ 17 | ?> 18 | 19 | enableFlashMessages): ?> 20 |
21 |
22 | session->getAllFlashes() as $type => $message): ?> 23 | 24 | ['class' => 'alert-dismissible alert-' . $type], 26 | 'body' => $message 27 | ]) ?> 28 | 29 | 30 |
31 |
32 | 33 | -------------------------------------------------------------------------------- /views/mail/text/welcome.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var dektrium\user\models\User 14 | */ 15 | ?> 16 | , 17 | 18 | name) ?>. 19 | enableGeneratingPassword): ?> 20 | : 21 | password ?> 22 | 23 | 24 | 25 | . 26 | 27 | url ?> 28 | 29 | . 30 | 31 | 32 | . 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2016 Dektrium project 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /messages/message.php: -------------------------------------------------------------------------------- 1 | __DIR__ . '/../', 5 | 'messagePath' => __DIR__, 6 | 'languages' => [ 7 | 'ca', 8 | 'da', 9 | 'de', 10 | 'de-DU', 11 | 'es', 12 | 'fa-IR', 13 | 'fi', 14 | 'fr', 15 | 'hr', 16 | 'hu', 17 | 'it', 18 | 'ko-KR', 19 | 'kz', 20 | 'lt', 21 | 'nl', 22 | 'pl', 23 | 'pt-BR', 24 | 'pt-PT', 25 | 'ro', 26 | 'ru', 27 | 'th', 28 | 'tr_TR', 29 | 'uk', 30 | 'vi', 31 | 'zh-CN', 32 | 'zh-TW', 33 | ], 34 | 'translator' => 'Yii::t', 35 | 'sort' => false, 36 | 'overwrite' => true, 37 | 'removeUnused' => false, 38 | 'only' => ['*.php'], 39 | 'except' => [ 40 | '.svn', 41 | '.git', 42 | '.gitignore', 43 | '.gitkeep', 44 | '.hgignore', 45 | '.hgkeep', 46 | '/messages', 47 | '/tests', 48 | '/vendor', 49 | ], 50 | 'format' => 'php', 51 | ]; 52 | -------------------------------------------------------------------------------- /traits/AjaxValidationTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\traits; 13 | 14 | use yii\base\Model; 15 | use yii\web\Response; 16 | use yii\widgets\ActiveForm; 17 | 18 | /** 19 | * @author Dmitry Erofeev 20 | */ 21 | trait AjaxValidationTrait 22 | { 23 | /** 24 | * Performs ajax validation. 25 | * 26 | * @param Model $model 27 | * 28 | * @throws \yii\base\ExitException 29 | */ 30 | protected function performAjaxValidation(Model $model) 31 | { 32 | if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) { 33 | \Yii::$app->response->format = Response::FORMAT_JSON; 34 | \Yii::$app->response->data = ActiveForm::validate($model); 35 | \Yii::$app->response->send(); 36 | \Yii::$app->end(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /clients/Twitter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use yii\authclient\clients\Twitter as BaseTwitter; 15 | use yii\helpers\ArrayHelper; 16 | 17 | /** 18 | * @author Dmitry Erofeev 19 | */ 20 | class Twitter extends BaseTwitter implements ClientInterface 21 | { 22 | /** 23 | * @return string 24 | */ 25 | public function getUsername() 26 | { 27 | return ArrayHelper::getValue($this->getUserAttributes(), 'screen_name'); 28 | } 29 | 30 | /** 31 | * @return string|null User's email, Twitter does not provide user's email address 32 | * unless elevated permissions have been granted 33 | * https://dev.twitter.com/rest/reference/get/account/verify_credentials 34 | */ 35 | public function getEmail() 36 | { 37 | return ArrayHelper::getValue($this->getUserAttributes(), 'email'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /clients/VKontakte.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use Yii; 15 | use yii\authclient\clients\VKontakte as BaseVKontakte; 16 | 17 | /** 18 | * @author Dmitry Erofeev 19 | */ 20 | class VKontakte extends BaseVKontakte implements ClientInterface 21 | { 22 | /** @inheritdoc */ 23 | public $scope = 'email'; 24 | 25 | /** @inheritdoc */ 26 | public function getEmail() 27 | { 28 | return $this->getAccessToken()->getParam('email'); 29 | } 30 | 31 | /** @inheritdoc */ 32 | public function getUsername() 33 | { 34 | return isset($this->getUserAttributes()['screen_name']) 35 | ? $this->getUserAttributes()['screen_name'] 36 | : null; 37 | } 38 | 39 | /** @inheritdoc */ 40 | protected function defaultTitle() 41 | { 42 | return Yii::t('user', 'VKontakte'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /filters/FrontendFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\filters; 13 | 14 | use yii\base\ActionFilter; 15 | use yii\web\NotFoundHttpException; 16 | 17 | /** 18 | * FrontendFilter is used to restrict access to admin controller in frontend when using Yii2-user with Yii2 19 | * advanced template. 20 | * 21 | * @author Dmitry Erofeev 22 | */ 23 | class FrontendFilter extends ActionFilter 24 | { 25 | /** 26 | * @var array 27 | */ 28 | public $controllers = ['admin']; 29 | 30 | /** 31 | * @param \yii\base\Action $action 32 | * 33 | * @return bool 34 | * @throws \yii\web\NotFoundHttpException 35 | */ 36 | public function beforeAction($action) 37 | { 38 | if (in_array($action->controller->id, $this->controllers)) { 39 | throw new NotFoundHttpException('Not found'); 40 | } 41 | 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /filters/BackendFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\filters; 13 | 14 | use yii\web\NotFoundHttpException; 15 | use yii\base\ActionFilter; 16 | 17 | /** 18 | * BackendFilter is used to allow access only to admin and security controller in frontend when using Yii2-user with 19 | * Yii2 advanced template. 20 | * 21 | * @author Dmitry Erofeev 22 | */ 23 | class BackendFilter extends ActionFilter 24 | { 25 | /** 26 | * @var array 27 | */ 28 | public $controllers = ['profile', 'recovery', 'registration', 'settings']; 29 | 30 | /** 31 | * @param \yii\base\Action $action 32 | * 33 | * @return bool 34 | * @throws \yii\web\NotFoundHttpException 35 | */ 36 | public function beforeAction($action) 37 | { 38 | if (in_array($action->controller->id, $this->controllers)) { 39 | throw new NotFoundHttpException('Not found'); 40 | } 41 | 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /migrations/m140504_130429_create_token_table.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | /** 15 | * @author Dmitry Erofeev 16 | */ 17 | class m140504_130429_create_token_table extends Migration 18 | { 19 | public function up() 20 | { 21 | $this->createTable('{{%token}}', [ 22 | 'user_id' => $this->integer()->notNull(), 23 | 'code' => $this->string(32)->notNull(), 24 | 'created_at' => $this->integer()->notNull(), 25 | 'type' => $this->smallInteger()->notNull(), 26 | ], $this->tableOptions); 27 | 28 | $this->createIndex('{{%token_unique}}', '{{%token}}', ['user_id', 'code', 'type'], true); 29 | $this->addForeignKey('{{%fk_user_token}}', '{{%token}}', 'user_id', '{{%user}}', 'id', $this->cascade, $this->restrict); 30 | } 31 | 32 | public function down() 33 | { 34 | $this->dropTable('{{%token}}'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /views/admin/_account.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\bootstrap\ActiveForm; 13 | use yii\helpers\Html; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var dektrium\user\models\User $user 18 | */ 19 | ?> 20 | 21 | beginContent('@dektrium/user/views/admin/update.php', ['user' => $user]) ?> 22 | 23 | 'horizontal', 25 | 'enableAjaxValidation' => true, 26 | 'enableClientValidation' => false, 27 | 'fieldConfig' => [ 28 | 'horizontalCssClasses' => [ 29 | 'wrapper' => 'col-sm-9', 30 | ], 31 | ], 32 | ]); ?> 33 | 34 | render('_user', ['form' => $form, 'user' => $user]) ?> 35 | 36 |
37 |
38 | 'btn btn-block btn-success']) ?> 39 |
40 |
41 | 42 | 43 | 44 | endContent() ?> 45 | -------------------------------------------------------------------------------- /migrations/m140403_174025_create_account_table.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | /** 15 | * @author Dmitry Erofeev createTable('{{%account}}', [ 22 | 'id' => $this->primaryKey(), 23 | 'user_id' => $this->integer()->null(), 24 | 'provider' => $this->string()->notNull(), 25 | 'client_id' => $this->string()->notNull(), 26 | 'properties' => $this->text()->null(), 27 | ], $this->tableOptions); 28 | 29 | $this->createIndex('{{%account_unique}}', '{{%account}}', ['provider', 'client_id'], true); 30 | $this->addForeignKey('{{%fk_user_account}}', '{{%account}}', 'user_id', '{{%user}}', 'id', $this->cascade, $this->restrict); 31 | } 32 | 33 | public function down() 34 | { 35 | $this->dropTable('{{%account}}'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /clients/Yandex.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use Yii; 15 | use yii\authclient\clients\Yandex as BaseYandex; 16 | 17 | /** 18 | * @author Dmitry Erofeev 19 | */ 20 | class Yandex extends BaseYandex implements ClientInterface 21 | { 22 | /** @inheritdoc */ 23 | public function getEmail() 24 | { 25 | $emails = isset($this->getUserAttributes()['emails']) 26 | ? $this->getUserAttributes()['emails'] 27 | : null; 28 | 29 | if ($emails !== null && isset($emails[0])) { 30 | return $emails[0]; 31 | } else { 32 | return null; 33 | } 34 | } 35 | 36 | /** @inheritdoc */ 37 | public function getUsername() 38 | { 39 | return isset($this->getUserAttributes()['login']) 40 | ? $this->getUserAttributes()['login'] 41 | : null; 42 | } 43 | 44 | /** @inheritdoc */ 45 | protected function defaultTitle() 46 | { 47 | return Yii::t('user', 'Yandex'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /clients/Google.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\clients; 13 | 14 | use yii\authclient\clients\Google as BaseGoogle; 15 | 16 | /** 17 | * @author Dmitry Erofeev 18 | */ 19 | class Google extends BaseGoogle implements ClientInterface 20 | { 21 | /** 22 | * @var string Hosted domain (hd) parameter sent to Google 23 | */ 24 | public $hostedDomain; 25 | 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | public function buildAuthUrl(array $params = []) 30 | { 31 | if ($this->hostedDomain) { 32 | $params['hd'] = $this->hostedDomain; 33 | } 34 | 35 | return parent::buildAuthUrl($params); 36 | } 37 | 38 | /** @inheritdoc */ 39 | public function getEmail() 40 | { 41 | return isset($this->getUserAttributes()['emails'][0]['value']) 42 | ? $this->getUserAttributes()['emails'][0]['value'] 43 | : null; 44 | } 45 | 46 | /** @inheritdoc */ 47 | public function getUsername() 48 | { 49 | return; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /helpers/Timezone.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\helpers; 13 | 14 | /** 15 | * Timezone helper. 16 | * 17 | * @author Dmitry Erofeev 18 | */ 19 | class Timezone 20 | { 21 | 22 | /** 23 | * Get all of the time zones with the offsets sorted by their offset 24 | * 25 | * @return array 26 | */ 27 | public static function getAll() 28 | { 29 | $timeZones = []; 30 | $timeZoneIdentifiers = \DateTimeZone::listIdentifiers(); 31 | 32 | foreach ($timeZoneIdentifiers as $timeZone) { 33 | $date = new \DateTime('now', new \DateTimeZone($timeZone)); 34 | $offset = $date->getOffset(); 35 | $tz = ($offset > 0 ? '+' : '-') . gmdate('H:i', abs($offset)); 36 | $timeZones[] = [ 37 | 'timezone' => $timeZone, 38 | 'name' => "{$timeZone} (UTC {$tz})", 39 | 'offset' => $offset 40 | ]; 41 | } 42 | 43 | \yii\helpers\ArrayHelper::multisort($timeZones, 'offset', SORT_DESC, SORT_NUMERIC); 44 | 45 | return $timeZones; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /views/mail/new_password.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | 14 | /** 15 | * @var dektrium\user\Module $module 16 | * @var dektrium\user\models\User $user 17 | * @var dektrium\user\models\Password $password 18 | */ 19 | 20 | ?> 21 |

22 | , 23 |

24 | 25 |

26 | name) ?>. 27 | : password ?> 28 |

29 | 30 |

31 | . 32 |

33 | -------------------------------------------------------------------------------- /events/ConnectEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\events; 13 | 14 | use dektrium\user\models\User; 15 | use dektrium\user\models\Account; 16 | use yii\base\Event; 17 | 18 | /** 19 | * @property User $model 20 | * @property Account $account 21 | * @author Dmitry Erofeev 22 | */ 23 | class ConnectEvent extends Event 24 | { 25 | /** 26 | * @var User 27 | */ 28 | private $_user; 29 | 30 | /** 31 | * @var Account 32 | */ 33 | private $_account; 34 | 35 | /** 36 | * @return Account 37 | */ 38 | public function getAccount() 39 | { 40 | return $this->_account; 41 | } 42 | 43 | /** 44 | * @param Account $account 45 | */ 46 | public function setAccount(Account $account) 47 | { 48 | $this->_account = $account; 49 | } 50 | 51 | /** 52 | * @return User 53 | */ 54 | public function getUser() 55 | { 56 | return $this->_user; 57 | } 58 | 59 | /** 60 | * @param User $form 61 | */ 62 | public function setUser(User $user) 63 | { 64 | $this->_user = $user; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /events/ResetPasswordEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\events; 13 | 14 | use dektrium\user\models\RecoveryForm; 15 | use dektrium\user\models\Token; 16 | use yii\base\Event; 17 | 18 | /** 19 | * @property Token $token 20 | * @property RecoveryForm $form 21 | * @author Dmitry Erofeev 22 | */ 23 | class ResetPasswordEvent extends Event 24 | { 25 | /** 26 | * @var RecoveryForm 27 | */ 28 | private $_form; 29 | 30 | /** 31 | * @var Token 32 | */ 33 | private $_token; 34 | 35 | /** 36 | * @return Token 37 | */ 38 | public function getToken() 39 | { 40 | return $this->_token; 41 | } 42 | 43 | /** 44 | * @param Token $token 45 | */ 46 | public function setToken(Token $token = null) 47 | { 48 | $this->_token = $token; 49 | } 50 | 51 | /** 52 | * @return RecoveryForm 53 | */ 54 | public function getForm() 55 | { 56 | return $this->_form; 57 | } 58 | 59 | /** 60 | * @param RecoveryForm $form 61 | */ 62 | public function setForm(RecoveryForm $form = null) 63 | { 64 | $this->_form = $form; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dektrium/yii2-user", 3 | "description": "Flexible user registration and authentication module for Yii2", 4 | "keywords": ["yii2", "yii2-user", "user management", "dektrium"], 5 | "type": "yii2-extension", 6 | "license": "MIT", 7 | "support": { 8 | "issues": "https://github.com/dektrium/yii2-user/issues?state=open", 9 | "forum": "https://gitter.im/dektrium/yii2-user", 10 | "source": "https://github.com/dektrium/yii2-user" 11 | }, 12 | "authors": [ 13 | { 14 | "name": "Dmitry Erofeev", 15 | "email": "dmeroff@gmail.com", 16 | "homepage": "http://dmeroff.ru" 17 | } 18 | ], 19 | "minimum-stability": "dev", 20 | "require": { 21 | "php": ">=5.4.0", 22 | "yiisoft/yii2": "^2.0.13", 23 | "yiisoft/yii2-swiftmailer": "^2.0.0", 24 | "yiisoft/yii2-authclient": "^2.1.0", 25 | "yiisoft/yii2-bootstrap": "^2.0.0" 26 | }, 27 | "require-dev": { 28 | "yiisoft/yii2-codeception": "^2.0.0", 29 | "codeception/specify": "^0.4.3", 30 | "codeception/verify": "^0.3.1" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "dektrium\\user\\": "" 35 | } 36 | }, 37 | "extra": { 38 | "bootstrap": "dektrium\\user\\Bootstrap", 39 | "branch-alias": { 40 | "dev-master": "0.9.x-dev", 41 | "dev-develop": "1.0.x-dev" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /filters/AccessRule.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\filters; 13 | 14 | /** 15 | * Access rule class for simpler RBAC. 16 | * @see http://yii2-user.dmeroff.ru/docs/custom-access-control 17 | * @author Dmitry Erofeev 18 | */ 19 | class AccessRule extends \yii\filters\AccessRule 20 | { 21 | /** 22 | * @inheritdoc 23 | * */ 24 | protected function matchRole($user) 25 | { 26 | if (empty($this->roles)) { 27 | return true; 28 | } 29 | 30 | foreach ($this->roles as $role) { 31 | if ($role === '?') { 32 | if (\Yii::$app->user->isGuest) { 33 | return true; 34 | } 35 | } elseif ($role === '@') { 36 | if (!\Yii::$app->user->isGuest) { 37 | return true; 38 | } 39 | } elseif ($role === 'admin') { 40 | if (!\Yii::$app->user->isGuest && \Yii::$app->user->identity->isAdmin) { 41 | return true; 42 | } 43 | } elseif ($user->can($role)) { 44 | return true; 45 | } 46 | } 47 | 48 | return false; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /events/AuthEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\events; 13 | 14 | use dektrium\user\models\Account; 15 | use yii\authclient\ClientInterface; 16 | use yii\base\Event; 17 | 18 | /** 19 | * @property Account $account 20 | * @property ClientInterface $client 21 | * @author Dmitry Erofeev 22 | */ 23 | class AuthEvent extends Event 24 | { 25 | /** 26 | * @var ClientInterface 27 | */ 28 | private $_client; 29 | 30 | /** 31 | * @var Account 32 | */ 33 | private $_account; 34 | 35 | /** 36 | * @return Account 37 | */ 38 | public function getAccount() 39 | { 40 | return $this->_account; 41 | } 42 | 43 | /** 44 | * @param Account $account 45 | */ 46 | public function setAccount(Account $account) 47 | { 48 | $this->_account = $account; 49 | } 50 | 51 | /** 52 | * @return ClientInterface 53 | */ 54 | public function getClient() 55 | { 56 | return $this->_client; 57 | } 58 | 59 | /** 60 | * @param ClientInterface $client 61 | */ 62 | public function setClient(ClientInterface $client) 63 | { 64 | $this->_client = $client; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /views/admin/_profile.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\bootstrap\ActiveForm; 13 | use yii\helpers\Html; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var dektrium\user\models\User $user 18 | * @var dektrium\user\models\Profile $profile 19 | */ 20 | ?> 21 | 22 | beginContent('@dektrium/user/views/admin/update.php', ['user' => $user]) ?> 23 | 24 | 'horizontal', 26 | 'enableAjaxValidation' => true, 27 | 'enableClientValidation' => false, 28 | 'fieldConfig' => [ 29 | 'horizontalCssClasses' => [ 30 | 'wrapper' => 'col-sm-9', 31 | ], 32 | ], 33 | ]); ?> 34 | 35 | field($profile, 'name') ?> 36 | field($profile, 'public_email') ?> 37 | field($profile, 'website') ?> 38 | field($profile, 'location') ?> 39 | field($profile, 'gravatar_email') ?> 40 | field($profile, 'bio')->textarea() ?> 41 | 42 |
43 |
44 | 'btn btn-block btn-success']) ?> 45 |
46 |
47 | 48 | 49 | 50 | endContent() ?> 51 | -------------------------------------------------------------------------------- /views/registration/resend.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use yii\widgets\ActiveForm; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var dektrium\user\models\ResendForm $model 18 | */ 19 | 20 | $this->title = Yii::t('user', 'Request new confirmation message'); 21 | $this->params['breadcrumbs'][] = $this->title; 22 | ?> 23 |
24 |
25 |
26 |
27 |

title) ?>

28 |
29 |
30 | 'resend-form', 32 | 'enableAjaxValidation' => true, 33 | 'enableClientValidation' => false, 34 | ]); ?> 35 | 36 | field($model, 'email')->textInput(['autofocus' => true]) ?> 37 | 38 | 'btn btn-primary btn-block']) ?>
39 | 40 | 41 |
42 |
43 |
44 |
45 | -------------------------------------------------------------------------------- /views/recovery/reset.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use yii\widgets\ActiveForm; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var yii\widgets\ActiveForm $form 18 | * @var dektrium\user\models\RecoveryForm $model 19 | */ 20 | 21 | $this->title = Yii::t('user', 'Reset your password'); 22 | $this->params['breadcrumbs'][] = $this->title; 23 | ?> 24 |
25 |
26 |
27 |
28 |

title) ?>

29 |
30 |
31 | 'password-recovery-form', 33 | 'enableAjaxValidation' => true, 34 | 'enableClientValidation' => false, 35 | ]); ?> 36 | 37 | field($model, 'password')->passwordInput() ?> 38 | 39 | 'btn btn-success btn-block']) ?>
40 | 41 | 42 |
43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /views/recovery/request.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use yii\widgets\ActiveForm; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var yii\widgets\ActiveForm $form 18 | * @var dektrium\user\models\RecoveryForm $model 19 | */ 20 | 21 | $this->title = Yii::t('user', 'Recover your password'); 22 | $this->params['breadcrumbs'][] = $this->title; 23 | ?> 24 |
25 |
26 |
27 |
28 |

title) ?>

29 |
30 |
31 | 'password-recovery-form', 33 | 'enableAjaxValidation' => true, 34 | 'enableClientValidation' => false, 35 | ]); ?> 36 | 37 | field($model, 'email')->textInput(['autofocus' => true]) ?> 38 | 39 | 'btn btn-primary btn-block']) ?>
40 | 41 | 42 |
43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /widgets/UserMenu.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\widgets; 13 | 14 | use yii\widgets\Menu; 15 | use Yii; 16 | use yii\base\Widget; 17 | 18 | /** 19 | * User menu widget. 20 | */ 21 | class UserMenu extends Widget 22 | { 23 | 24 | /** @array \dektrium\user\models\RegistrationForm */ 25 | public $items; 26 | 27 | public function init() 28 | { 29 | parent::init(); 30 | 31 | $networksVisible = count(Yii::$app->authClientCollection->clients) > 0; 32 | 33 | $this->items = [ 34 | ['label' => Yii::t('user', 'Profile'), 'url' => ['/user/settings/profile']], 35 | ['label' => Yii::t('user', 'Account'), 'url' => ['/user/settings/account']], 36 | [ 37 | 'label' => Yii::t('user', 'Networks'), 38 | 'url' => ['/user/settings/networks'], 39 | 'visible' => $networksVisible 40 | ], 41 | ]; 42 | } 43 | 44 | /** 45 | * @inheritdoc 46 | */ 47 | public function run() 48 | { 49 | return Menu::widget([ 50 | 'options' => [ 51 | 'class' => 'nav nav-pills nav-stacked', 52 | ], 53 | 'items' => $this->items, 54 | ]); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /migrations/m141222_135246_alter_username_length.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | class m141222_135246_alter_username_length extends Migration 15 | { 16 | public function up() 17 | { 18 | if ($this->dbType == 'sqlsrv') { 19 | $this->dropIndex('{{%user_unique_username}}', '{{%user}}'); 20 | } 21 | if ($this->dbType == 'pgsql') { 22 | $this->alterColumn('{{%user}}', 'username', 'SET NOT NULL'); 23 | } else { 24 | $this->alterColumn('{{%user}}', 'username', $this->string(255)->notNull()); 25 | } 26 | if ($this->dbType == 'sqlsrv') { 27 | $this->createIndex('{{%user_unique_username}}', '{{%user}}', 'username', true); 28 | } 29 | } 30 | 31 | public function down() 32 | { 33 | if ($this->dbType == 'sqlsrv') { 34 | $this->dropIndex('{{%user_unique_username}}', '{{%user}}'); 35 | } 36 | if ($this->dbType == 'pgsql') { 37 | $this->alterColumn('{{%user}}', 'username', 'DROP NOT NULL'); 38 | } else { 39 | $this->alterColumn('{{%user}}', 'username', $this->string(255)->notNull()); 40 | } 41 | if ($this->dbType == 'sqlsrv') { 42 | $this->createIndex('{{%user_unique_username}}', '{{%user}}', 'username', true); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /migrations/m150623_212711_fix_username_notnull.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | class m150623_212711_fix_username_notnull extends Migration 15 | { 16 | public function up() 17 | { 18 | if ($this->dbType == 'pgsql') { 19 | $this->alterColumn('{{%user}}', 'username', 'SET NOT NULL'); 20 | } else { 21 | if ($this->dbType == 'sqlsrv') { 22 | $this->dropIndex('{{%user_unique_username}}', '{{%user}}'); 23 | } 24 | $this->alterColumn('{{%user}}', 'username', $this->string(255)->notNull()); 25 | if ($this->dbType == 'sqlsrv') { 26 | $this->createIndex('{{%user_unique_username}}', '{{%user}}', 'username', true); 27 | } 28 | } 29 | } 30 | 31 | public function down() 32 | { 33 | if ($this->dbType == "pgsql") { 34 | $this->alterColumn('{{%user}}', 'username', 'DROP NOT NULL'); 35 | } else { 36 | if ($this->dbType == 'sqlsrv') { 37 | $this->dropIndex('{{%user_unique_username}}', '{{%user}}'); 38 | } 39 | $this->alterColumn('{{%user}}', 'username', $this->string(255)->null()); 40 | if ($this->dbType == 'sqlsrv') { 41 | $this->createIndex('{{%user_unique_username}}', '{{%user}}', 'username', true); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /migrations/m150614_103145_update_social_account_table.php: -------------------------------------------------------------------------------- 1 | addColumn('{{%social_account}}', 'code', $this->string(32)->null()); 11 | $this->addColumn('{{%social_account}}', 'created_at', $this->integer()->null()); 12 | $this->addColumn('{{%social_account}}', 'email', $this->string()->null()); 13 | $this->addColumn('{{%social_account}}', 'username', $this->string()->null()); 14 | $this->createIndex('{{%account_unique_code}}', '{{%social_account}}', 'code', true); 15 | 16 | $accounts = (new Query())->from('{{%social_account}}')->select('id')->all($this->db); 17 | 18 | $transaction = $this->db->beginTransaction(); 19 | try { 20 | foreach ($accounts as $account) { 21 | $this->db->createCommand()->update('{{%social_account}}', [ 22 | 'created_at' => time(), 23 | ], 'id = ' . $account['id'])->execute(); 24 | } 25 | $transaction->commit(); 26 | } catch (Exception $e) { 27 | $transaction->rollBack(); 28 | throw $e; 29 | } 30 | } 31 | 32 | public function down() 33 | { 34 | $this->dropIndex('{{%account_unique_code}}', '{{%social_account}}'); 35 | $this->dropColumn('{{%social_account}}', 'email'); 36 | $this->dropColumn('{{%social_account}}', 'username'); 37 | $this->dropColumn('{{%social_account}}', 'code'); 38 | $this->dropColumn('{{%social_account}}', 'created_at'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /widgets/views/login.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Url; 13 | use yii\widgets\ActiveForm; 14 | use yii\helpers\Html; 15 | 16 | /** 17 | * @var yii\web\View $this 18 | * @var yii\widgets\ActiveForm $form 19 | * @var dektrium\user\models\LoginForm $model 20 | * @var string $action 21 | */ 22 | 23 | ?> 24 | 25 | user->isGuest): ?> 26 | 'login-widget-form', 28 | 'action' => Url::to(['/user/security/login']), 29 | 'enableAjaxValidation' => true, 30 | 'enableClientValidation' => false, 31 | 'validateOnBlur' => false, 32 | 'validateOnType' => false, 33 | 'validateOnChange' => false, 34 | ]) ?> 35 | 36 | field($model, 'login')->textInput(['placeholder' => 'Login']) ?> 37 | 38 | field($model, 'password')->passwordInput(['placeholder' => 'Password']) ?> 39 | 40 | field($model, 'rememberMe')->checkbox() ?> 41 | 42 | 'btn btn-primary btn-block']) ?> 43 | 44 | 45 | 46 | 'btn btn-danger btn-block', 48 | 'data-method' => 'post' 49 | ]) ?> 50 | 51 | -------------------------------------------------------------------------------- /models/query/AccountQuery.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models\query; 13 | 14 | use dektrium\user\models\Account; 15 | use yii\authclient\ClientInterface; 16 | use yii\db\ActiveQuery; 17 | 18 | /** 19 | * @method Account|null one($db = null) 20 | * @method Account[] all($db = null) 21 | * 22 | * @author Dmitry Erofeev 23 | */ 24 | class AccountQuery extends ActiveQuery 25 | { 26 | /** 27 | * Finds an account by code. 28 | * @param string $code 29 | * @return AccountQuery 30 | */ 31 | public function byCode($code) 32 | { 33 | return $this->andWhere(['code' => md5($code)]); 34 | } 35 | 36 | /** 37 | * Finds an account by id. 38 | * @param integer $id 39 | * @return AccountQuery 40 | */ 41 | public function byId($id) 42 | { 43 | return $this->andWhere(['id' => $id]); 44 | } 45 | 46 | /** 47 | * Finds an account by user_id. 48 | * @param integer $userId 49 | * @return AccountQuery 50 | */ 51 | public function byUser($userId) 52 | { 53 | return $this->andWhere(['user_id' => $userId]); 54 | } 55 | 56 | /** 57 | * Finds an account by client. 58 | * @param ClientInterface $client 59 | * @return AccountQuery 60 | */ 61 | public function byClient(ClientInterface $client) 62 | { 63 | return $this->andWhere([ 64 | 'provider' => $client->getId(), 65 | 'client_id' => $client->getUserAttributes()['id'], 66 | ]); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /views/mail/confirmation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | 14 | /** 15 | * @var dektrium\user\models\User $user 16 | * @var dektrium\user\models\Token $token 17 | */ 18 | ?> 19 |

20 | , 21 |

22 |

23 | name) ?>. 24 | . 25 |

26 |

27 | url), $token->url) ?> 28 |

29 |

30 | . 31 |

32 |

33 | . 34 |

35 | -------------------------------------------------------------------------------- /views/mail/recovery.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | 14 | /** 15 | * @var dektrium\user\models\User $user 16 | * @var dektrium\user\models\Token $token 17 | */ 18 | ?> 19 |

20 | , 21 |

22 |

23 | name) ?>. 24 | . 25 |

26 |

27 | url), $token->url); ?> 28 |

29 |

30 | . 31 |

32 |

33 | . 34 |

35 | -------------------------------------------------------------------------------- /commands/ConfirmController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\commands; 13 | 14 | use dektrium\user\Finder; 15 | use Yii; 16 | use yii\console\Controller; 17 | use yii\helpers\Console; 18 | 19 | /** 20 | * Confirms a user. 21 | * 22 | * @property \dektrium\user\Module $module 23 | * 24 | * @author Dmitry Erofeev 25 | */ 26 | class ConfirmController extends Controller 27 | { 28 | /** @var Finder */ 29 | protected $finder; 30 | 31 | /** 32 | * @param string $id 33 | * @param \yii\base\Module $module 34 | * @param Finder $finder 35 | * @param array $config 36 | */ 37 | public function __construct($id, $module, Finder $finder, $config = []) 38 | { 39 | $this->finder = $finder; 40 | parent::__construct($id, $module, $config); 41 | } 42 | 43 | /** 44 | * Confirms a user by setting confirmed_at field to current time. 45 | * 46 | * @param string $search Email or username 47 | */ 48 | public function actionIndex($search) 49 | { 50 | $user = $this->finder->findUserByUsernameOrEmail($search); 51 | if ($user === null) { 52 | $this->stdout(Yii::t('user', 'User is not found') . "\n", Console::FG_RED); 53 | } else { 54 | if ($user->confirm()) { 55 | $this->stdout(Yii::t('user', 'User has been confirmed') . "\n", Console::FG_GREEN); 56 | } else { 57 | $this->stdout(Yii::t('user', 'Error occurred while confirming user') . "\n", Console::FG_RED); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /views/mail/reconfirmation.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | 14 | /** 15 | * @var dektrium\user\models\Token $token 16 | */ 17 | ?> 18 |

19 | , 20 |

21 |

22 | name 26 | ) ?>. 27 | . 28 |

29 |

30 | getUrl()), $token->getUrl()); ?> 31 |

32 |

33 | . 34 |

35 |

36 | . 37 |

38 | -------------------------------------------------------------------------------- /views/registration/register.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use yii\widgets\ActiveForm; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var dektrium\user\models\User $model 18 | * @var dektrium\user\Module $module 19 | */ 20 | 21 | $this->title = Yii::t('user', 'Sign up'); 22 | $this->params['breadcrumbs'][] = $this->title; 23 | ?> 24 |
25 |
26 |
27 |
28 |

title) ?>

29 |
30 |
31 | 'registration-form', 33 | 'enableAjaxValidation' => true, 34 | 'enableClientValidation' => false, 35 | ]); ?> 36 | 37 | field($model, 'email') ?> 38 | 39 | field($model, 'username') ?> 40 | 41 | enableGeneratingPassword == false): ?> 42 | field($model, 'password')->passwordInput() ?> 43 | 44 | 45 | 'btn btn-success btn-block']) ?> 46 | 47 | 48 |
49 |
50 |

51 | 52 |

53 |
54 |
55 | -------------------------------------------------------------------------------- /commands/PasswordController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\commands; 13 | 14 | use dektrium\user\Finder; 15 | use Yii; 16 | use yii\console\Controller; 17 | use yii\helpers\Console; 18 | 19 | /** 20 | * Updates user's password. 21 | * 22 | * @property \dektrium\user\Module $module 23 | * 24 | * @author Dmitry Erofeev 25 | */ 26 | class PasswordController extends Controller 27 | { 28 | /** @var Finder */ 29 | protected $finder; 30 | 31 | /** 32 | * @param string $id 33 | * @param \yii\base\Module $module 34 | * @param Finder $finder 35 | * @param array $config 36 | */ 37 | public function __construct($id, $module, Finder $finder, $config = []) 38 | { 39 | $this->finder = $finder; 40 | parent::__construct($id, $module, $config); 41 | } 42 | 43 | /** 44 | * Updates user's password to given. 45 | * 46 | * @param string $search Email or username 47 | * @param string $password New password 48 | */ 49 | public function actionIndex($search, $password) 50 | { 51 | $user = $this->finder->findUserByUsernameOrEmail($search); 52 | if ($user === null) { 53 | $this->stdout(Yii::t('user', 'User is not found') . "\n", Console::FG_RED); 54 | } else { 55 | if ($user->resetPassword($password)) { 56 | $this->stdout(Yii::t('user', 'Password has been changed') . "\n", Console::FG_GREEN); 57 | } else { 58 | $this->stdout(Yii::t('user', 'Error occurred while changing password') . "\n", Console::FG_RED); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /views/admin/_info.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var yii\web\View $this 14 | * @var dektrium\user\models\User $user 15 | */ 16 | ?> 17 | 18 | beginContent('@dektrium/user/views/admin/update.php', ['user' => $user]) ?> 19 | 20 | 21 | 22 | 23 | 24 | 25 | registration_ip !== null): ?> 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | isConfirmed): ?> 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | isBlocked): ?> 44 | 47 | 48 | 49 | 50 | 51 |
:created_at]) ?>
:registration_ip ?>
: 35 | confirmed_at]) ?> 36 |
: 45 | blocked_at]) ?> 46 |
52 | 53 | endContent() ?> 54 | -------------------------------------------------------------------------------- /commands/DeleteController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\commands; 13 | 14 | use dektrium\user\Finder; 15 | use Yii; 16 | use yii\console\Controller; 17 | use yii\helpers\Console; 18 | 19 | /** 20 | * Deletes a user. 21 | * 22 | * @property \dektrium\user\Module $module 23 | * 24 | * @author Dmitry Erofeev 25 | */ 26 | class DeleteController extends Controller 27 | { 28 | /** @var Finder */ 29 | protected $finder; 30 | 31 | /** 32 | * @param string $id 33 | * @param \yii\base\Module $module 34 | * @param Finder $finder 35 | * @param array $config 36 | */ 37 | public function __construct($id, $module, Finder $finder, $config = []) 38 | { 39 | $this->finder = $finder; 40 | parent::__construct($id, $module, $config); 41 | } 42 | 43 | /** 44 | * Deletes a user. 45 | * 46 | * @param string $search Email or username 47 | */ 48 | public function actionIndex($search) 49 | { 50 | if ($this->confirm(Yii::t('user', 'Are you sure? Deleted user can not be restored'))) { 51 | $user = $this->finder->findUserByUsernameOrEmail($search); 52 | if ($user === null) { 53 | $this->stdout(Yii::t('user', 'User is not found') . "\n", Console::FG_RED); 54 | } else { 55 | if ($user->delete()) { 56 | $this->stdout(Yii::t('user', 'User has been deleted') . "\n", Console::FG_GREEN); 57 | } else { 58 | $this->stdout(Yii::t('user', 'Error occurred while deleting user') . "\n", Console::FG_RED); 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /widgets/Connect.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\widgets; 13 | 14 | use Yii; 15 | use yii\authclient\ClientInterface; 16 | use yii\authclient\widgets\AuthChoice; 17 | use yii\authclient\widgets\AuthChoiceAsset; 18 | use yii\helpers\Html; 19 | use yii\helpers\Url; 20 | 21 | /** 22 | * @author Dmitry Erofeev 23 | */ 24 | class Connect extends AuthChoice 25 | { 26 | /** 27 | * @var array|null An array of user's accounts 28 | */ 29 | public $accounts; 30 | 31 | /** 32 | * @inheritdoc 33 | */ 34 | public $options = []; 35 | 36 | /** 37 | * @inheritdoc 38 | */ 39 | public function init() 40 | { 41 | AuthChoiceAsset::register(Yii::$app->view); 42 | if ($this->popupMode) { 43 | Yii::$app->view->registerJs("\$('#" . $this->getId() . "').authchoice();"); 44 | } 45 | $this->options['id'] = $this->getId(); 46 | echo Html::beginTag('div', $this->options); 47 | } 48 | 49 | /** 50 | * @inheritdoc 51 | */ 52 | public function createClientUrl($provider) 53 | { 54 | if ($this->isConnected($provider)) { 55 | return Url::to(['/user/settings/disconnect', 'id' => $this->accounts[$provider->getId()]->id]); 56 | } else { 57 | return parent::createClientUrl($provider); 58 | } 59 | } 60 | 61 | /** 62 | * Checks if provider already connected to user. 63 | * 64 | * @param ClientInterface $provider 65 | * 66 | * @return bool 67 | */ 68 | public function isConnected(ClientInterface $provider) 69 | { 70 | return $this->accounts != null && isset($this->accounts[$provider->getId()]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /commands/CreateController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\commands; 13 | 14 | use dektrium\user\models\User; 15 | use Yii; 16 | use yii\console\Controller; 17 | use yii\helpers\Console; 18 | 19 | /** 20 | * Creates new user account. 21 | * 22 | * @property \dektrium\user\Module $module 23 | * 24 | * @author Dmitry Erofeev 25 | */ 26 | class CreateController extends Controller 27 | { 28 | /** 29 | * This command creates new user account. If password is not set, this command will generate new 8-char password. 30 | * After saving user to database, this command uses mailer component to send credentials (username and password) to 31 | * user via email. 32 | * 33 | * @param string $email Email address 34 | * @param string $username Username 35 | * @param null|string $password Password (if null it will be generated automatically) 36 | */ 37 | public function actionIndex($email, $username, $password = null) 38 | { 39 | $user = Yii::createObject([ 40 | 'class' => User::className(), 41 | 'scenario' => 'create', 42 | 'email' => $email, 43 | 'username' => $username, 44 | 'password' => $password, 45 | ]); 46 | 47 | if ($user->create()) { 48 | $this->stdout(Yii::t('user', 'User has been created') . "!\n", Console::FG_GREEN); 49 | } else { 50 | $this->stdout(Yii::t('user', 'Please fix following errors:') . "\n", Console::FG_RED); 51 | foreach ($user->errors as $errors) { 52 | foreach ($errors as $error) { 53 | $this->stdout(' - ' . $error . "\n", Console::FG_RED); 54 | } 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [ABANDONED] Yii2-user [![Build Status](https://img.shields.io/travis/dektrium/yii2-user/master.svg?style=flat-square)](https://travis-ci.org/dektrium/yii2-user) [![Packagist Version](https://img.shields.io/packagist/v/dektrium/yii2-user.svg?style=flat-square)](https://packagist.org/packages/dektrium/yii2-user) [![Total Downloads](https://img.shields.io/packagist/dt/dektrium/yii2-user.svg?style=flat-square)](https://packagist.org/packages/dektrium/yii2-user) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 2 | 3 | ATTENTION: THIS PROJECT HAS BEEN ABANDONED!!! 4 | -------------------------------------------- 5 | 6 | Most of web applications provide a way for users to register, log in or reset 7 | their forgotten passwords. Rather than re-implementing this on each application, 8 | you can use Yii2-user which is a flexible user management module for Yii2 that 9 | handles common tasks such as registration, authentication and password retrieval. 10 | The latest version includes following features: 11 | 12 | * Registration with an optional confirmation per mail 13 | * Registration via social networks 14 | * Password recovery 15 | * Account and profile management 16 | * Console commands 17 | * User management interface 18 | * Ability to impersonate as another user given admin access is available 19 | 20 | > **NOTE:** Module is in initial development. Anything may change at any time. 21 | 22 | ## Documentation 23 | 24 | [Read the Documentation for master](docs/README.md) 25 | 26 | [Read the Documentation for v0.9.12](https://github.com/dektrium/yii2-user/blob/0.9.12/docs/README.md) 27 | 28 | ## Installation 29 | 30 | All installation instructions are located in documentation. 31 | 32 | ## Support 33 | 34 | If you have any questions or problems with Yii2-user you can ask them on [our forum](http://dektrium.com). 35 | 36 | ## Contributing to this project 37 | 38 | Anyone and everyone is welcome to contribute. Please take a moment to 39 | review the [guidelines for contributing](.github/CONTRIBUTING.md). 40 | 41 | ## License 42 | 43 | Yii2-user is released under the MIT License. See the bundled [LICENSE.md](LICENSE.md) 44 | for details. 45 | -------------------------------------------------------------------------------- /views/registration/connect.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use yii\widgets\ActiveForm; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var yii\widgets\ActiveForm $form 18 | * @var dektrium\user\models\User $model 19 | * @var dektrium\user\models\Account $account 20 | */ 21 | 22 | $this->title = Yii::t('user', 'Sign in'); 23 | $this->params['breadcrumbs'][] = $this->title; 24 | ?> 25 |
26 |
27 |
28 |
29 |

title) ?>

30 |
31 |
32 |
33 |

34 | : 38 |

39 |
40 | 'connect-account-form', 42 | ]); ?> 43 | 44 | field($model, 'email') ?> 45 | 46 | field($model, 'username') ?> 47 | 48 | 'btn btn-success btn-block']) ?> 49 | 50 | 51 |
52 |
53 |

54 | . 61 |

62 |
63 |
64 | -------------------------------------------------------------------------------- /helpers/Password.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\helpers; 13 | 14 | use Yii; 15 | 16 | /** 17 | * Password helper. 18 | * 19 | * @author Dmitry Erofeev 20 | */ 21 | class Password 22 | { 23 | /** 24 | * Wrapper for yii security helper method. 25 | * 26 | * @param $password 27 | * 28 | * @return string 29 | */ 30 | public static function hash($password) 31 | { 32 | return Yii::$app->security->generatePasswordHash($password, Yii::$app->getModule('user')->cost); 33 | } 34 | 35 | /** 36 | * Wrapper for yii security helper method. 37 | * 38 | * @param $password 39 | * @param $hash 40 | * 41 | * @return bool 42 | */ 43 | public static function validate($password, $hash) 44 | { 45 | return Yii::$app->security->validatePassword($password, $hash); 46 | } 47 | 48 | /** 49 | * Generates user-friendly random password containing at least one lower case letter, one uppercase letter and one 50 | * digit. The remaining characters in the password are chosen at random from those three sets. 51 | * 52 | * @see https://gist.github.com/tylerhall/521810 53 | * 54 | * @param $length 55 | * 56 | * @return string 57 | */ 58 | public static function generate($length) 59 | { 60 | $sets = [ 61 | 'abcdefghjkmnpqrstuvwxyz', 62 | 'ABCDEFGHJKMNPQRSTUVWXYZ', 63 | '23456789', 64 | ]; 65 | $all = ''; 66 | $password = ''; 67 | foreach ($sets as $set) { 68 | $password .= $set[array_rand(str_split($set))]; 69 | $all .= $set; 70 | } 71 | 72 | $all = str_split($all); 73 | for ($i = 0; $i < $length - count($sets); $i++) { 74 | $password .= $all[array_rand($all)]; 75 | } 76 | 77 | $password = str_shuffle($password); 78 | 79 | return $password; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Yii2-user 2 | 3 | Please take a moment to review this document in order to make the contribution process easy and effective for everyone 4 | involved. 5 | 6 | Following these guidelines helps to communicate that you respect the time of the developers managing and developing 7 | this open source project. In return, they should reciprocate that respect in addressing your issue or assessing 8 | patches and features. 9 | 10 | ## Do you have a question or problem with using Yii2-user? 11 | 12 | Ask any question about how to use Yii2-user on [our forum](http://dektrium.com). 13 | 14 | ## Did you find a security issue? 15 | 16 | Please don't use forum or Github issues to report security issues. Instead contact us directly by using following email 17 | address: `dmeroff@gmail.com`. 18 | 19 | ## Did you find a bug? 20 | 21 | - Ensure the bug was not already reported by searching on GitHub under Issues. 22 | - If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a title and clear 23 | description, as much relevant information as possible, and a code sample or an executable test case demonstrating the 24 | expected behavior that is not occurring. 25 | 26 | ## Do you intend to add a new feature or change an existing one? 27 | 28 | - Suggest your change on [our forum](http://dektrium.com) and start writing code. 29 | - Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are 30 | primarily intended for bug reports and fixes. 31 | 32 | ## Did you write a patch that fixes a bug? 33 | 34 | - Ensure your code follows PSR-2 code style 35 | - Commit your changes in logical chunks. Please adhere to 36 | [these git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your 37 | code is unlikely be merged into the main project. Use Git's interactive rebase feature to tidy up your commits before 38 | making them public. 39 | - Open a new GitHub pull request with the patch. 40 | - Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 41 | 42 | > **IMPORTANT**: By submitting a patch, you agree to allow the project owner to license your work under the same license 43 | as that used by the project. -------------------------------------------------------------------------------- /views/admin/_menu.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\bootstrap\Nav; 13 | 14 | ?> 15 | 16 | [ 18 | 'class' => 'nav-tabs', 19 | 'style' => 'margin-bottom: 15px', 20 | ], 21 | 'items' => [ 22 | [ 23 | 'label' => Yii::t('user', 'Users'), 24 | 'url' => ['/user/admin/index'], 25 | ], 26 | [ 27 | 'label' => Yii::t('user', 'Roles'), 28 | 'url' => ['/rbac/role/index'], 29 | 'visible' => isset(Yii::$app->extensions['dektrium/yii2-rbac']), 30 | ], 31 | [ 32 | 'label' => Yii::t('user', 'Permissions'), 33 | 'url' => ['/rbac/permission/index'], 34 | 'visible' => isset(Yii::$app->extensions['dektrium/yii2-rbac']), 35 | ], 36 | [ 37 | 'label' => \Yii::t('user', 'Rules'), 38 | 'url' => ['/rbac/rule/index'], 39 | 'visible' => isset(Yii::$app->extensions['dektrium/yii2-rbac']), 40 | ], 41 | [ 42 | 'label' => Yii::t('user', 'Create'), 43 | 'items' => [ 44 | [ 45 | 'label' => Yii::t('user', 'New user'), 46 | 'url' => ['/user/admin/create'], 47 | ], 48 | [ 49 | 'label' => Yii::t('user', 'New role'), 50 | 'url' => ['/rbac/role/create'], 51 | 'visible' => isset(Yii::$app->extensions['dektrium/yii2-rbac']), 52 | ], 53 | [ 54 | 'label' => Yii::t('user', 'New permission'), 55 | 'url' => ['/rbac/permission/create'], 56 | 'visible' => isset(Yii::$app->extensions['dektrium/yii2-rbac']), 57 | ], 58 | [ 59 | 'label' => \Yii::t('user', 'New rule'), 60 | 'url' => ['/rbac/rule/create'], 61 | 'visible' => isset(Yii::$app->extensions['dektrium/yii2-rbac']), 62 | ] 63 | ], 64 | ], 65 | ], 66 | ]) ?> 67 | -------------------------------------------------------------------------------- /migrations/m141222_110026_update_ip_field.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | use yii\db\Query; 14 | 15 | class m141222_110026_update_ip_field extends Migration 16 | { 17 | public function up() 18 | { 19 | $users = (new Query())->from('{{%user}}')->select('id, registration_ip ip')->all($this->db); 20 | 21 | $transaction = $this->db->beginTransaction(); 22 | try { 23 | $this->alterColumn('{{%user}}', 'registration_ip', $this->string(45)); 24 | foreach ($users as $user) { 25 | if ($user['ip'] == null) { 26 | continue; 27 | } 28 | $this->db->createCommand()->update('{{%user}}', [ 29 | 'registration_ip' => long2ip($user['ip']), 30 | ], 'id = ' . $user['id'])->execute(); 31 | } 32 | $transaction->commit(); 33 | } catch (Exception $e) { 34 | $transaction->rollBack(); 35 | throw $e; 36 | } 37 | } 38 | 39 | public function down() 40 | { 41 | $users = (new Query())->from('{{%user}}')->select('id, registration_ip ip')->all($this->db); 42 | 43 | $transaction = $this->db->beginTransaction(); 44 | try { 45 | foreach ($users as $user) { 46 | if ($user['ip'] == null) { 47 | continue; 48 | } 49 | $this->db->createCommand()->update('{{%user}}', [ 50 | 'registration_ip' => ip2long($user['ip']) 51 | ], 'id = ' . $user['id'])->execute(); 52 | } 53 | if ($this->dbType == 'pgsql') { 54 | $this->alterColumn('{{%user}}', 'registration_ip', $this->bigInteger() . ' USING registration_ip::bigint'); 55 | } else { 56 | $this->alterColumn('{{%user}}', 'registration_ip', $this->bigInteger()); 57 | } 58 | 59 | $transaction->commit(); 60 | } catch (Exception $e) { 61 | $transaction->rollBack(); 62 | throw $e; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /views/mail/welcome.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | 14 | /** 15 | * @var dektrium\user\Module $module 16 | * @var dektrium\user\models\User $user 17 | * @var dektrium\user\models\Token $token 18 | * @var bool $showPassword 19 | */ 20 | ?> 21 |

22 | , 23 |

24 | 25 |

26 | name) ?>. 27 | enableGeneratingPassword): ?> 28 | : password ?> 29 | 30 | 31 |

32 | 33 | 34 |

35 | . 36 |

37 |

38 | url), $token->url); ?> 39 |

40 |

41 | . 42 |

43 | 44 | 45 |

46 | . 47 |

48 | -------------------------------------------------------------------------------- /controllers/ProfileController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\controllers; 13 | 14 | use dektrium\user\Finder; 15 | use yii\filters\AccessControl; 16 | use yii\web\Controller; 17 | use yii\web\NotFoundHttpException; 18 | 19 | /** 20 | * ProfileController shows users profiles. 21 | * 22 | * @property \dektrium\user\Module $module 23 | * 24 | * @author Dmitry Erofeev 25 | */ 26 | class ProfileController extends Controller 27 | { 28 | /** @var Finder */ 29 | protected $finder; 30 | 31 | /** 32 | * @param string $id 33 | * @param \yii\base\Module $module 34 | * @param Finder $finder 35 | * @param array $config 36 | */ 37 | public function __construct($id, $module, Finder $finder, $config = []) 38 | { 39 | $this->finder = $finder; 40 | parent::__construct($id, $module, $config); 41 | } 42 | 43 | /** @inheritdoc */ 44 | public function behaviors() 45 | { 46 | return [ 47 | 'access' => [ 48 | 'class' => AccessControl::className(), 49 | 'rules' => [ 50 | ['allow' => true, 'actions' => ['index'], 'roles' => ['@']], 51 | ['allow' => true, 'actions' => ['show'], 'roles' => ['?', '@']], 52 | ], 53 | ], 54 | ]; 55 | } 56 | 57 | /** 58 | * Redirects to current user's profile. 59 | * 60 | * @return \yii\web\Response 61 | */ 62 | public function actionIndex() 63 | { 64 | return $this->redirect(['show', 'id' => \Yii::$app->user->getId()]); 65 | } 66 | 67 | /** 68 | * Shows user's profile. 69 | * 70 | * @param int $id 71 | * 72 | * @return \yii\web\Response 73 | * @throws \yii\web\NotFoundHttpException 74 | */ 75 | public function actionShow($id) 76 | { 77 | $profile = $this->finder->findProfileById($id); 78 | 79 | if ($profile === null) { 80 | throw new NotFoundHttpException(); 81 | } 82 | 83 | return $this->render('show', [ 84 | 'profile' => $profile, 85 | ]); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /migrations/m140504_113157_update_tables.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | /** 15 | * @author Dmitry Erofeev 16 | */ 17 | class m140504_113157_update_tables extends Migration 18 | { 19 | public function up() 20 | { 21 | // user table 22 | $this->dropIndex('{{%user_confirmation}}', '{{%user}}'); 23 | $this->dropIndex('{{%user_recovery}}', '{{%user}}'); 24 | $this->dropColumn('{{%user}}', 'confirmation_token'); 25 | $this->dropColumn('{{%user}}', 'confirmation_sent_at'); 26 | $this->dropColumn('{{%user}}', 'recovery_token'); 27 | $this->dropColumn('{{%user}}', 'recovery_sent_at'); 28 | $this->dropColumn('{{%user}}', 'logged_in_from'); 29 | $this->dropColumn('{{%user}}', 'logged_in_at'); 30 | $this->renameColumn('{{%user}}', 'registered_from', 'registration_ip'); 31 | $this->addColumn('{{%user}}', 'flags', $this->integer()->notNull()->defaultValue(0)); 32 | 33 | // account table 34 | $this->renameColumn('{{%account}}', 'properties', 'data'); 35 | } 36 | 37 | public function down() 38 | { 39 | // account table 40 | $this->renameColumn('{{%account}}', 'data', 'properties'); 41 | 42 | // user table 43 | if ($this->dbType == 'sqlsrv') { 44 | // this is needed because we need to drop the default constraint first 45 | $this->dropColumnConstraints('{{%user}}', 'flags'); 46 | } 47 | $this->dropColumn('{{%user}}', 'flags'); 48 | $this->renameColumn('{{%user}}', 'registration_ip', 'registered_from'); 49 | $this->addColumn('{{%user}}', 'logged_in_at', $this->integer()); 50 | $this->addColumn('{{%user}}', 'logged_in_from', $this->integer()); 51 | $this->addColumn('{{%user}}', 'recovery_sent_at', $this->integer()); 52 | $this->addColumn('{{%user}}', 'recovery_token', $this->string(32)); 53 | $this->addColumn('{{%user}}', 'confirmation_sent_at', $this->integer()); 54 | $this->addColumn('{{%user}}', 'confirmation_token', $this->string(32)); 55 | $this->createIndex('{{%user_confirmation}}', '{{%user}}', 'id, confirmation_token', true); 56 | $this->createIndex('{{%user_recovery}}', '{{%user}}', 'id, recovery_token', true); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /migrations/Migration.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\migrations; 13 | 14 | use Yii; 15 | 16 | /** 17 | * @author Dmitry Erofeev 18 | */ 19 | class Migration extends \yii\db\Migration 20 | { 21 | /** 22 | * @var string 23 | */ 24 | protected $tableOptions; 25 | protected $restrict = 'RESTRICT'; 26 | protected $cascade = 'CASCADE'; 27 | protected $dbType; 28 | 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | public function init() 34 | { 35 | parent::init(); 36 | 37 | switch ($this->db->driverName) { 38 | case 'mysql': 39 | $this->tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 40 | $this->dbType = 'mysql'; 41 | break; 42 | case 'pgsql': 43 | $this->tableOptions = null; 44 | $this->dbType = 'pgsql'; 45 | break; 46 | case 'dblib': 47 | case 'mssql': 48 | case 'sqlsrv': 49 | $this->restrict = 'NO ACTION'; 50 | $this->tableOptions = null; 51 | $this->dbType = 'sqlsrv'; 52 | break; 53 | default: 54 | throw new \RuntimeException('Your database is not supported!'); 55 | } 56 | } 57 | 58 | public function dropColumnConstraints($table, $column) 59 | { 60 | $table = $this->db->schema->getRawTableName($table); 61 | $cmd = $this->db->createCommand('SELECT name FROM sys.default_constraints 62 | WHERE parent_object_id = object_id(:table) 63 | AND type = \'D\' AND parent_column_id = ( 64 | SELECT column_id 65 | FROM sys.columns 66 | WHERE object_id = object_id(:table) 67 | and name = :column 68 | )', [ ':table' => $table, ':column' => $column ]); 69 | 70 | $constraints = $cmd->queryAll(); 71 | foreach ($constraints as $c) { 72 | $this->execute('ALTER TABLE '.$this->db->quoteTableName($table).' DROP CONSTRAINT '.$this->db->quoteColumnName($c['name'])); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /views/profile/show.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | 14 | /** 15 | * @var \yii\web\View $this 16 | * @var \dektrium\user\models\Profile $profile 17 | */ 18 | 19 | $this->title = empty($profile->name) ? Html::encode($profile->user->username) : Html::encode($profile->name); 20 | $this->params['breadcrumbs'][] = $this->title; 21 | ?> 22 |
23 |
24 |
25 |
26 | getAvatarUrl(230), [ 27 | 'class' => 'img-rounded img-responsive', 28 | 'alt' => $profile->user->username, 29 | ]) ?> 30 |
31 |
32 |

title ?>

33 |
    34 | location)): ?> 35 |
  • 36 | location) ?> 37 |
  • 38 | 39 | website)): ?> 40 |
  • 41 | website), Html::encode($profile->website)) ?> 42 |
  • 43 | 44 | public_email)): ?> 45 |
  • 46 | public_email), 'mailto:' . Html::encode($profile->public_email)) ?> 47 |
  • 48 | 49 |
  • 50 | user->created_at) ?> 51 |
  • 52 |
53 | bio)): ?> 54 |

bio) ?>

55 | 56 |
57 |
58 |
59 |
60 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | Upgrading instructions for Yii2-user 2 | ==================================== 3 | 4 | The following upgrading instructions are cumulative. That is, if you want to 5 | upgrade from version A to version C and there is version B between A and C, you 6 | need to following the instructions for both A and B. 7 | 8 | Upgrade from Yii2-user 0.9.* to Yii2-user 0.9.4 9 | 10 | - New authentication via social networks has been introduced. You should update 11 | your `authClientCollection` component as described in [guide](docs/social-auth.md). 12 | 13 | - Admin views have been remade. If you override admin view files, you should 14 | update them accordingly to the made changes. 15 | 16 | Upgrade from Yii2-user 0.8.* 17 | ---------------------------- 18 | 19 | - **APPLY NEW MIGRATIONS!** 20 | 21 | - `webUserClass` module option has been removed. If you use your own user 22 | component class you should set in `user` application component configuration: 23 | 24 | ```php 25 | 'components' => [ 26 | 'user' => [ 27 | 'class' => 'your\web\User', 28 | ], 29 | ], 30 | ``` 31 | 32 | - ModelManager component has been removed. If you override models, now you 33 | should set them via `modelMap` module's property. 34 | 35 | **Before:** 36 | 37 | ```php 38 | 'modules' => [ 39 | 'user' => [ 40 | 'class' => 'dektrium\user\Module', 41 | 'components' => [ 42 | 'manager' => [ 43 | 'User' => 'your\model\User', 44 | 'Profile' => 'your\model\Profile', 45 | ... 46 | ], 47 | ], 48 | ], 49 | ], 50 | ``` 51 | 52 | **After:** 53 | 54 | ```php 55 | 'modules' => [ 56 | 'user' => [ 57 | 'class' => 'dektrium\user\Module', 58 | 'modelMap' => [ 59 | 'User' => 'your\model\User', 60 | 'Profile' => 'your\model\Profile', 61 | ... 62 | ], 63 | ], 64 | ], 65 | ``` 66 | 67 | - Mailer component has been changed. Now it should be configured via `mailer` 68 | module property. You can read more about mailer configuration [here](docs/mailer.md). 69 | 70 | **Before:** 71 | 72 | ```php 73 | 'modules' => [ 74 | 'user' => [ 75 | 'class' => 'dektrium\user\Module', 76 | 'components' => [ 77 | 'mailer' => [ 78 | 'sender' => 'noreply@myhost.com', 79 | ], 80 | ], 81 | ], 82 | ], 83 | ``` 84 | 85 | **After:** 86 | 87 | ```php 88 | 'modules' => [ 89 | 'user' => [ 90 | 'class' => 'dektrium\user\Module', 91 | 'mailer' => [ 92 | 'sender' => 'noreply@myhost.com', 93 | ], 94 | ], 95 | ], 96 | ``` 97 | 98 | - Urls `user/settings/email` and `user/settings/password` have been merged into 99 | a new one `user/settings/account`. -------------------------------------------------------------------------------- /views/settings/networks.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\widgets\Connect; 13 | use yii\helpers\Html; 14 | 15 | /** 16 | * @var $this yii\web\View 17 | * @var $form yii\widgets\ActiveForm 18 | */ 19 | 20 | $this->title = Yii::t('user', 'Networks'); 21 | $this->params['breadcrumbs'][] = $this->title; 22 | ?> 23 | 24 | render('/_alert', ['module' => Yii::$app->getModule('user')]) ?> 25 | 26 |
27 |
28 | render('_menu') ?> 29 |
30 |
31 |
32 |
33 | title) ?> 34 |
35 |
36 |
37 |

.

38 |
39 | ['/user/security/auth'], 41 | 'accounts' => $user->accounts, 42 | 'autoRender' => false, 43 | 'popupMode' => false, 44 | ]) ?> 45 | 46 | getClients() as $client): ?> 47 | 48 | 51 | 54 | 65 | 66 | 67 |
49 | 'auth-icon ' . $client->getName()]) ?> 50 | 52 | getTitle() ?> 53 | 55 | isConnected($client) ? 56 | Html::a(Yii::t('user', 'Disconnect'), $auth->createClientUrl($client), [ 57 | 'class' => 'btn btn-danger btn-block', 58 | 'data-method' => 'post', 59 | ]) : 60 | Html::a(Yii::t('user', 'Connect'), $auth->createClientUrl($client), [ 61 | 'class' => 'btn btn-success btn-block', 62 | ]) 63 | ?> 64 |
68 | 69 |
70 |
71 |
72 |
73 | -------------------------------------------------------------------------------- /migrations/m140209_132017_init.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\migrations\Migration; 13 | 14 | /** 15 | * @author Dmitry Erofeev createTable('{{%user}}', [ 22 | 'id' => $this->primaryKey(), 23 | 'username' => $this->string(25)->notNull(), 24 | 'email' => $this->string(255)->notNull(), 25 | 'password_hash' => $this->string(60)->notNull(), 26 | 'auth_key' => $this->string(32)->notNull(), 27 | 'confirmation_token' => $this->string(32)->null(), 28 | 'confirmation_sent_at' => $this->integer()->null(), 29 | 'confirmed_at' => $this->integer()->null(), 30 | 'unconfirmed_email' => $this->string(255)->null(), 31 | 'recovery_token' => $this->string(32)->null(), 32 | 'recovery_sent_at' => $this->integer()->null(), 33 | 'blocked_at' => $this->integer()->null(), 34 | 'registered_from' => $this->integer()->null(), 35 | 'logged_in_from' => $this->integer()->null(), 36 | 'logged_in_at' => $this->integer()->null(), 37 | 'created_at' => $this->integer()->notNull(), 38 | 'updated_at' => $this->integer()->notNull(), 39 | ], $this->tableOptions); 40 | 41 | $this->createIndex('{{%user_unique_username}}', '{{%user}}', 'username', true); 42 | $this->createIndex('{{%user_unique_email}}', '{{%user}}', 'email', true); 43 | $this->createIndex('{{%user_confirmation}}', '{{%user}}', 'id, confirmation_token', true); 44 | $this->createIndex('{{%user_recovery}}', '{{%user}}', 'id, recovery_token', true); 45 | 46 | $this->createTable('{{%profile}}', [ 47 | 'user_id' => $this->integer()->notNull()->append('PRIMARY KEY'), 48 | 'name' => $this->string(255)->null(), 49 | 'public_email' => $this->string(255)->null(), 50 | 'gravatar_email' => $this->string(255)->null(), 51 | 'gravatar_id' => $this->string(32)->null(), 52 | 'location' => $this->string(255)->null(), 53 | 'website' => $this->string(255)->null(), 54 | 'bio' => $this->text()->null(), 55 | ], $this->tableOptions); 56 | 57 | $this->addForeignKey('{{%fk_user_profile}}', '{{%profile}}', 'user_id', '{{%user}}', 'id', $this->cascade, $this->restrict); 58 | } 59 | 60 | public function down() 61 | { 62 | $this->dropTable('{{%profile}}'); 63 | $this->dropTable('{{%user}}'); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /models/ResendForm.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\Finder; 15 | use dektrium\user\Mailer; 16 | use yii\base\Model; 17 | 18 | /** 19 | * ResendForm gets user email address and if user with given email is registered it sends new confirmation message 20 | * to him in case he did not validate his email. 21 | * 22 | * @author Dmitry Erofeev 23 | */ 24 | class ResendForm extends Model 25 | { 26 | /** 27 | * @var string 28 | */ 29 | public $email; 30 | 31 | /** 32 | * @var Mailer 33 | */ 34 | protected $mailer; 35 | 36 | /** 37 | * @var Finder 38 | */ 39 | protected $finder; 40 | 41 | /** 42 | * @param Mailer $mailer 43 | * @param Finder $finder 44 | * @param array $config 45 | */ 46 | public function __construct(Mailer $mailer, Finder $finder, $config = []) 47 | { 48 | $this->mailer = $mailer; 49 | $this->finder = $finder; 50 | parent::__construct($config); 51 | } 52 | 53 | /** 54 | * @inheritdoc 55 | */ 56 | public function rules() 57 | { 58 | return [ 59 | 'emailRequired' => ['email', 'required'], 60 | 'emailPattern' => ['email', 'email'], 61 | ]; 62 | } 63 | 64 | /** 65 | * @inheritdoc 66 | */ 67 | public function attributeLabels() 68 | { 69 | return [ 70 | 'email' => \Yii::t('user', 'Email'), 71 | ]; 72 | } 73 | 74 | /** 75 | * @inheritdoc 76 | */ 77 | public function formName() 78 | { 79 | return 'resend-form'; 80 | } 81 | 82 | /** 83 | * Creates new confirmation token and sends it to the user. 84 | * 85 | * @return bool 86 | */ 87 | public function resend() 88 | { 89 | if (!$this->validate()) { 90 | return false; 91 | } 92 | 93 | $user = $this->finder->findUserByEmail($this->email); 94 | 95 | if ($user instanceof User && !$user->isConfirmed) { 96 | /** @var Token $token */ 97 | $token = \Yii::createObject([ 98 | 'class' => Token::className(), 99 | 'user_id' => $user->id, 100 | 'type' => Token::TYPE_CONFIRMATION, 101 | ]); 102 | $token->save(false); 103 | $this->mailer->sendConfirmationMessage($user, $token); 104 | } 105 | 106 | \Yii::$app->session->setFlash( 107 | 'info', 108 | \Yii::t( 109 | 'user', 110 | 'A message has been sent to your email address. It contains a confirmation link that you must click to complete registration.' 111 | ) 112 | ); 113 | 114 | return true; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /views/settings/profile.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use dektrium\user\helpers\Timezone; 14 | use yii\widgets\ActiveForm; 15 | use yii\helpers\ArrayHelper; 16 | 17 | /** 18 | * @var yii\web\View $this 19 | * @var yii\widgets\ActiveForm $form 20 | * @var dektrium\user\models\Profile $model 21 | */ 22 | 23 | $this->title = Yii::t('user', 'Profile settings'); 24 | $this->params['breadcrumbs'][] = $this->title; 25 | ?> 26 | 27 | render('/_alert', ['module' => Yii::$app->getModule('user')]) ?> 28 | 29 |
30 |
31 | render('_menu') ?> 32 |
33 |
34 |
35 |
36 | title) ?> 37 |
38 |
39 | 'profile-form', 41 | 'options' => ['class' => 'form-horizontal'], 42 | 'fieldConfig' => [ 43 | 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", 44 | 'labelOptions' => ['class' => 'col-lg-3 control-label'], 45 | ], 46 | 'enableAjaxValidation' => true, 47 | 'enableClientValidation' => false, 48 | 'validateOnBlur' => false, 49 | ]); ?> 50 | 51 | field($model, 'name') ?> 52 | 53 | field($model, 'public_email') ?> 54 | 55 | field($model, 'website') ?> 56 | 57 | field($model, 'location') ?> 58 | 59 | field($model, 'timezone') 61 | ->dropDownList( 62 | ArrayHelper::map( 63 | Timezone::getAll(), 64 | 'timezone', 65 | 'name' 66 | ) 67 | ); ?> 68 | 69 | field($model, 'gravatar_email') 71 | ->hint(Html::a(Yii::t('user', 'Change your avatar at Gravatar.com'), 'http://gravatar.com')) ?> 72 | 73 | field($model, 'bio')->textarea() ?> 74 | 75 |
76 |
77 | 'btn btn-block btn-success']) ?> 78 |
79 |
80 |
81 | 82 | 83 |
84 |
85 |
86 |
87 | -------------------------------------------------------------------------------- /traits/EventTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\traits; 13 | 14 | use dektrium\user\events\AuthEvent; 15 | use dektrium\user\events\ConnectEvent; 16 | use dektrium\user\events\FormEvent; 17 | use dektrium\user\events\ProfileEvent; 18 | use dektrium\user\events\ResetPasswordEvent; 19 | use dektrium\user\events\UserEvent; 20 | use dektrium\user\models\Account; 21 | use dektrium\user\models\Profile; 22 | use dektrium\user\models\RecoveryForm; 23 | use dektrium\user\models\Token; 24 | use dektrium\user\models\User; 25 | use yii\authclient\ClientInterface; 26 | use yii\base\Model; 27 | 28 | /** 29 | * @author Dmitry Erofeev 30 | */ 31 | trait EventTrait 32 | { 33 | /** 34 | * @param Model $form 35 | * @return FormEvent 36 | * @throws \yii\base\InvalidConfigException 37 | */ 38 | protected function getFormEvent(Model $form) 39 | { 40 | return \Yii::createObject(['class' => FormEvent::className(), 'form' => $form]); 41 | } 42 | 43 | /** 44 | * @param User $user 45 | * @return UserEvent 46 | * @throws \yii\base\InvalidConfigException 47 | */ 48 | protected function getUserEvent(User $user) 49 | { 50 | return \Yii::createObject(['class' => UserEvent::className(), 'user' => $user]); 51 | } 52 | 53 | /** 54 | * @param Profile $profile 55 | * @return ProfileEvent 56 | * @throws \yii\base\InvalidConfigException 57 | */ 58 | protected function getProfileEvent(Profile $profile) 59 | { 60 | return \Yii::createObject(['class' => ProfileEvent::className(), 'profile' => $profile]); 61 | } 62 | 63 | 64 | /** 65 | * @param Account $account 66 | * @param User $user 67 | * @return ConnectEvent 68 | * @throws \yii\base\InvalidConfigException 69 | */ 70 | protected function getConnectEvent(Account $account, User $user) 71 | { 72 | return \Yii::createObject(['class' => ConnectEvent::className(), 'account' => $account, 'user' => $user]); 73 | } 74 | 75 | /** 76 | * @param Account $account 77 | * @param ClientInterface $client 78 | * @return AuthEvent 79 | * @throws \yii\base\InvalidConfigException 80 | */ 81 | protected function getAuthEvent(Account $account, ClientInterface $client) 82 | { 83 | return \Yii::createObject(['class' => AuthEvent::className(), 'account' => $account, 'client' => $client]); 84 | } 85 | 86 | /** 87 | * @param Token $token 88 | * @param RecoveryForm $form 89 | * @return ResetPasswordEvent 90 | * @throws \yii\base\InvalidConfigException 91 | */ 92 | protected function getResetPasswordEvent(Token $token = null, RecoveryForm $form = null) 93 | { 94 | return \Yii::createObject(['class' => ResetPasswordEvent::className(), 'token' => $token, 'form' => $form]); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /views/admin/create.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\bootstrap\ActiveForm; 13 | use yii\bootstrap\Nav; 14 | use yii\helpers\Html; 15 | 16 | /** 17 | * @var yii\web\View $this 18 | * @var dektrium\user\models\User $user 19 | */ 20 | 21 | $this->title = Yii::t('user', 'Create a user account'); 22 | $this->params['breadcrumbs'][] = ['label' => Yii::t('user', 'Users'), 'url' => ['index']]; 23 | $this->params['breadcrumbs'][] = $this->title; 24 | ?> 25 | 26 | render('/_alert', ['module' => Yii::$app->getModule('user'),]) ?> 27 | 28 | render('_menu') ?> 29 | 30 |
31 |
32 |
33 |
34 | [ 36 | 'class' => 'nav-pills nav-stacked', 37 | ], 38 | 'items' => [ 39 | ['label' => Yii::t('user', 'Account details'), 'url' => ['/user/admin/create']], 40 | ['label' => Yii::t('user', 'Profile details'), 'options' => [ 41 | 'class' => 'disabled', 42 | 'onclick' => 'return false;', 43 | ]], 44 | ['label' => Yii::t('user', 'Information'), 'options' => [ 45 | 'class' => 'disabled', 46 | 'onclick' => 'return false;', 47 | ]], 48 | ], 49 | ]) ?> 50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | . 58 | . 59 |
60 | 'horizontal', 62 | 'enableAjaxValidation' => true, 63 | 'enableClientValidation' => false, 64 | 'fieldConfig' => [ 65 | 'horizontalCssClasses' => [ 66 | 'wrapper' => 'col-sm-9', 67 | ], 68 | ], 69 | ]); ?> 70 | 71 | render('_user', ['form' => $form, 'user' => $user]) ?> 72 | 73 |
74 |
75 | 'btn btn-block btn-success']) ?> 76 |
77 |
78 | 79 | 80 |
81 |
82 |
83 |
84 | -------------------------------------------------------------------------------- /views/settings/account.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\helpers\Html; 13 | use yii\widgets\ActiveForm; 14 | 15 | /** 16 | * @var yii\web\View $this 17 | * @var yii\widgets\ActiveForm $form 18 | * @var dektrium\user\models\SettingsForm $model 19 | */ 20 | 21 | $this->title = Yii::t('user', 'Account settings'); 22 | $this->params['breadcrumbs'][] = $this->title; 23 | ?> 24 | 25 | render('/_alert', ['module' => Yii::$app->getModule('user')]) ?> 26 | 27 |
28 |
29 | render('_menu') ?> 30 |
31 |
32 |
33 |
34 |

title) ?>

35 |
36 |
37 | 'account-form', 39 | 'options' => ['class' => 'form-horizontal'], 40 | 'fieldConfig' => [ 41 | 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", 42 | 'labelOptions' => ['class' => 'col-lg-3 control-label'], 43 | ], 44 | 'enableAjaxValidation' => true, 45 | 'enableClientValidation' => false, 46 | ]); ?> 47 | 48 | field($model, 'email') ?> 49 | 50 | field($model, 'username') ?> 51 | 52 | field($model, 'new_password')->passwordInput() ?> 53 | 54 |
55 | 56 | field($model, 'current_password')->passwordInput() ?> 57 | 58 |
59 |
60 | 'btn btn-block btn-success']) ?>
61 |
62 |
63 | 64 | 65 |
66 |
67 | 68 | module->enableAccountDelete): ?> 69 |
70 |
71 |

72 |
73 |
74 |

75 | . 76 | . 77 | . 78 |

79 | 'btn btn-danger', 81 | 'data-method' => 'post', 82 | 'data-confirm' => Yii::t('user', 'Are you sure? There is no going back'), 83 | ]) ?> 84 |
85 |
86 | 87 |
88 |
89 | -------------------------------------------------------------------------------- /models/UserSearch.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\Finder; 15 | use Yii; 16 | use yii\base\Model; 17 | use yii\data\ActiveDataProvider; 18 | 19 | /** 20 | * UserSearch represents the model behind the search form about User. 21 | */ 22 | class UserSearch extends Model 23 | { 24 | /** @var integer */ 25 | public $id; 26 | 27 | /** @var string */ 28 | public $username; 29 | 30 | /** @var string */ 31 | public $email; 32 | 33 | /** @var int */ 34 | public $created_at; 35 | 36 | /** @var int */ 37 | public $last_login_at; 38 | 39 | /** @var string */ 40 | public $registration_ip; 41 | 42 | /** @var Finder */ 43 | protected $finder; 44 | 45 | /** 46 | * @param Finder $finder 47 | * @param array $config 48 | */ 49 | public function __construct(Finder $finder, $config = []) 50 | { 51 | $this->finder = $finder; 52 | parent::__construct($config); 53 | } 54 | 55 | /** @inheritdoc */ 56 | public function rules() 57 | { 58 | return [ 59 | 'fieldsSafe' => [['id', 'username', 'email', 'registration_ip', 'created_at', 'last_login_at'], 'safe'], 60 | 'createdDefault' => ['created_at', 'default', 'value' => null], 61 | 'lastloginDefault' => ['last_login_at', 'default', 'value' => null], 62 | ]; 63 | } 64 | 65 | /** @inheritdoc */ 66 | public function attributeLabels() 67 | { 68 | return [ 69 | 'id' => Yii::t('user', '#'), 70 | 'username' => Yii::t('user', 'Username'), 71 | 'email' => Yii::t('user', 'Email'), 72 | 'created_at' => Yii::t('user', 'Registration time'), 73 | 'last_login_at' => Yii::t('user', 'Last login'), 74 | 'registration_ip' => Yii::t('user', 'Registration ip'), 75 | ]; 76 | } 77 | 78 | /** 79 | * @param $params 80 | * 81 | * @return ActiveDataProvider 82 | */ 83 | public function search($params) 84 | { 85 | $query = $this->finder->getUserQuery(); 86 | 87 | $dataProvider = new ActiveDataProvider([ 88 | 'query' => $query, 89 | 'sort' => ['defaultOrder' => ['created_at' => SORT_DESC]], 90 | ]); 91 | 92 | if (!($this->load($params) && $this->validate())) { 93 | return $dataProvider; 94 | } 95 | 96 | $modelClass = $query->modelClass; 97 | $table_name = $modelClass::tableName(); 98 | 99 | if ($this->created_at !== null) { 100 | $date = strtotime($this->created_at); 101 | $query->andFilterWhere(['between', $table_name . '.created_at', $date, $date + 3600 * 24]); 102 | } 103 | 104 | $query->andFilterWhere(['like', $table_name . '.username', $this->username]) 105 | ->andFilterWhere(['like', $table_name . '.email', $this->email]) 106 | ->andFilterWhere([$table_name . '.id' => $this->id]) 107 | ->andFilterWhere([$table_name . '.registration_ip' => $this->registration_ip]); 108 | 109 | return $dataProvider; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /models/Token.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\traits\ModuleTrait; 15 | use Yii; 16 | use yii\db\ActiveRecord; 17 | use yii\helpers\Url; 18 | 19 | /** 20 | * Token Active Record model. 21 | * 22 | * @property integer $user_id 23 | * @property string $code 24 | * @property integer $created_at 25 | * @property integer $type 26 | * @property string $url 27 | * @property bool $isExpired 28 | * @property User $user 29 | * 30 | * @author Dmitry Erofeev 31 | */ 32 | class Token extends ActiveRecord 33 | { 34 | use ModuleTrait; 35 | 36 | const TYPE_CONFIRMATION = 0; 37 | const TYPE_RECOVERY = 1; 38 | const TYPE_CONFIRM_NEW_EMAIL = 2; 39 | const TYPE_CONFIRM_OLD_EMAIL = 3; 40 | 41 | /** 42 | * @return \yii\db\ActiveQuery 43 | */ 44 | public function getUser() 45 | { 46 | return $this->hasOne($this->module->modelMap['User'], ['id' => 'user_id']); 47 | } 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function getUrl() 53 | { 54 | switch ($this->type) { 55 | case self::TYPE_CONFIRMATION: 56 | $route = '/user/registration/confirm'; 57 | break; 58 | case self::TYPE_RECOVERY: 59 | $route = '/user/recovery/reset'; 60 | break; 61 | case self::TYPE_CONFIRM_NEW_EMAIL: 62 | case self::TYPE_CONFIRM_OLD_EMAIL: 63 | $route = '/user/settings/confirm'; 64 | break; 65 | default: 66 | throw new \RuntimeException(); 67 | } 68 | 69 | return Url::to([$route, 'id' => $this->user_id, 'code' => $this->code], true); 70 | } 71 | 72 | /** 73 | * @return bool Whether token has expired. 74 | */ 75 | public function getIsExpired() 76 | { 77 | switch ($this->type) { 78 | case self::TYPE_CONFIRMATION: 79 | case self::TYPE_CONFIRM_NEW_EMAIL: 80 | case self::TYPE_CONFIRM_OLD_EMAIL: 81 | $expirationTime = $this->module->confirmWithin; 82 | break; 83 | case self::TYPE_RECOVERY: 84 | $expirationTime = $this->module->recoverWithin; 85 | break; 86 | default: 87 | throw new \RuntimeException(); 88 | } 89 | 90 | return ($this->created_at + $expirationTime) < time(); 91 | } 92 | 93 | /** @inheritdoc */ 94 | public function beforeSave($insert) 95 | { 96 | if ($insert) { 97 | static::deleteAll(['user_id' => $this->user_id, 'type' => $this->type]); 98 | $this->setAttribute('created_at', time()); 99 | $this->setAttribute('code', Yii::$app->security->generateRandomString()); 100 | } 101 | 102 | return parent::beforeSave($insert); 103 | } 104 | 105 | /** @inheritdoc */ 106 | public static function tableName() 107 | { 108 | return '{{%token}}'; 109 | } 110 | 111 | /** @inheritdoc */ 112 | public static function primaryKey() 113 | { 114 | return ['user_id', 'code', 'type']; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Module.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user; 13 | 14 | use yii\base\Module as BaseModule; 15 | 16 | /** 17 | * This is the main module class for the Yii2-user. 18 | * 19 | * @property array $modelMap 20 | * 21 | * @author Dmitry Erofeev 22 | */ 23 | class Module extends BaseModule 24 | { 25 | const VERSION = '0.9.12'; 26 | 27 | /** Email is changed right after user enter's new email address. */ 28 | const STRATEGY_INSECURE = 0; 29 | 30 | /** Email is changed after user clicks confirmation link sent to his new email address. */ 31 | const STRATEGY_DEFAULT = 1; 32 | 33 | /** Email is changed after user clicks both confirmation links sent to his old and new email addresses. */ 34 | const STRATEGY_SECURE = 2; 35 | 36 | /** @var bool Whether to show flash messages. */ 37 | public $enableFlashMessages = true; 38 | 39 | /** @var bool Whether to enable registration. */ 40 | public $enableRegistration = true; 41 | 42 | /** @var bool Whether to remove password field from registration form. */ 43 | public $enableGeneratingPassword = false; 44 | 45 | /** @var bool Whether user has to confirm his account. */ 46 | public $enableConfirmation = true; 47 | 48 | /** @var bool Whether to allow logging in without confirmation. */ 49 | public $enableUnconfirmedLogin = false; 50 | 51 | /** @var bool Whether to enable password recovery. */ 52 | public $enablePasswordRecovery = true; 53 | 54 | /** @var bool Whether user can remove his account */ 55 | public $enableAccountDelete = false; 56 | 57 | /** @var bool Enable the 'impersonate as another user' function */ 58 | public $enableImpersonateUser = true; 59 | 60 | /** @var int Email changing strategy. */ 61 | public $emailChangeStrategy = self::STRATEGY_DEFAULT; 62 | 63 | /** @var int The time you want the user will be remembered without asking for credentials. */ 64 | public $rememberFor = 1209600; // two weeks 65 | 66 | /** @var int The time before a confirmation token becomes invalid. */ 67 | public $confirmWithin = 86400; // 24 hours 68 | 69 | /** @var int The time before a recovery token becomes invalid. */ 70 | public $recoverWithin = 21600; // 6 hours 71 | 72 | /** @var int Cost parameter used by the Blowfish hash algorithm. */ 73 | public $cost = 10; 74 | 75 | /** @var array An array of administrator's usernames. */ 76 | public $admins = []; 77 | 78 | /** @var string The Administrator permission name. */ 79 | public $adminPermission; 80 | 81 | /** @var array Mailer configuration */ 82 | public $mailer = []; 83 | 84 | /** @var array Model map */ 85 | public $modelMap = []; 86 | 87 | /** 88 | * @var string The prefix for user module URL. 89 | * 90 | * @See [[GroupUrlRule::prefix]] 91 | */ 92 | public $urlPrefix = 'user'; 93 | 94 | /** 95 | * @var bool Is the user module in DEBUG mode? Will be set to false automatically 96 | * if the application leaves DEBUG mode. 97 | */ 98 | public $debug = false; 99 | 100 | /** @var string The database connection to use for models in this module. */ 101 | public $dbConnection = 'db'; 102 | 103 | /** @var array The rules to be used in URL management. */ 104 | public $urlRules = [ 105 | '' => 'profile/show', 106 | '' => 'security/', 107 | '' => 'registration/', 108 | 'confirm//' => 'registration/confirm', 109 | 'forgot' => 'recovery/request', 110 | 'recover//' => 'recovery/reset', 111 | 'settings/' => 'settings/' 112 | ]; 113 | 114 | /** 115 | * @return string 116 | */ 117 | public function getDb() 118 | { 119 | return \Yii::$app->get($this->dbConnection); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /models/RegistrationForm.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\traits\ModuleTrait; 15 | use Yii; 16 | use yii\base\Model; 17 | 18 | /** 19 | * Registration form collects user input on registration process, validates it and creates new User model. 20 | * 21 | * @author Dmitry Erofeev 22 | */ 23 | class RegistrationForm extends Model 24 | { 25 | use ModuleTrait; 26 | /** 27 | * @var string User email address 28 | */ 29 | public $email; 30 | 31 | /** 32 | * @var string Username 33 | */ 34 | public $username; 35 | 36 | /** 37 | * @var string Password 38 | */ 39 | public $password; 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public function rules() 45 | { 46 | $user = $this->module->modelMap['User']; 47 | 48 | return [ 49 | // username rules 50 | 'usernameTrim' => ['username', 'trim'], 51 | 'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255], 52 | 'usernamePattern' => ['username', 'match', 'pattern' => $user::$usernameRegexp], 53 | 'usernameRequired' => ['username', 'required'], 54 | 'usernameUnique' => [ 55 | 'username', 56 | 'unique', 57 | 'targetClass' => $user, 58 | 'message' => Yii::t('user', 'This username has already been taken') 59 | ], 60 | // email rules 61 | 'emailTrim' => ['email', 'trim'], 62 | 'emailRequired' => ['email', 'required'], 63 | 'emailPattern' => ['email', 'email'], 64 | 'emailUnique' => [ 65 | 'email', 66 | 'unique', 67 | 'targetClass' => $user, 68 | 'message' => Yii::t('user', 'This email address has already been taken') 69 | ], 70 | // password rules 71 | 'passwordRequired' => ['password', 'required', 'skipOnEmpty' => $this->module->enableGeneratingPassword], 72 | 'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72], 73 | ]; 74 | } 75 | 76 | /** 77 | * @inheritdoc 78 | */ 79 | public function attributeLabels() 80 | { 81 | return [ 82 | 'email' => Yii::t('user', 'Email'), 83 | 'username' => Yii::t('user', 'Username'), 84 | 'password' => Yii::t('user', 'Password'), 85 | ]; 86 | } 87 | 88 | /** 89 | * @inheritdoc 90 | */ 91 | public function formName() 92 | { 93 | return 'register-form'; 94 | } 95 | 96 | /** 97 | * Registers a new user account. If registration was successful it will set flash message. 98 | * 99 | * @return bool 100 | */ 101 | public function register() 102 | { 103 | if (!$this->validate()) { 104 | return false; 105 | } 106 | 107 | /** @var User $user */ 108 | $user = Yii::createObject(User::className()); 109 | $user->setScenario('register'); 110 | $this->loadAttributes($user); 111 | 112 | if (!$user->register()) { 113 | return false; 114 | } 115 | 116 | Yii::$app->session->setFlash( 117 | 'info', 118 | Yii::t( 119 | 'user', 120 | 'Your account has been created and a message with further instructions has been sent to your email' 121 | ) 122 | ); 123 | 124 | return true; 125 | } 126 | 127 | /** 128 | * Loads attributes to the user model. You should override this method if you are going to add new fields to the 129 | * registration form. You can read more in special guide. 130 | * 131 | * By default this method set all attributes of this model to the attributes of User model, so you should properly 132 | * configure safe attributes of your User model. 133 | * 134 | * @param User $user 135 | */ 136 | protected function loadAttributes(User $user) 137 | { 138 | $user->setAttributes($this->attributes); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /views/security/login.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use dektrium\user\widgets\Connect; 13 | use dektrium\user\models\LoginForm; 14 | use yii\helpers\Html; 15 | use yii\widgets\ActiveForm; 16 | 17 | /** 18 | * @var yii\web\View $this 19 | * @var dektrium\user\models\LoginForm $model 20 | * @var dektrium\user\Module $module 21 | */ 22 | 23 | $this->title = Yii::t('user', 'Sign in'); 24 | $this->params['breadcrumbs'][] = $this->title; 25 | ?> 26 | 27 | render('/_alert', ['module' => Yii::$app->getModule('user')]) ?> 28 | 29 |
30 |
31 |
32 |
33 |

title) ?>

34 |
35 |
36 | 'login-form', 38 | 'enableAjaxValidation' => true, 39 | 'enableClientValidation' => false, 40 | 'validateOnBlur' => false, 41 | 'validateOnType' => false, 42 | 'validateOnChange' => false, 43 | ]) ?> 44 | 45 | debug): ?> 46 | field($model, 'login', [ 47 | 'inputOptions' => [ 48 | 'autofocus' => 'autofocus', 49 | 'class' => 'form-control', 50 | 'tabindex' => '1']])->dropDownList(LoginForm::loginList()); 51 | ?> 52 | 53 | 54 | 55 | field($model, 'login', 56 | ['inputOptions' => ['autofocus' => 'autofocus', 'class' => 'form-control', 'tabindex' => '1']] 57 | ); 58 | ?> 59 | 60 | 61 | 62 | debug): ?> 63 |
64 | 65 |
66 | 67 | field( 68 | $model, 69 | 'password', 70 | ['inputOptions' => ['class' => 'form-control', 'tabindex' => '2']]) 71 | ->passwordInput() 72 | ->label( 73 | Yii::t('user', 'Password') 74 | . ($module->enablePasswordRecovery ? 75 | ' (' . Html::a( 76 | Yii::t('user', 'Forgot password?'), 77 | ['/user/recovery/request'], 78 | ['tabindex' => '5'] 79 | ) 80 | . ')' : '') 81 | ) ?> 82 | 83 | 84 | field($model, 'rememberMe')->checkbox(['tabindex' => '3']) ?> 85 | 86 | 'btn btn-primary btn-block', 'tabindex' => '4'] 89 | ) ?> 90 | 91 | 92 |
93 |
94 | enableConfirmation): ?> 95 |

96 | 97 |

98 | 99 | enableRegistration): ?> 100 |

101 | 102 |

103 | 104 | ['/user/security/auth'], 106 | ]) ?> 107 |
108 |
109 | -------------------------------------------------------------------------------- /models/RecoveryForm.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\Finder; 15 | use dektrium\user\Mailer; 16 | use yii\base\Model; 17 | 18 | /** 19 | * Model for collecting data on password recovery. 20 | * 21 | * @author Dmitry Erofeev 22 | */ 23 | class RecoveryForm extends Model 24 | { 25 | const SCENARIO_REQUEST = 'request'; 26 | const SCENARIO_RESET = 'reset'; 27 | 28 | /** 29 | * @var string 30 | */ 31 | public $email; 32 | 33 | /** 34 | * @var string 35 | */ 36 | public $password; 37 | 38 | /** 39 | * @var Mailer 40 | */ 41 | protected $mailer; 42 | 43 | /** 44 | * @var Finder 45 | */ 46 | protected $finder; 47 | 48 | /** 49 | * @param Mailer $mailer 50 | * @param Finder $finder 51 | * @param array $config 52 | */ 53 | public function __construct(Mailer $mailer, Finder $finder, $config = []) 54 | { 55 | $this->mailer = $mailer; 56 | $this->finder = $finder; 57 | parent::__construct($config); 58 | } 59 | 60 | /** 61 | * @inheritdoc 62 | */ 63 | public function attributeLabels() 64 | { 65 | return [ 66 | 'email' => \Yii::t('user', 'Email'), 67 | 'password' => \Yii::t('user', 'Password'), 68 | ]; 69 | } 70 | 71 | /** 72 | * @inheritdoc 73 | */ 74 | public function scenarios() 75 | { 76 | return [ 77 | self::SCENARIO_REQUEST => ['email'], 78 | self::SCENARIO_RESET => ['password'], 79 | ]; 80 | } 81 | 82 | /** 83 | * @inheritdoc 84 | */ 85 | public function rules() 86 | { 87 | return [ 88 | 'emailTrim' => ['email', 'trim'], 89 | 'emailRequired' => ['email', 'required'], 90 | 'emailPattern' => ['email', 'email'], 91 | 'passwordRequired' => ['password', 'required'], 92 | 'passwordLength' => ['password', 'string', 'max' => 72, 'min' => 6], 93 | ]; 94 | } 95 | 96 | /** 97 | * Sends recovery message. 98 | * 99 | * @return bool 100 | */ 101 | public function sendRecoveryMessage() 102 | { 103 | if (!$this->validate()) { 104 | return false; 105 | } 106 | 107 | $user = $this->finder->findUserByEmail($this->email); 108 | 109 | if ($user instanceof User) { 110 | /** @var Token $token */ 111 | $token = \Yii::createObject([ 112 | 'class' => Token::className(), 113 | 'user_id' => $user->id, 114 | 'type' => Token::TYPE_RECOVERY, 115 | ]); 116 | 117 | if (!$token->save(false)) { 118 | return false; 119 | } 120 | 121 | if (!$this->mailer->sendRecoveryMessage($user, $token)) { 122 | return false; 123 | } 124 | } 125 | 126 | \Yii::$app->session->setFlash( 127 | 'info', 128 | \Yii::t('user', 'An email has been sent with instructions for resetting your password') 129 | ); 130 | 131 | return true; 132 | } 133 | 134 | /** 135 | * Resets user's password. 136 | * 137 | * @param Token $token 138 | * 139 | * @return bool 140 | */ 141 | public function resetPassword(Token $token) 142 | { 143 | if (!$this->validate() || $token->user === null) { 144 | return false; 145 | } 146 | 147 | if ($token->user->resetPassword($this->password)) { 148 | \Yii::$app->session->setFlash('success', \Yii::t('user', 'Your password has been changed successfully.')); 149 | $token->delete(); 150 | } else { 151 | \Yii::$app->session->setFlash( 152 | 'danger', 153 | \Yii::t('user', 'An error occurred and your password has not been changed. Please try again later.') 154 | ); 155 | } 156 | 157 | return true; 158 | } 159 | 160 | /** 161 | * @inheritdoc 162 | */ 163 | public function formName() 164 | { 165 | return 'recovery-form'; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /views/admin/update.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\bootstrap\Nav; 13 | 14 | /** 15 | * @var \yii\web\View $this 16 | * @var \dektrium\user\models\User $user 17 | * @var string $content 18 | */ 19 | 20 | $this->title = Yii::t('user', 'Update user account'); 21 | $this->params['breadcrumbs'][] = ['label' => Yii::t('user', 'Users'), 'url' => ['index']]; 22 | $this->params['breadcrumbs'][] = $this->title; 23 | ?> 24 | 25 | render('/_alert', ['module' => Yii::$app->getModule('user')]) ?> 26 | 27 | render('_menu') ?> 28 | 29 |
30 |
31 |
32 |
33 | [ 35 | 'class' => 'nav-pills nav-stacked', 36 | ], 37 | 'items' => [ 38 | [ 39 | 'label' => Yii::t('user', 'Account details'), 40 | 'url' => ['/user/admin/update', 'id' => $user->id] 41 | ], 42 | [ 43 | 'label' => Yii::t('user', 'Profile details'), 44 | 'url' => ['/user/admin/update-profile', 'id' => $user->id] 45 | ], 46 | ['label' => Yii::t('user', 'Information'), 'url' => ['/user/admin/info', 'id' => $user->id]], 47 | [ 48 | 'label' => Yii::t('user', 'Assignments'), 49 | 'url' => ['/user/admin/assignments', 'id' => $user->id], 50 | 'visible' => isset(Yii::$app->extensions['dektrium/yii2-rbac']), 51 | ], 52 | '
', 53 | [ 54 | 'label' => Yii::t('user', 'Confirm'), 55 | 'url' => ['/user/admin/confirm', 'id' => $user->id], 56 | 'visible' => !$user->isConfirmed, 57 | 'linkOptions' => [ 58 | 'class' => 'text-success', 59 | 'data-method' => 'post', 60 | 'data-confirm' => Yii::t('user', 'Are you sure you want to confirm this user?'), 61 | ], 62 | ], 63 | [ 64 | 'label' => Yii::t('user', 'Block'), 65 | 'url' => ['/user/admin/block', 'id' => $user->id], 66 | 'visible' => !$user->isBlocked, 67 | 'linkOptions' => [ 68 | 'class' => 'text-danger', 69 | 'data-method' => 'post', 70 | 'data-confirm' => Yii::t('user', 'Are you sure you want to block this user?'), 71 | ], 72 | ], 73 | [ 74 | 'label' => Yii::t('user', 'Unblock'), 75 | 'url' => ['/user/admin/block', 'id' => $user->id], 76 | 'visible' => $user->isBlocked, 77 | 'linkOptions' => [ 78 | 'class' => 'text-success', 79 | 'data-method' => 'post', 80 | 'data-confirm' => Yii::t('user', 'Are you sure you want to unblock this user?'), 81 | ], 82 | ], 83 | [ 84 | 'label' => Yii::t('user', 'Delete'), 85 | 'url' => ['/user/admin/delete', 'id' => $user->id], 86 | 'linkOptions' => [ 87 | 'class' => 'text-danger', 88 | 'data-method' => 'post', 89 | 'data-confirm' => Yii::t('user', 'Are you sure you want to delete this user?'), 90 | ], 91 | ], 92 | ], 93 | ]) ?> 94 |
95 |
96 |
97 |
98 |
99 |
100 | 101 |
102 |
103 |
104 |
105 | -------------------------------------------------------------------------------- /views/mail/layouts/html.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /** 13 | * @var \yii\web\View $this 14 | * @var yii\mail\BaseMessage $content 15 | */ 16 | ?> 17 | beginPage() ?> 18 | 19 | 20 | 21 | 22 | 23 | head() ?> 24 | 25 | 26 | 27 | 28 | 29 | 42 | 43 | 44 |
30 |
31 | 32 | 33 | 38 | 39 |
34 | beginBody() ?> 35 | 36 | endBody() ?> 37 |
40 |
41 |
45 | 46 | 59 | 60 | 61 | 62 | 63 | 64 | endPage() ?> 65 | -------------------------------------------------------------------------------- /Bootstrap.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user; 13 | 14 | use Yii; 15 | use yii\authclient\Collection; 16 | use yii\base\BootstrapInterface; 17 | use yii\console\Application as ConsoleApplication; 18 | use yii\i18n\PhpMessageSource; 19 | 20 | /** 21 | * Bootstrap class registers module and user application component. It also creates some url rules which will be applied 22 | * when UrlManager.enablePrettyUrl is enabled. 23 | * 24 | * @author Dmitry Erofeev 25 | */ 26 | class Bootstrap implements BootstrapInterface 27 | { 28 | /** @var array Model's map */ 29 | private $_modelMap = [ 30 | 'User' => 'dektrium\user\models\User', 31 | 'Account' => 'dektrium\user\models\Account', 32 | 'Profile' => 'dektrium\user\models\Profile', 33 | 'Token' => 'dektrium\user\models\Token', 34 | 'RegistrationForm' => 'dektrium\user\models\RegistrationForm', 35 | 'ResendForm' => 'dektrium\user\models\ResendForm', 36 | 'LoginForm' => 'dektrium\user\models\LoginForm', 37 | 'SettingsForm' => 'dektrium\user\models\SettingsForm', 38 | 'RecoveryForm' => 'dektrium\user\models\RecoveryForm', 39 | 'UserSearch' => 'dektrium\user\models\UserSearch', 40 | ]; 41 | 42 | /** @inheritdoc */ 43 | public function bootstrap($app) 44 | { 45 | /** @var Module $module */ 46 | /** @var \yii\db\ActiveRecord $modelName */ 47 | if ($app->hasModule('user') && ($module = $app->getModule('user')) instanceof Module) { 48 | $this->_modelMap = array_merge($this->_modelMap, $module->modelMap); 49 | foreach ($this->_modelMap as $name => $definition) { 50 | $class = "dektrium\\user\\models\\" . $name; 51 | Yii::$container->set($class, $definition); 52 | $modelName = is_array($definition) ? $definition['class'] : $definition; 53 | $module->modelMap[$name] = $modelName; 54 | if (in_array($name, ['User', 'Profile', 'Token', 'Account'])) { 55 | Yii::$container->set($name . 'Query', function () use ($modelName) { 56 | return $modelName::find(); 57 | }); 58 | } 59 | } 60 | 61 | Yii::$container->setSingleton(Finder::className(), [ 62 | 'userQuery' => Yii::$container->get('UserQuery'), 63 | 'profileQuery' => Yii::$container->get('ProfileQuery'), 64 | 'tokenQuery' => Yii::$container->get('TokenQuery'), 65 | 'accountQuery' => Yii::$container->get('AccountQuery'), 66 | ]); 67 | 68 | if ($app instanceof ConsoleApplication) { 69 | $module->controllerNamespace = 'dektrium\user\commands'; 70 | } else { 71 | Yii::$container->set('yii\web\User', [ 72 | 'enableAutoLogin' => true, 73 | 'loginUrl' => ['/user/security/login'], 74 | 'identityClass' => $module->modelMap['User'], 75 | ]); 76 | 77 | $configUrlRule = [ 78 | 'prefix' => $module->urlPrefix, 79 | 'rules' => $module->urlRules, 80 | ]; 81 | 82 | if ($module->urlPrefix != 'user') { 83 | $configUrlRule['routePrefix'] = 'user'; 84 | } 85 | 86 | $configUrlRule['class'] = 'yii\web\GroupUrlRule'; 87 | $rule = Yii::createObject($configUrlRule); 88 | 89 | $app->urlManager->addRules([$rule], false); 90 | 91 | if (!$app->has('authClientCollection')) { 92 | $app->set('authClientCollection', [ 93 | 'class' => Collection::className(), 94 | ]); 95 | } 96 | } 97 | 98 | if (!isset($app->get('i18n')->translations['user*'])) { 99 | $app->get('i18n')->translations['user*'] = [ 100 | 'class' => PhpMessageSource::className(), 101 | 'basePath' => __DIR__ . '/messages', 102 | 'sourceLanguage' => 'en-US' 103 | ]; 104 | } 105 | 106 | Yii::$container->set('dektrium\user\Mailer', $module->mailer); 107 | 108 | $module->debug = $this->ensureCorrectDebugSetting(); 109 | } 110 | } 111 | 112 | /** Ensure the module is not in DEBUG mode on production environments */ 113 | public function ensureCorrectDebugSetting() 114 | { 115 | if (!defined('YII_DEBUG')) { 116 | return false; 117 | } 118 | if (!defined('YII_ENV')) { 119 | return false; 120 | } 121 | if (defined('YII_ENV') && YII_ENV !== 'dev') { 122 | return false; 123 | } 124 | if (defined('YII_DEBUG') && YII_DEBUG !== true) { 125 | return false; 126 | } 127 | 128 | return Yii::$app->getModule('user')->debug; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /models/Profile.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\traits\ModuleTrait; 15 | use yii\db\ActiveRecord; 16 | 17 | /** 18 | * This is the model class for table "profile". 19 | * 20 | * @property integer $user_id 21 | * @property string $name 22 | * @property string $public_email 23 | * @property string $gravatar_email 24 | * @property string $gravatar_id 25 | * @property string $location 26 | * @property string $website 27 | * @property string $bio 28 | * @property string $timezone 29 | * @property User $user 30 | * 31 | * @author Dmitry Erofeev module = \Yii::$app->getModule('user'); 43 | } 44 | 45 | /** 46 | * Returns avatar url or null if avatar is not set. 47 | * @param int $size 48 | * @return string|null 49 | */ 50 | public function getAvatarUrl($size = 200) 51 | { 52 | return '//gravatar.com/avatar/' . $this->gravatar_id . '?s=' . $size; 53 | } 54 | 55 | /** 56 | * @return \yii\db\ActiveQueryInterface 57 | */ 58 | public function getUser() 59 | { 60 | return $this->hasOne($this->module->modelMap['User'], ['id' => 'user_id']); 61 | } 62 | 63 | /** 64 | * @inheritdoc 65 | */ 66 | public function rules() 67 | { 68 | return [ 69 | 'bioString' => ['bio', 'string'], 70 | 'timeZoneValidation' => ['timezone', 'validateTimeZone'], 71 | 'publicEmailPattern' => ['public_email', 'email'], 72 | 'gravatarEmailPattern' => ['gravatar_email', 'email'], 73 | 'websiteUrl' => ['website', 'url'], 74 | 'nameLength' => ['name', 'string', 'max' => 255], 75 | 'publicEmailLength' => ['public_email', 'string', 'max' => 255], 76 | 'gravatarEmailLength' => ['gravatar_email', 'string', 'max' => 255], 77 | 'locationLength' => ['location', 'string', 'max' => 255], 78 | 'websiteLength' => ['website', 'string', 'max' => 255], 79 | ]; 80 | } 81 | 82 | /** 83 | * @inheritdoc 84 | */ 85 | public function attributeLabels() 86 | { 87 | return [ 88 | 'name' => \Yii::t('user', 'Name'), 89 | 'public_email' => \Yii::t('user', 'Email (public)'), 90 | 'gravatar_email' => \Yii::t('user', 'Gravatar email'), 91 | 'location' => \Yii::t('user', 'Location'), 92 | 'website' => \Yii::t('user', 'Website'), 93 | 'bio' => \Yii::t('user', 'Bio'), 94 | 'timezone' => \Yii::t('user', 'Time zone'), 95 | ]; 96 | } 97 | 98 | /** 99 | * Validates the timezone attribute. 100 | * Adds an error when the specified time zone doesn't exist. 101 | * @param string $attribute the attribute being validated 102 | * @param array $params values for the placeholders in the error message 103 | */ 104 | public function validateTimeZone($attribute, $params) 105 | { 106 | if (!in_array($this->$attribute, timezone_identifiers_list())) { 107 | $this->addError($attribute, \Yii::t('user', 'Time zone is not valid')); 108 | } 109 | } 110 | 111 | /** 112 | * Get the user's time zone. 113 | * Defaults to the application timezone if not specified by the user. 114 | * @return \DateTimeZone 115 | */ 116 | public function getTimeZone() 117 | { 118 | try { 119 | return new \DateTimeZone($this->timezone); 120 | } catch (\Exception $e) { 121 | // Default to application time zone if the user hasn't set their time zone 122 | return new \DateTimeZone(\Yii::$app->timeZone); 123 | } 124 | } 125 | 126 | /** 127 | * Set the user's time zone. 128 | * @param \DateTimeZone $timezone the timezone to save to the user's profile 129 | */ 130 | public function setTimeZone(\DateTimeZone $timeZone) 131 | { 132 | $this->setAttribute('timezone', $timeZone->getName()); 133 | } 134 | 135 | /** 136 | * Converts DateTime to user's local time 137 | * @param \DateTime the datetime to convert 138 | * @return \DateTime 139 | */ 140 | public function toLocalTime(\DateTime $dateTime = null) 141 | { 142 | if ($dateTime === null) { 143 | $dateTime = new \DateTime(); 144 | } 145 | 146 | return $dateTime->setTimezone($this->getTimeZone()); 147 | } 148 | 149 | /** 150 | * @inheritdoc 151 | */ 152 | public function beforeSave($insert) 153 | { 154 | if ($this->isAttributeChanged('gravatar_email')) { 155 | $this->setAttribute('gravatar_id', md5(strtolower(trim($this->getAttribute('gravatar_email'))))); 156 | } 157 | 158 | return parent::beforeSave($insert); 159 | } 160 | 161 | /** 162 | * @inheritdoc 163 | */ 164 | public static function tableName() 165 | { 166 | return '{{%profile}}'; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /models/LoginForm.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\Finder; 15 | use dektrium\user\helpers\Password; 16 | use dektrium\user\traits\ModuleTrait; 17 | use yii\helpers\ArrayHelper; 18 | use yii\helpers\Html; 19 | use Yii; 20 | use yii\base\Model; 21 | 22 | /** 23 | * LoginForm get user's login and password, validates them and logs the user in. If user has been blocked, it adds 24 | * an error to login form. 25 | * 26 | * @author Dmitry Erofeev 27 | */ 28 | class LoginForm extends Model 29 | { 30 | use ModuleTrait; 31 | 32 | /** @var string User's email or username */ 33 | public $login; 34 | 35 | /** @var string User's plain password */ 36 | public $password; 37 | 38 | /** @var string Whether to remember the user */ 39 | public $rememberMe = false; 40 | 41 | /** @var \dektrium\user\models\User */ 42 | protected $user; 43 | 44 | /** @var Finder */ 45 | protected $finder; 46 | 47 | /** 48 | * @param Finder $finder 49 | * @param array $config 50 | */ 51 | public function __construct(Finder $finder, $config = []) 52 | { 53 | $this->finder = $finder; 54 | parent::__construct($config); 55 | } 56 | 57 | /** 58 | * Gets all users to generate the dropdown list when in debug mode. 59 | * 60 | * @return array 61 | */ 62 | public static function loginList() 63 | { 64 | /** @var \dektrium\user\Module $module */ 65 | $module = \Yii::$app->getModule('user'); 66 | 67 | $userModel = $module->modelMap['User']; 68 | 69 | return ArrayHelper::map($userModel::find()->where(['blocked_at' => null])->all(), 'username', function ($user) { 70 | return sprintf('%s (%s)', Html::encode($user->username), Html::encode($user->email)); 71 | }); 72 | } 73 | 74 | /** @inheritdoc */ 75 | public function attributeLabels() 76 | { 77 | return [ 78 | 'login' => Yii::t('user', 'Login'), 79 | 'password' => Yii::t('user', 'Password'), 80 | 'rememberMe' => Yii::t('user', 'Remember me next time'), 81 | ]; 82 | } 83 | 84 | /** @inheritdoc */ 85 | public function rules() 86 | { 87 | $rules = [ 88 | 'loginTrim' => ['login', 'trim'], 89 | 'requiredFields' => [['login'], 'required'], 90 | 'confirmationValidate' => [ 91 | 'login', 92 | function ($attribute) { 93 | if ($this->user !== null) { 94 | $confirmationRequired = $this->module->enableConfirmation 95 | && !$this->module->enableUnconfirmedLogin; 96 | if ($confirmationRequired && !$this->user->getIsConfirmed()) { 97 | $this->addError($attribute, Yii::t('user', 'You need to confirm your email address')); 98 | } 99 | if ($this->user->getIsBlocked()) { 100 | $this->addError($attribute, Yii::t('user', 'Your account has been blocked')); 101 | } 102 | } 103 | } 104 | ], 105 | 'rememberMe' => ['rememberMe', 'boolean'], 106 | ]; 107 | 108 | if (!$this->module->debug) { 109 | $rules = array_merge($rules, [ 110 | 'requiredFields' => [['login', 'password'], 'required'], 111 | 'passwordValidate' => [ 112 | 'password', 113 | function ($attribute) { 114 | if ($this->user === null || !Password::validate($this->password, $this->user->password_hash)) { 115 | $this->addError($attribute, Yii::t('user', 'Invalid login or password')); 116 | } 117 | } 118 | ] 119 | ]); 120 | } 121 | 122 | return $rules; 123 | } 124 | 125 | /** 126 | * Validates if the hash of the given password is identical to the saved hash in the database. 127 | * It will always succeed if the module is in DEBUG mode. 128 | * 129 | * @return void 130 | */ 131 | public function validatePassword($attribute, $params) 132 | { 133 | if ($this->user === null || !Password::validate($this->password, $this->user->password_hash)) 134 | $this->addError($attribute, Yii::t('user', 'Invalid login or password')); 135 | } 136 | 137 | /** 138 | * Validates form and logs the user in. 139 | * 140 | * @return bool whether the user is logged in successfully 141 | */ 142 | public function login() 143 | { 144 | if ($this->validate() && $this->user) { 145 | $isLogged = Yii::$app->getUser()->login($this->user, $this->rememberMe ? $this->module->rememberFor : 0); 146 | 147 | if ($isLogged) { 148 | $this->user->updateAttributes(['last_login_at' => time()]); 149 | } 150 | 151 | return $isLogged; 152 | } 153 | 154 | return false; 155 | } 156 | 157 | 158 | /** @inheritdoc */ 159 | public function formName() 160 | { 161 | return 'login-form'; 162 | } 163 | 164 | /** @inheritdoc */ 165 | public function beforeValidate() 166 | { 167 | if (parent::beforeValidate()) { 168 | $this->user = $this->finder->findUserByUsernameOrEmail(trim($this->login)); 169 | 170 | return true; 171 | } else { 172 | return false; 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Finder.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user; 13 | 14 | use dektrium\user\models\query\AccountQuery; 15 | use dektrium\user\models\Token; 16 | use yii\authclient\ClientInterface; 17 | use yii\base\BaseObject; 18 | use yii\db\ActiveQuery; 19 | 20 | /** 21 | * Finder provides some useful methods for finding active record models. 22 | * 23 | * @author Dmitry Erofeev 24 | */ 25 | class Finder extends BaseObject 26 | { 27 | /** @var ActiveQuery */ 28 | protected $userQuery; 29 | 30 | /** @var ActiveQuery */ 31 | protected $tokenQuery; 32 | 33 | /** @var AccountQuery */ 34 | protected $accountQuery; 35 | 36 | /** @var ActiveQuery */ 37 | protected $profileQuery; 38 | 39 | /** 40 | * @return ActiveQuery 41 | */ 42 | public function getUserQuery() 43 | { 44 | return $this->userQuery; 45 | } 46 | 47 | /** 48 | * @return ActiveQuery 49 | */ 50 | public function getTokenQuery() 51 | { 52 | return $this->tokenQuery; 53 | } 54 | 55 | /** 56 | * @return ActiveQuery 57 | */ 58 | public function getAccountQuery() 59 | { 60 | return $this->accountQuery; 61 | } 62 | 63 | /** 64 | * @return ActiveQuery 65 | */ 66 | public function getProfileQuery() 67 | { 68 | return $this->profileQuery; 69 | } 70 | 71 | /** @param ActiveQuery $accountQuery */ 72 | public function setAccountQuery(ActiveQuery $accountQuery) 73 | { 74 | $this->accountQuery = $accountQuery; 75 | } 76 | 77 | /** @param ActiveQuery $userQuery */ 78 | public function setUserQuery(ActiveQuery $userQuery) 79 | { 80 | $this->userQuery = $userQuery; 81 | } 82 | 83 | /** @param ActiveQuery $tokenQuery */ 84 | public function setTokenQuery(ActiveQuery $tokenQuery) 85 | { 86 | $this->tokenQuery = $tokenQuery; 87 | } 88 | 89 | /** @param ActiveQuery $profileQuery */ 90 | public function setProfileQuery(ActiveQuery $profileQuery) 91 | { 92 | $this->profileQuery = $profileQuery; 93 | } 94 | 95 | /** 96 | * Finds a user by the given id. 97 | * 98 | * @param int $id User id to be used on search. 99 | * 100 | * @return models\User 101 | */ 102 | public function findUserById($id) 103 | { 104 | return $this->findUser(['id' => $id])->one(); 105 | } 106 | 107 | /** 108 | * Finds a user by the given username. 109 | * 110 | * @param string $username Username to be used on search. 111 | * 112 | * @return models\User 113 | */ 114 | public function findUserByUsername($username) 115 | { 116 | return $this->findUser(['username' => $username])->one(); 117 | } 118 | 119 | /** 120 | * Finds a user by the given email. 121 | * 122 | * @param string $email Email to be used on search. 123 | * 124 | * @return models\User 125 | */ 126 | public function findUserByEmail($email) 127 | { 128 | return $this->findUser(['email' => $email])->one(); 129 | } 130 | 131 | /** 132 | * Finds a user by the given username or email. 133 | * 134 | * @param string $usernameOrEmail Username or email to be used on search. 135 | * 136 | * @return models\User 137 | */ 138 | public function findUserByUsernameOrEmail($usernameOrEmail) 139 | { 140 | if (filter_var($usernameOrEmail, FILTER_VALIDATE_EMAIL)) { 141 | return $this->findUserByEmail($usernameOrEmail); 142 | } 143 | 144 | return $this->findUserByUsername($usernameOrEmail); 145 | } 146 | 147 | /** 148 | * Finds a user by the given condition. 149 | * 150 | * @param mixed $condition Condition to be used on search. 151 | * 152 | * @return \yii\db\ActiveQuery 153 | */ 154 | public function findUser($condition) 155 | { 156 | return $this->userQuery->where($condition); 157 | } 158 | 159 | /** 160 | * @return AccountQuery 161 | */ 162 | public function findAccount() 163 | { 164 | return $this->accountQuery; 165 | } 166 | 167 | /** 168 | * Finds an account by id. 169 | * 170 | * @param int $id 171 | * 172 | * @return models\Account|null 173 | */ 174 | public function findAccountById($id) 175 | { 176 | return $this->accountQuery->where(['id' => $id])->one(); 177 | } 178 | 179 | /** 180 | * Finds a token by user id and code. 181 | * 182 | * @param mixed $condition 183 | * 184 | * @return ActiveQuery 185 | */ 186 | public function findToken($condition) 187 | { 188 | return $this->tokenQuery->where($condition); 189 | } 190 | 191 | /** 192 | * Finds a token by params. 193 | * 194 | * @param integer $userId 195 | * @param string $code 196 | * @param integer $type 197 | * 198 | * @return Token 199 | */ 200 | public function findTokenByParams($userId, $code, $type) 201 | { 202 | return $this->findToken([ 203 | 'user_id' => $userId, 204 | 'code' => $code, 205 | 'type' => $type, 206 | ])->one(); 207 | } 208 | 209 | /** 210 | * Finds a profile by user id. 211 | * 212 | * @param int $id 213 | * 214 | * @return null|models\Profile 215 | */ 216 | public function findProfileById($id) 217 | { 218 | return $this->findProfile(['user_id' => $id])->one(); 219 | } 220 | 221 | /** 222 | * Finds a profile. 223 | * 224 | * @param mixed $condition 225 | * 226 | * @return \yii\db\ActiveQuery 227 | */ 228 | public function findProfile($condition) 229 | { 230 | return $this->profileQuery->where($condition); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /views/admin/index.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE.md 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use yii\grid\GridView; 13 | use yii\helpers\Html; 14 | use yii\helpers\Url; 15 | use yii\web\View; 16 | use yii\widgets\Pjax; 17 | 18 | 19 | /** 20 | * @var \yii\web\View $this 21 | * @var \yii\data\ActiveDataProvider $dataProvider 22 | * @var \dektrium\user\models\UserSearch $searchModel 23 | */ 24 | 25 | $this->title = Yii::t('user', 'Manage users'); 26 | $this->params['breadcrumbs'][] = $this->title; 27 | ?> 28 | 29 | render('/_alert', ['module' => Yii::$app->getModule('user')]) ?> 30 | 31 | render('/admin/_menu') ?> 32 | 33 | 34 | 35 | $dataProvider, 37 | 'filterModel' => $searchModel, 38 | 'layout' => "{items}\n{pager}", 39 | 'columns' => [ 40 | [ 41 | 'attribute' => 'id', 42 | 'headerOptions' => ['style' => 'width:90px;'], # 90px is sufficient for 5-digit user ids 43 | ], 44 | 'username', 45 | 'email:email', 46 | [ 47 | 'attribute' => 'registration_ip', 48 | 'value' => function ($model) { 49 | return $model->registration_ip == null 50 | ? '' . Yii::t('user', '(not set)') . '' 51 | : $model->registration_ip; 52 | }, 53 | 'format' => 'html', 54 | ], 55 | [ 56 | 'attribute' => 'created_at', 57 | 'value' => function ($model) { 58 | if (extension_loaded('intl')) { 59 | return Yii::t('user', '{0, date, MMMM dd, YYYY HH:mm}', [$model->created_at]); 60 | } else { 61 | return date('Y-m-d G:i:s', $model->created_at); 62 | } 63 | }, 64 | ], 65 | 66 | [ 67 | 'attribute' => 'last_login_at', 68 | 'value' => function ($model) { 69 | if (!$model->last_login_at || $model->last_login_at == 0) { 70 | return Yii::t('user', 'Never'); 71 | } else if (extension_loaded('intl')) { 72 | return Yii::t('user', '{0, date, MMMM dd, YYYY HH:mm}', [$model->last_login_at]); 73 | } else { 74 | return date('Y-m-d G:i:s', $model->last_login_at); 75 | } 76 | }, 77 | ], 78 | [ 79 | 'header' => Yii::t('user', 'Confirmation'), 80 | 'value' => function ($model) { 81 | if ($model->isConfirmed) { 82 | return '
83 | ' . Yii::t('user', 'Confirmed') . ' 84 |
'; 85 | } else { 86 | return Html::a(Yii::t('user', 'Confirm'), ['confirm', 'id' => $model->id], [ 87 | 'class' => 'btn btn-xs btn-success btn-block', 88 | 'data-method' => 'post', 89 | 'data-confirm' => Yii::t('user', 'Are you sure you want to confirm this user?'), 90 | ]); 91 | } 92 | }, 93 | 'format' => 'raw', 94 | 'visible' => Yii::$app->getModule('user')->enableConfirmation, 95 | ], 96 | [ 97 | 'header' => Yii::t('user', 'Block status'), 98 | 'value' => function ($model) { 99 | if ($model->isBlocked) { 100 | return Html::a(Yii::t('user', 'Unblock'), ['block', 'id' => $model->id], [ 101 | 'class' => 'btn btn-xs btn-success btn-block', 102 | 'data-method' => 'post', 103 | 'data-confirm' => Yii::t('user', 'Are you sure you want to unblock this user?'), 104 | ]); 105 | } else { 106 | return Html::a(Yii::t('user', 'Block'), ['block', 'id' => $model->id], [ 107 | 'class' => 'btn btn-xs btn-danger btn-block', 108 | 'data-method' => 'post', 109 | 'data-confirm' => Yii::t('user', 'Are you sure you want to block this user?'), 110 | ]); 111 | } 112 | }, 113 | 'format' => 'raw', 114 | ], 115 | [ 116 | 'class' => 'yii\grid\ActionColumn', 117 | 'template' => '{switch} {resend_password} {update} {delete}', 118 | 'buttons' => [ 119 | 'resend_password' => function ($url, $model, $key) { 120 | if (\Yii::$app->user->identity->isAdmin && !$model->isAdmin) { 121 | return ' 122 | 123 | 124 | '; 125 | } 126 | }, 127 | 'switch' => function ($url, $model) { 128 | if(\Yii::$app->user->identity->isAdmin && $model->id != Yii::$app->user->id && Yii::$app->getModule('user')->enableImpersonateUser) { 129 | return Html::a('', ['/user/admin/switch', 'id' => $model->id], [ 130 | 'title' => Yii::t('user', 'Become this user'), 131 | 'data-confirm' => Yii::t('user', 'Are you sure you want to switch to this user for the rest of this Session?'), 132 | 'data-method' => 'POST', 133 | ]); 134 | } 135 | } 136 | ] 137 | ], 138 | ], 139 | ]); ?> 140 | 141 | 142 | -------------------------------------------------------------------------------- /controllers/RecoveryController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\controllers; 13 | 14 | use dektrium\user\Finder; 15 | use dektrium\user\models\RecoveryForm; 16 | use dektrium\user\models\Token; 17 | use dektrium\user\traits\AjaxValidationTrait; 18 | use dektrium\user\traits\EventTrait; 19 | use yii\filters\AccessControl; 20 | use yii\web\Controller; 21 | use yii\web\NotFoundHttpException; 22 | 23 | /** 24 | * RecoveryController manages password recovery process. 25 | * 26 | * @property \dektrium\user\Module $module 27 | * 28 | * @author Dmitry Erofeev 29 | */ 30 | class RecoveryController extends Controller 31 | { 32 | use AjaxValidationTrait; 33 | use EventTrait; 34 | 35 | /** 36 | * Event is triggered before requesting password reset. 37 | * Triggered with \dektrium\user\events\FormEvent. 38 | */ 39 | const EVENT_BEFORE_REQUEST = 'beforeRequest'; 40 | 41 | /** 42 | * Event is triggered after requesting password reset. 43 | * Triggered with \dektrium\user\events\FormEvent. 44 | */ 45 | const EVENT_AFTER_REQUEST = 'afterRequest'; 46 | 47 | /** 48 | * Event is triggered before validating recovery token. 49 | * Triggered with \dektrium\user\events\ResetPasswordEvent. May not have $form property set. 50 | */ 51 | const EVENT_BEFORE_TOKEN_VALIDATE = 'beforeTokenValidate'; 52 | 53 | /** 54 | * Event is triggered after validating recovery token. 55 | * Triggered with \dektrium\user\events\ResetPasswordEvent. May not have $form property set. 56 | */ 57 | const EVENT_AFTER_TOKEN_VALIDATE = 'afterTokenValidate'; 58 | 59 | /** 60 | * Event is triggered before resetting password. 61 | * Triggered with \dektrium\user\events\ResetPasswordEvent. 62 | */ 63 | const EVENT_BEFORE_RESET = 'beforeReset'; 64 | 65 | /** 66 | * Event is triggered after resetting password. 67 | * Triggered with \dektrium\user\events\ResetPasswordEvent. 68 | */ 69 | const EVENT_AFTER_RESET = 'afterReset'; 70 | 71 | /** @var Finder */ 72 | protected $finder; 73 | 74 | /** 75 | * @param string $id 76 | * @param \yii\base\Module $module 77 | * @param Finder $finder 78 | * @param array $config 79 | */ 80 | public function __construct($id, $module, Finder $finder, $config = []) 81 | { 82 | $this->finder = $finder; 83 | parent::__construct($id, $module, $config); 84 | } 85 | 86 | /** @inheritdoc */ 87 | public function behaviors() 88 | { 89 | return [ 90 | 'access' => [ 91 | 'class' => AccessControl::className(), 92 | 'rules' => [ 93 | ['allow' => true, 'actions' => ['request', 'reset'], 'roles' => ['?']], 94 | ], 95 | ], 96 | ]; 97 | } 98 | 99 | /** 100 | * Shows page where user can request password recovery. 101 | * 102 | * @return string 103 | * @throws \yii\web\NotFoundHttpException 104 | */ 105 | public function actionRequest() 106 | { 107 | if (!$this->module->enablePasswordRecovery) { 108 | throw new NotFoundHttpException(); 109 | } 110 | 111 | /** @var RecoveryForm $model */ 112 | $model = \Yii::createObject([ 113 | 'class' => RecoveryForm::className(), 114 | 'scenario' => RecoveryForm::SCENARIO_REQUEST, 115 | ]); 116 | $event = $this->getFormEvent($model); 117 | 118 | $this->performAjaxValidation($model); 119 | $this->trigger(self::EVENT_BEFORE_REQUEST, $event); 120 | 121 | if ($model->load(\Yii::$app->request->post()) && $model->sendRecoveryMessage()) { 122 | $this->trigger(self::EVENT_AFTER_REQUEST, $event); 123 | return $this->render('/message', [ 124 | 'title' => \Yii::t('user', 'Recovery message sent'), 125 | 'module' => $this->module, 126 | ]); 127 | } 128 | 129 | return $this->render('request', [ 130 | 'model' => $model, 131 | ]); 132 | } 133 | 134 | /** 135 | * Displays page where user can reset password. 136 | * 137 | * @param int $id 138 | * @param string $code 139 | * 140 | * @return string 141 | * @throws \yii\web\NotFoundHttpException 142 | */ 143 | public function actionReset($id, $code) 144 | { 145 | if (!$this->module->enablePasswordRecovery) { 146 | throw new NotFoundHttpException(); 147 | } 148 | 149 | /** @var Token $token */ 150 | $token = $this->finder->findToken(['user_id' => $id, 'code' => $code, 'type' => Token::TYPE_RECOVERY])->one(); 151 | if (empty($token) || ! $token instanceof Token) { 152 | throw new NotFoundHttpException(); 153 | } 154 | $event = $this->getResetPasswordEvent($token); 155 | 156 | $this->trigger(self::EVENT_BEFORE_TOKEN_VALIDATE, $event); 157 | 158 | if ($token === null || $token->isExpired || $token->user === null) { 159 | $this->trigger(self::EVENT_AFTER_TOKEN_VALIDATE, $event); 160 | \Yii::$app->session->setFlash( 161 | 'danger', 162 | \Yii::t('user', 'Recovery link is invalid or expired. Please try requesting a new one.') 163 | ); 164 | return $this->render('/message', [ 165 | 'title' => \Yii::t('user', 'Invalid or expired link'), 166 | 'module' => $this->module, 167 | ]); 168 | } 169 | 170 | /** @var RecoveryForm $model */ 171 | $model = \Yii::createObject([ 172 | 'class' => RecoveryForm::className(), 173 | 'scenario' => RecoveryForm::SCENARIO_RESET, 174 | ]); 175 | $event->setForm($model); 176 | 177 | $this->performAjaxValidation($model); 178 | $this->trigger(self::EVENT_BEFORE_RESET, $event); 179 | 180 | if ($model->load(\Yii::$app->getRequest()->post()) && $model->resetPassword($token)) { 181 | $this->trigger(self::EVENT_AFTER_RESET, $event); 182 | return $this->render('/message', [ 183 | 'title' => \Yii::t('user', 'Password has been changed'), 184 | 'module' => $this->module, 185 | ]); 186 | } 187 | 188 | return $this->render('reset', [ 189 | 'model' => $model, 190 | ]); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /models/Account.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\clients\ClientInterface; 15 | use dektrium\user\Finder; 16 | use dektrium\user\models\query\AccountQuery; 17 | use dektrium\user\traits\ModuleTrait; 18 | use yii\authclient\ClientInterface as BaseClientInterface; 19 | use yii\db\ActiveRecord; 20 | use yii\helpers\Json; 21 | use yii\helpers\Url; 22 | 23 | /** 24 | * @property integer $id Id 25 | * @property integer $user_id User id, null if account is not bind to user 26 | * @property string $provider Name of service 27 | * @property string $client_id Account id 28 | * @property string $data Account properties returned by social network (json encoded) 29 | * @property string $decodedData Json-decoded properties 30 | * @property string $code 31 | * @property integer $created_at 32 | * @property string $email 33 | * @property string $username 34 | * 35 | * @property User $user User that this account is connected for. 36 | * 37 | * @author Dmitry Erofeev 38 | */ 39 | class Account extends ActiveRecord 40 | { 41 | use ModuleTrait; 42 | 43 | /** @var Finder */ 44 | protected static $finder; 45 | 46 | /** @var */ 47 | private $_data; 48 | 49 | /** @inheritdoc */ 50 | public static function tableName() 51 | { 52 | return '{{%social_account}}'; 53 | } 54 | 55 | /** 56 | * @return User 57 | */ 58 | public function getUser() 59 | { 60 | return $this->hasOne($this->module->modelMap['User'], ['id' => 'user_id']); 61 | } 62 | 63 | /** 64 | * @return bool Whether this social account is connected to user. 65 | */ 66 | public function getIsConnected() 67 | { 68 | return $this->user_id != null; 69 | } 70 | 71 | /** 72 | * @return mixed Json decoded properties. 73 | */ 74 | public function getDecodedData() 75 | { 76 | if ($this->_data == null) { 77 | $this->_data = Json::decode($this->data); 78 | } 79 | 80 | return $this->_data; 81 | } 82 | 83 | /** 84 | * Returns connect url. 85 | * @return string 86 | */ 87 | public function getConnectUrl() 88 | { 89 | $code = \Yii::$app->security->generateRandomString(); 90 | $this->updateAttributes(['code' => md5($code)]); 91 | 92 | return Url::to(['/user/registration/connect', 'code' => $code]); 93 | } 94 | 95 | public function connect(User $user) 96 | { 97 | return $this->updateAttributes([ 98 | 'username' => null, 99 | 'email' => null, 100 | 'code' => null, 101 | 'user_id' => $user->id, 102 | ]); 103 | } 104 | 105 | /** 106 | * @return AccountQuery 107 | */ 108 | public static function find() 109 | { 110 | return \Yii::createObject(AccountQuery::className(), [get_called_class()]); 111 | } 112 | 113 | public static function create(BaseClientInterface $client) 114 | { 115 | /** @var Account $account */ 116 | $account = \Yii::createObject([ 117 | 'class' => static::className(), 118 | 'provider' => $client->getId(), 119 | 'client_id' => $client->getUserAttributes()['id'], 120 | 'data' => Json::encode($client->getUserAttributes()), 121 | ]); 122 | 123 | if ($client instanceof ClientInterface) { 124 | $account->setAttributes([ 125 | 'username' => $client->getUsername(), 126 | 'email' => $client->getEmail(), 127 | ], false); 128 | } 129 | 130 | if (($user = static::fetchUser($account)) instanceof User) { 131 | $account->user_id = $user->id; 132 | } 133 | 134 | $account->save(false); 135 | 136 | return $account; 137 | } 138 | 139 | /** 140 | * Tries to find an account and then connect that account with current user. 141 | * 142 | * @param BaseClientInterface $client 143 | */ 144 | public static function connectWithUser(BaseClientInterface $client) 145 | { 146 | if (\Yii::$app->user->isGuest) { 147 | \Yii::$app->session->setFlash('danger', \Yii::t('user', 'Something went wrong')); 148 | 149 | return; 150 | } 151 | 152 | $account = static::fetchAccount($client); 153 | 154 | if ($account->user === null) { 155 | $account->link('user', \Yii::$app->user->identity); 156 | \Yii::$app->session->setFlash('success', \Yii::t('user', 'Your account has been connected')); 157 | } else { 158 | \Yii::$app->session->setFlash( 159 | 'danger', 160 | \Yii::t('user', 'This account has already been connected to another user') 161 | ); 162 | } 163 | } 164 | 165 | /** 166 | * Tries to find account, otherwise creates new account. 167 | * 168 | * @param BaseClientInterface $client 169 | * 170 | * @return Account 171 | * @throws \yii\base\InvalidConfigException 172 | */ 173 | protected static function fetchAccount(BaseClientInterface $client) 174 | { 175 | $account = static::getFinder()->findAccount()->byClient($client)->one(); 176 | 177 | if (null === $account) { 178 | $account = \Yii::createObject([ 179 | 'class' => static::className(), 180 | 'provider' => $client->getId(), 181 | 'client_id' => $client->getUserAttributes()['id'], 182 | 'data' => Json::encode($client->getUserAttributes()), 183 | ]); 184 | $account->save(false); 185 | } 186 | 187 | return $account; 188 | } 189 | 190 | /** 191 | * Tries to find user or create a new one. 192 | * 193 | * @param Account $account 194 | * 195 | * @return User|bool False when can't create user. 196 | */ 197 | protected static function fetchUser(Account $account) 198 | { 199 | $user = static::getFinder()->findUserByEmail($account->email); 200 | 201 | if (null !== $user) { 202 | return $user; 203 | } 204 | 205 | $user = \Yii::createObject([ 206 | 'class' => User::className(), 207 | 'scenario' => 'connect', 208 | 'username' => $account->username, 209 | 'email' => $account->email, 210 | ]); 211 | 212 | if (!$user->validate(['email'])) { 213 | $account->email = null; 214 | } 215 | 216 | if (!$user->validate(['username'])) { 217 | $account->username = null; 218 | } 219 | 220 | return $user->create() ? $user : false; 221 | } 222 | 223 | /** 224 | * @return Finder 225 | */ 226 | protected static function getFinder() 227 | { 228 | if (static::$finder === null) { 229 | static::$finder = \Yii::$container->get(Finder::className()); 230 | } 231 | 232 | return static::$finder; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /models/SettingsForm.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace dektrium\user\models; 13 | 14 | use dektrium\user\helpers\Password; 15 | use dektrium\user\Mailer; 16 | use dektrium\user\Module; 17 | use dektrium\user\traits\ModuleTrait; 18 | use Yii; 19 | use yii\base\Model; 20 | 21 | /** 22 | * SettingsForm gets user's username, email and password and changes them. 23 | * 24 | * @property User $user 25 | * 26 | * @author Dmitry Erofeev 27 | */ 28 | class SettingsForm extends Model 29 | { 30 | use ModuleTrait; 31 | 32 | /** @var string */ 33 | public $email; 34 | 35 | /** @var string */ 36 | public $username; 37 | 38 | /** @var string */ 39 | public $new_password; 40 | 41 | /** @var string */ 42 | public $current_password; 43 | 44 | /** @var Mailer */ 45 | protected $mailer; 46 | 47 | /** @var User */ 48 | private $_user; 49 | 50 | /** @return User */ 51 | public function getUser() 52 | { 53 | if ($this->_user == null) { 54 | $this->_user = Yii::$app->user->identity; 55 | } 56 | 57 | return $this->_user; 58 | } 59 | 60 | /** @inheritdoc */ 61 | public function __construct(Mailer $mailer, $config = []) 62 | { 63 | $this->mailer = $mailer; 64 | $this->setAttributes([ 65 | 'username' => $this->user->username, 66 | 'email' => $this->user->unconfirmed_email ?: $this->user->email, 67 | ], false); 68 | parent::__construct($config); 69 | } 70 | 71 | /** @inheritdoc */ 72 | public function rules() 73 | { 74 | return [ 75 | 'usernameTrim' => ['username', 'trim'], 76 | 'usernameRequired' => ['username', 'required'], 77 | 'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255], 78 | 'usernamePattern' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@]+$/'], 79 | 'emailTrim' => ['email', 'trim'], 80 | 'emailRequired' => ['email', 'required'], 81 | 'emailPattern' => ['email', 'email'], 82 | 'emailUsernameUnique' => [['email', 'username'], 'unique', 'when' => function ($model, $attribute) { 83 | return $this->user->$attribute != $model->$attribute; 84 | }, 'targetClass' => $this->module->modelMap['User']], 85 | 'newPasswordLength' => ['new_password', 'string', 'max' => 72, 'min' => 6], 86 | 'currentPasswordRequired' => ['current_password', 'required'], 87 | 'currentPasswordValidate' => ['current_password', function ($attr) { 88 | if (!Password::validate($this->$attr, $this->user->password_hash)) { 89 | $this->addError($attr, Yii::t('user', 'Current password is not valid')); 90 | } 91 | }], 92 | ]; 93 | } 94 | 95 | /** @inheritdoc */ 96 | public function attributeLabels() 97 | { 98 | return [ 99 | 'email' => Yii::t('user', 'Email'), 100 | 'username' => Yii::t('user', 'Username'), 101 | 'new_password' => Yii::t('user', 'New password'), 102 | 'current_password' => Yii::t('user', 'Current password'), 103 | ]; 104 | } 105 | 106 | /** @inheritdoc */ 107 | public function formName() 108 | { 109 | return 'settings-form'; 110 | } 111 | 112 | /** 113 | * Saves new account settings. 114 | * 115 | * @return bool 116 | */ 117 | public function save() 118 | { 119 | if ($this->validate()) { 120 | $this->user->scenario = 'settings'; 121 | $this->user->username = $this->username; 122 | $this->user->password = $this->new_password; 123 | if ($this->email == $this->user->email && $this->user->unconfirmed_email != null) { 124 | $this->user->unconfirmed_email = null; 125 | } elseif ($this->email != $this->user->email) { 126 | switch ($this->module->emailChangeStrategy) { 127 | case Module::STRATEGY_INSECURE: 128 | $this->insecureEmailChange(); 129 | break; 130 | case Module::STRATEGY_DEFAULT: 131 | $this->defaultEmailChange(); 132 | break; 133 | case Module::STRATEGY_SECURE: 134 | $this->secureEmailChange(); 135 | break; 136 | default: 137 | throw new \OutOfBoundsException('Invalid email changing strategy'); 138 | } 139 | } 140 | 141 | return $this->user->save(); 142 | } 143 | 144 | return false; 145 | } 146 | 147 | /** 148 | * Changes user's email address to given without any confirmation. 149 | */ 150 | protected function insecureEmailChange() 151 | { 152 | $this->user->email = $this->email; 153 | Yii::$app->session->setFlash('success', Yii::t('user', 'Your email address has been changed')); 154 | } 155 | 156 | /** 157 | * Sends a confirmation message to user's email address with link to confirm changing of email. 158 | */ 159 | protected function defaultEmailChange() 160 | { 161 | $this->user->unconfirmed_email = $this->email; 162 | /** @var Token $token */ 163 | $token = Yii::createObject([ 164 | 'class' => Token::className(), 165 | 'user_id' => $this->user->id, 166 | 'type' => Token::TYPE_CONFIRM_NEW_EMAIL, 167 | ]); 168 | $token->save(false); 169 | $this->mailer->sendReconfirmationMessage($this->user, $token); 170 | Yii::$app->session->setFlash( 171 | 'info', 172 | Yii::t('user', 'A confirmation message has been sent to your new email address') 173 | ); 174 | } 175 | 176 | /** 177 | * Sends a confirmation message to both old and new email addresses with link to confirm changing of email. 178 | * 179 | * @throws \yii\base\InvalidConfigException 180 | */ 181 | protected function secureEmailChange() 182 | { 183 | $this->defaultEmailChange(); 184 | /** @var Token $token */ 185 | $token = Yii::createObject([ 186 | 'class' => Token::className(), 187 | 'user_id' => $this->user->id, 188 | 'type' => Token::TYPE_CONFIRM_OLD_EMAIL, 189 | ]); 190 | $token->save(false); 191 | $this->mailer->sendReconfirmationMessage($this->user, $token); 192 | 193 | // unset flags if they exist 194 | $this->user->flags &= ~User::NEW_EMAIL_CONFIRMED; 195 | $this->user->flags &= ~User::OLD_EMAIL_CONFIRMED; 196 | $this->user->save(false); 197 | 198 | Yii::$app->session->setFlash( 199 | 'info', 200 | Yii::t( 201 | 'user', 202 | 'We have sent confirmation links to both old and new email addresses. You must click both links to complete your request' 203 | ) 204 | ); 205 | } 206 | } 207 | --------------------------------------------------------------------------------