├── .bowerrc ├── .gitignore ├── LICENSE.md ├── README.md ├── backend ├── assets │ └── AppAsset.php ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── main.php │ └── params.php ├── controllers │ └── SiteController.php ├── models │ └── .gitkeep ├── runtime │ └── .gitignore ├── views │ ├── layouts │ │ └── main.php │ └── site │ │ ├── error.php │ │ ├── index.php │ │ └── login.php └── web │ ├── .gitignore │ ├── assets │ └── .gitignore │ ├── css │ └── site.css │ ├── favicon.ico │ └── robots.txt ├── common ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── main.php │ └── params.php ├── mail │ ├── layouts │ │ ├── html.php │ │ └── text.php │ ├── passwordResetToken-html.php │ └── passwordResetToken-text.php └── models │ ├── LoginForm.php │ └── User.php ├── composer.json ├── composer.lock ├── console ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── main.php │ └── params.php ├── controllers │ └── .gitkeep ├── migrations │ └── m130524_201442_init.php ├── models │ └── .gitkeep └── runtime │ └── .gitignore ├── db └── users.db ├── environments ├── dev │ ├── backend │ │ ├── config │ │ │ ├── main-local.php │ │ │ └── params-local.php │ │ └── web │ │ │ ├── index-test.php │ │ │ └── index.php │ ├── common │ │ └── config │ │ │ ├── main-local.php │ │ │ └── params-local.php │ ├── console │ │ └── config │ │ │ ├── main-local.php │ │ │ └── params-local.php │ ├── frontend │ │ ├── config │ │ │ ├── main-local.php │ │ │ └── params-local.php │ │ └── web │ │ │ ├── index-test.php │ │ │ └── index.php │ └── yii ├── index.php └── prod │ ├── backend │ ├── config │ │ ├── main-local.php │ │ └── params-local.php │ └── web │ │ └── index.php │ ├── common │ └── config │ │ ├── main-local.php │ │ └── params-local.php │ ├── console │ └── config │ │ ├── main-local.php │ │ └── params-local.php │ ├── frontend │ ├── config │ │ ├── main-local.php │ │ └── params-local.php │ └── web │ │ └── index.php │ └── yii ├── frontend ├── assets │ ├── AngularAsset.php │ └── AppAsset.php ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── main.php │ └── params.php ├── controllers │ ├── ApiController.php │ └── SiteController.php ├── models │ ├── ContactForm.php │ ├── PasswordResetRequestForm.php │ ├── ResetPasswordForm.php │ └── SignupForm.php ├── runtime │ └── .gitignore ├── views │ ├── layouts │ │ └── main.php │ └── site │ │ └── error.php └── web │ ├── .gitignore │ ├── .htaccess │ ├── assets │ └── .gitignore │ ├── css │ └── site.css │ ├── favicon.ico │ ├── js │ ├── app.js │ └── controllers.js │ ├── partials │ ├── 404.html │ ├── about.html │ ├── contact.html │ ├── dashboard.html │ ├── index.html │ └── login.html │ └── robots.txt ├── init ├── init.bat ├── requirements.php ├── tests ├── README.md ├── codeception.yml └── codeception │ ├── _output │ └── .gitignore │ ├── backend │ ├── .gitignore │ ├── _bootstrap.php │ ├── _output │ │ └── .gitignore │ ├── acceptance.suite.yml │ ├── acceptance │ │ ├── LoginCept.php │ │ └── _bootstrap.php │ ├── codeception.yml │ ├── functional.suite.yml │ ├── functional │ │ ├── LoginCept.php │ │ └── _bootstrap.php │ ├── unit.suite.yml │ └── unit │ │ ├── DbTestCase.php │ │ ├── TestCase.php │ │ ├── _bootstrap.php │ │ └── fixtures │ │ └── data │ │ └── .gitkeep │ ├── bin │ ├── _bootstrap.php │ ├── yii │ └── yii.bat │ ├── common │ ├── .gitignore │ ├── _bootstrap.php │ ├── _output │ │ └── .gitignore │ ├── _pages │ │ └── LoginPage.php │ ├── _support │ │ └── FixtureHelper.php │ ├── codeception.yml │ ├── fixtures │ │ ├── UserFixture.php │ │ └── data │ │ │ └── init_login.php │ ├── templates │ │ └── fixtures │ │ │ └── user.php │ ├── unit.suite.yml │ └── unit │ │ ├── DbTestCase.php │ │ ├── TestCase.php │ │ ├── _bootstrap.php │ │ ├── fixtures │ │ └── data │ │ │ └── models │ │ │ └── user.php │ │ └── models │ │ └── LoginFormTest.php │ ├── config │ ├── acceptance.php │ ├── backend │ │ ├── acceptance.php │ │ ├── config.php │ │ ├── functional.php │ │ └── unit.php │ ├── common │ │ └── unit.php │ ├── config.php │ ├── console │ │ └── unit.php │ ├── frontend │ │ ├── acceptance.php │ │ ├── config.php │ │ ├── functional.php │ │ └── unit.php │ ├── functional.php │ └── unit.php │ ├── console │ ├── .gitignore │ ├── _bootstrap.php │ ├── _output │ │ └── .gitignore │ ├── codeception.yml │ ├── unit.suite.yml │ └── unit │ │ ├── DbTestCase.php │ │ ├── TestCase.php │ │ ├── _bootstrap.php │ │ └── fixtures │ │ └── data │ │ └── .gitkeep │ └── frontend │ ├── .gitignore │ ├── _bootstrap.php │ ├── _output │ └── .gitignore │ ├── _pages │ ├── AboutPage.php │ ├── ContactPage.php │ └── SignupPage.php │ ├── acceptance.suite.yml │ ├── acceptance │ ├── AboutCept.php │ ├── ContactCept.php │ ├── HomeCept.php │ ├── LoginCept.php │ ├── SignupCest.php │ └── _bootstrap.php │ ├── codeception.yml │ ├── functional.suite.yml │ ├── functional │ ├── AboutCept.php │ ├── ContactCept.php │ ├── HomeCept.php │ ├── LoginCept.php │ ├── SignupCest.php │ └── _bootstrap.php │ ├── unit.suite.yml │ └── unit │ ├── DbTestCase.php │ ├── TestCase.php │ ├── _bootstrap.php │ ├── fixtures │ └── data │ │ └── models │ │ └── user.php │ └── models │ ├── ContactFormTest.php │ ├── PasswordResetRequestFormTest.php │ ├── ResetPasswordFormTest.php │ └── SignupFormTest.php └── yii.bat /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory" : "vendor/bower" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # yii console command 2 | /yii 3 | 4 | # phpstorm project files 5 | .idea 6 | 7 | # netbeans project files 8 | nbproject 9 | 10 | # zend studio for eclipse project files 11 | .buildpath 12 | .project 13 | .settings 14 | 15 | # windows thumbnail cache 16 | Thumbs.db 17 | 18 | # composer vendor dir 19 | /vendor 20 | 21 | # composer itself is not needed 22 | composer.phar 23 | 24 | # Mac DS_Store Files 25 | .DS_Store 26 | 27 | # phpunit itself is not needed 28 | phpunit.phar 29 | # local phpunit config 30 | /phpunit.xml 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The Yii framework is free software. It is released under the terms of 2 | the following BSD License. 3 | 4 | Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | * Neither the name of Yii Software LLC nor the names of its 18 | contributors may be used to endorse or promote products derived 19 | from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AngularJS and Yii2 Part 2: Authentication 2 | ================================ 3 | 4 | If you're planning on running these on your server don't forget to: 5 | ~~~ 6 | php composer.phar install 7 | ~~~ 8 | and initialize the environment 9 | ~~~ 10 | php init 11 | ~~~ 12 | 13 | The tutorial is located here [Neat Tutorials](http://blog.neattutorials.com/angularjs-and-yii2-part-2-authentication/) 14 | -------------------------------------------------------------------------------- /backend/assets/AppAsset.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 2.0 15 | */ 16 | class AppAsset extends AssetBundle 17 | { 18 | public $basePath = '@webroot'; 19 | public $baseUrl = '@web'; 20 | public $css = [ 21 | 'css/site.css', 22 | ]; 23 | public $js = [ 24 | ]; 25 | public $depends = [ 26 | 'yii\web\YiiAsset', 27 | 'yii\bootstrap\BootstrapAsset', 28 | ]; 29 | } 30 | -------------------------------------------------------------------------------- /backend/config/.gitignore: -------------------------------------------------------------------------------- 1 | main-local.php 2 | params-local.php -------------------------------------------------------------------------------- /backend/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | 'app-backend', 11 | 'basePath' => dirname(__DIR__), 12 | 'controllerNamespace' => 'backend\controllers', 13 | 'bootstrap' => ['log'], 14 | 'modules' => [], 15 | 'components' => [ 16 | 'user' => [ 17 | 'identityClass' => 'common\models\User', 18 | 'enableAutoLogin' => true, 19 | ], 20 | 'log' => [ 21 | 'traceLevel' => YII_DEBUG ? 3 : 0, 22 | 'targets' => [ 23 | [ 24 | 'class' => 'yii\log\FileTarget', 25 | 'levels' => ['error', 'warning'], 26 | ], 27 | ], 28 | ], 29 | 'errorHandler' => [ 30 | 'errorAction' => 'site/error', 31 | ], 32 | ], 33 | 'params' => $params, 34 | ]; 35 | -------------------------------------------------------------------------------- /backend/config/params.php: -------------------------------------------------------------------------------- 1 | 'admin@example.com', 4 | ]; 5 | -------------------------------------------------------------------------------- /backend/controllers/SiteController.php: -------------------------------------------------------------------------------- 1 | [ 22 | 'class' => AccessControl::className(), 23 | 'rules' => [ 24 | [ 25 | 'actions' => ['login', 'error'], 26 | 'allow' => true, 27 | ], 28 | [ 29 | 'actions' => ['logout', 'index'], 30 | 'allow' => true, 31 | 'roles' => ['@'], 32 | ], 33 | ], 34 | ], 35 | 'verbs' => [ 36 | 'class' => VerbFilter::className(), 37 | 'actions' => [ 38 | 'logout' => ['post'], 39 | ], 40 | ], 41 | ]; 42 | } 43 | 44 | /** 45 | * @inheritdoc 46 | */ 47 | public function actions() 48 | { 49 | return [ 50 | 'error' => [ 51 | 'class' => 'yii\web\ErrorAction', 52 | ], 53 | ]; 54 | } 55 | 56 | public function actionIndex() 57 | { 58 | return $this->render('index'); 59 | } 60 | 61 | public function actionLogin() 62 | { 63 | if (!\Yii::$app->user->isGuest) { 64 | return $this->goHome(); 65 | } 66 | 67 | $model = new LoginForm(); 68 | if ($model->load(Yii::$app->request->post()) && $model->login()) { 69 | return $this->goBack(); 70 | } else { 71 | return $this->render('login', [ 72 | 'model' => $model, 73 | ]); 74 | } 75 | } 76 | 77 | public function actionLogout() 78 | { 79 | Yii::$app->user->logout(); 80 | 81 | return $this->goHome(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /backend/models/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /backend/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /backend/views/layouts/main.php: -------------------------------------------------------------------------------- 1 | 13 | beginPage() ?> 14 | 15 | 16 | 17 | 18 | 19 | 20 | <?= Html::encode($this->title) ?> 21 | head() ?> 22 | 23 | 24 | beginBody() ?> 25 |
26 | 'My Company', 29 | 'brandUrl' => Yii::$app->homeUrl, 30 | 'options' => [ 31 | 'class' => 'navbar-inverse navbar-fixed-top', 32 | ], 33 | ]); 34 | $menuItems = [ 35 | ['label' => 'Home', 'url' => ['/site/index']], 36 | ]; 37 | if (Yii::$app->user->isGuest) { 38 | $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; 39 | } else { 40 | $menuItems[] = [ 41 | 'label' => 'Logout (' . Yii::$app->user->identity->username . ')', 42 | 'url' => ['/site/logout'], 43 | 'linkOptions' => ['data-method' => 'post'] 44 | ]; 45 | } 46 | echo Nav::widget([ 47 | 'options' => ['class' => 'navbar-nav navbar-right'], 48 | 'items' => $menuItems, 49 | ]); 50 | NavBar::end(); 51 | ?> 52 | 53 |
54 | isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], 56 | ]) ?> 57 | 58 |
59 |
60 | 61 | 67 | 68 | endBody() ?> 69 | 70 | 71 | endPage() ?> 72 | -------------------------------------------------------------------------------- /backend/views/site/error.php: -------------------------------------------------------------------------------- 1 | title = $name; 11 | ?> 12 |
13 | 14 |

title) ?>

15 | 16 |
17 | 18 |
19 | 20 |

21 | The above error occurred while the Web server was processing your request. 22 |

23 |

24 | Please contact us if you think this is a server error. Thank you. 25 |

26 | 27 |
28 | -------------------------------------------------------------------------------- /backend/views/site/index.php: -------------------------------------------------------------------------------- 1 | title = 'My Yii Application'; 5 | ?> 6 |
7 | 8 |
9 |

Congratulations!

10 | 11 |

You have successfully created your Yii-powered application.

12 | 13 |

Get started with Yii

14 |
15 | 16 |
17 | 18 |
19 |
20 |

Heading

21 | 22 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 23 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 24 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 25 | fugiat nulla pariatur.

26 | 27 |

Yii Documentation »

28 |
29 |
30 |

Heading

31 | 32 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 33 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 34 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 35 | fugiat nulla pariatur.

36 | 37 |

Yii Forum »

38 |
39 |
40 |

Heading

41 | 42 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 43 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 44 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 45 | fugiat nulla pariatur.

46 | 47 |

Yii Extensions »

48 |
49 |
50 | 51 |
52 |
53 | -------------------------------------------------------------------------------- /backend/views/site/login.php: -------------------------------------------------------------------------------- 1 | title = 'Login'; 10 | $this->params['breadcrumbs'][] = $this->title; 11 | ?> 12 |
13 |

title) ?>

14 | 15 |

Please fill out the following fields to login:

16 | 17 |
18 |
19 | 'login-form']); ?> 20 | field($model, 'username') ?> 21 | field($model, 'password')->passwordInput() ?> 22 | field($model, 'rememberMe')->checkbox() ?> 23 |
24 | 'btn btn-primary', 'name' => 'login-button']) ?> 25 |
26 | 27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /backend/web/.gitignore: -------------------------------------------------------------------------------- 1 | /index.php 2 | /index-test.php 3 | -------------------------------------------------------------------------------- /backend/web/assets/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/web/css/site.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | .wrap { 7 | min-height: 100%; 8 | height: auto; 9 | margin: 0 auto -60px; 10 | padding: 0 0 60px; 11 | } 12 | 13 | .wrap > .container { 14 | padding: 70px 15px 20px; 15 | } 16 | 17 | .footer { 18 | height: 60px; 19 | background-color: #f5f5f5; 20 | border-top: 1px solid #ddd; 21 | padding-top: 20px; 22 | } 23 | 24 | .jumbotron { 25 | text-align: center; 26 | background-color: transparent; 27 | } 28 | 29 | .jumbotron .btn { 30 | font-size: 21px; 31 | padding: 14px 24px; 32 | } 33 | 34 | .not-set { 35 | color: #c55; 36 | font-style: italic; 37 | } 38 | 39 | /* add sorting icons to gridview sort links */ 40 | a.asc:after, a.desc:after { 41 | position: relative; 42 | top: 1px; 43 | display: inline-block; 44 | font-family: 'Glyphicons Halflings'; 45 | font-style: normal; 46 | font-weight: normal; 47 | line-height: 1; 48 | padding-left: 5px; 49 | } 50 | 51 | a.asc:after { 52 | content: /*"\e113"*/ "\e151"; 53 | } 54 | 55 | a.desc:after { 56 | content: /*"\e114"*/ "\e152"; 57 | } 58 | 59 | .sort-numerical a.asc:after { 60 | content: "\e153"; 61 | } 62 | 63 | .sort-numerical a.desc:after { 64 | content: "\e154"; 65 | } 66 | 67 | .sort-ordinal a.asc:after { 68 | content: "\e155"; 69 | } 70 | 71 | .sort-ordinal a.desc:after { 72 | content: "\e156"; 73 | } 74 | 75 | .grid-view th { 76 | white-space: nowrap; 77 | } 78 | 79 | .hint-block { 80 | display: block; 81 | margin-top: 5px; 82 | color: #999; 83 | } 84 | 85 | .error-summary { 86 | color: #a94442; 87 | background: #fdf7f7; 88 | border-left: 3px solid #eed3d7; 89 | padding: 10px 20px; 90 | margin: 0 0 15px 0; 91 | } 92 | -------------------------------------------------------------------------------- /backend/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neattutorials/angularjs-yii2-part-2-authentication/726353f9a475c61da3a53fce0afe120c841ccf3a/backend/web/favicon.ico -------------------------------------------------------------------------------- /backend/web/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /common/config/.gitignore: -------------------------------------------------------------------------------- 1 | main-local.php 2 | params-local.php 3 | -------------------------------------------------------------------------------- /common/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | dirname(dirname(__DIR__)) . '/vendor', 4 | 'components' => [ 5 | 'cache' => [ 6 | 'class' => 'yii\caching\FileCache', 7 | ], 8 | ], 9 | ]; 10 | -------------------------------------------------------------------------------- /common/config/params.php: -------------------------------------------------------------------------------- 1 | 'admin@example.com', 4 | 'supportEmail' => 'support@example.com', 5 | 'user.passwordResetTokenExpire' => 3600, 6 | ]; 7 | -------------------------------------------------------------------------------- /common/mail/layouts/html.php: -------------------------------------------------------------------------------- 1 | 8 | beginPage() ?> 9 | 10 | 11 | 12 | 13 | <?= Html::encode($this->title) ?> 14 | head() ?> 15 | 16 | 17 | beginBody() ?> 18 | 19 | endBody() ?> 20 | 21 | 22 | endPage() ?> 23 | -------------------------------------------------------------------------------- /common/mail/layouts/text.php: -------------------------------------------------------------------------------- 1 | 8 | beginPage() ?> 9 | beginBody() ?> 10 | 11 | endBody() ?> 12 | endPage() ?> 13 | -------------------------------------------------------------------------------- /common/mail/passwordResetToken-html.php: -------------------------------------------------------------------------------- 1 | urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); 8 | ?> 9 |
10 |

Hello username) ?>,

11 | 12 |

Follow the link below to reset your password:

13 | 14 |

15 |
16 | -------------------------------------------------------------------------------- /common/mail/passwordResetToken-text.php: -------------------------------------------------------------------------------- 1 | urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); 7 | ?> 8 | Hello username ?>, 9 | 10 | Follow the link below to reset your password: 11 | 12 | 13 | -------------------------------------------------------------------------------- /common/models/LoginForm.php: -------------------------------------------------------------------------------- 1 | hasErrors()) { 44 | $user = $this->getUser(); 45 | if (!$user || !$user->validatePassword($this->password)) { 46 | $this->addError($attribute, 'Incorrect username or password.'); 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * Logs in a user using the provided username and password. 53 | * 54 | * @return boolean whether the user is logged in successfully 55 | */ 56 | public function login() 57 | { 58 | if ($this->validate()) { 59 | return Yii::$app->user->login($this->getUser()/*, $this->rememberMe ? 3600 * 24 * 30 : 0*/); 60 | } else { 61 | return false; 62 | } 63 | } 64 | 65 | /** 66 | * Finds user by [[username]] 67 | * 68 | * @return User|null 69 | */ 70 | public function getUser() 71 | { 72 | if ($this->_user === false) { 73 | $this->_user = User::findByUsername($this->username); 74 | } 75 | 76 | return $this->_user; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /common/models/User.php: -------------------------------------------------------------------------------- 1 | self::STATUS_ACTIVE], 54 | ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], 55 | ]; 56 | } 57 | 58 | /** 59 | * @inheritdoc 60 | */ 61 | public static function findIdentity($id) 62 | { 63 | return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); 64 | } 65 | 66 | /** 67 | * @inheritdoc 68 | */ 69 | public static function findIdentityByAccessToken($token, $type = null) 70 | { 71 | return static::findOne(['auth_key' => $token]); 72 | } 73 | 74 | /** 75 | * Finds user by username 76 | * 77 | * @param string $username 78 | * @return static|null 79 | */ 80 | public static function findByUsername($username) 81 | { 82 | return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]); 83 | } 84 | 85 | /** 86 | * Finds user by password reset token 87 | * 88 | * @param string $token password reset token 89 | * @return static|null 90 | */ 91 | public static function findByPasswordResetToken($token) 92 | { 93 | if (!static::isPasswordResetTokenValid($token)) { 94 | return null; 95 | } 96 | 97 | return static::findOne([ 98 | 'password_reset_token' => $token, 99 | 'status' => self::STATUS_ACTIVE, 100 | ]); 101 | } 102 | 103 | /** 104 | * Finds out if password reset token is valid 105 | * 106 | * @param string $token password reset token 107 | * @return boolean 108 | */ 109 | public static function isPasswordResetTokenValid($token) 110 | { 111 | if (empty($token)) { 112 | return false; 113 | } 114 | $expire = Yii::$app->params['user.passwordResetTokenExpire']; 115 | $parts = explode('_', $token); 116 | $timestamp = (int) end($parts); 117 | return $timestamp + $expire >= time(); 118 | } 119 | 120 | /** 121 | * @inheritdoc 122 | */ 123 | public function getId() 124 | { 125 | return $this->getPrimaryKey(); 126 | } 127 | 128 | /** 129 | * @inheritdoc 130 | */ 131 | public function getAuthKey() 132 | { 133 | return $this->auth_key; 134 | } 135 | 136 | /** 137 | * @inheritdoc 138 | */ 139 | public function validateAuthKey($authKey) 140 | { 141 | return $this->getAuthKey() === $authKey; 142 | } 143 | 144 | /** 145 | * Validates password 146 | * 147 | * @param string $password password to validate 148 | * @return boolean if password provided is valid for current user 149 | */ 150 | public function validatePassword($password) 151 | { 152 | return Yii::$app->security->validatePassword($password, $this->password_hash); 153 | } 154 | 155 | /** 156 | * Generates password hash from password and sets it to the model 157 | * 158 | * @param string $password 159 | */ 160 | public function setPassword($password) 161 | { 162 | $this->password_hash = Yii::$app->security->generatePasswordHash($password); 163 | } 164 | 165 | /** 166 | * Generates "remember me" authentication key 167 | */ 168 | public function generateAuthKey() 169 | { 170 | $this->auth_key = Yii::$app->security->generateRandomString(); 171 | } 172 | 173 | /** 174 | * Generates new password reset token 175 | */ 176 | public function generatePasswordResetToken() 177 | { 178 | $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); 179 | } 180 | 181 | /** 182 | * Removes password reset token 183 | */ 184 | public function removePasswordResetToken() 185 | { 186 | $this->password_reset_token = null; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yiisoft/yii2-app-advanced", 3 | "description": "Yii 2 Advanced Application Template", 4 | "keywords": ["yii2", "framework", "advanced", "application template"], 5 | "homepage": "http://www.yiiframework.com/", 6 | "type": "project", 7 | "license": "BSD-3-Clause", 8 | "support": { 9 | "issues": "https://github.com/yiisoft/yii2/issues?state=open", 10 | "forum": "http://www.yiiframework.com/forum/", 11 | "wiki": "http://www.yiiframework.com/wiki/", 12 | "irc": "irc://irc.freenode.net/yii", 13 | "source": "https://github.com/yiisoft/yii2" 14 | }, 15 | "minimum-stability": "stable", 16 | "require": { 17 | "php": ">=5.4.0", 18 | "yiisoft/yii2": "*", 19 | "yiisoft/yii2-bootstrap": "*", 20 | "yiisoft/yii2-swiftmailer": "*", 21 | "bower-asset/angular": "*", 22 | "bower-asset/angular-route": "*", 23 | "bower-asset/angular-strap": "*" 24 | 25 | }, 26 | "require-dev": { 27 | "yiisoft/yii2-codeception": "*", 28 | "yiisoft/yii2-debug": "*", 29 | "yiisoft/yii2-gii": "*", 30 | "yiisoft/yii2-faker": "*" 31 | }, 32 | "config": { 33 | "process-timeout": 1800 34 | }, 35 | "extra": { 36 | "asset-installer-paths": { 37 | "npm-asset-library": "vendor/npm", 38 | "bower-asset-library": "vendor/bower" 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "71736ffee996c56eeff126dbefbfe013", 8 | "packages": [ 9 | { 10 | "name": "bower-asset/angular", 11 | "version": "v1.3.15", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/angular/bower-angular.git", 15 | "reference": "ba7abcfa409ba852146e6ba206693cf7bac3e359" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/angular/bower-angular/zipball/ba7abcfa409ba852146e6ba206693cf7bac3e359", 20 | "reference": "ba7abcfa409ba852146e6ba206693cf7bac3e359", 21 | "shasum": "" 22 | }, 23 | "type": "bower-asset-library", 24 | "extra": { 25 | "bower-asset-main": "./angular.js", 26 | "bower-asset-ignore": [] 27 | } 28 | }, 29 | { 30 | "name": "bower-asset/angular-cookies", 31 | "version": "v1.3.15", 32 | "source": { 33 | "type": "git", 34 | "url": "https://github.com/angular/bower-angular-cookies.git", 35 | "reference": "846700fd8e45eefa1a43cf1865bcb7aaf95a68e0" 36 | }, 37 | "dist": { 38 | "type": "zip", 39 | "url": "https://api.github.com/repos/angular/bower-angular-cookies/zipball/846700fd8e45eefa1a43cf1865bcb7aaf95a68e0", 40 | "reference": "846700fd8e45eefa1a43cf1865bcb7aaf95a68e0", 41 | "shasum": "" 42 | }, 43 | "require": { 44 | "bower-asset/angular": "1.3.15" 45 | }, 46 | "type": "bower-asset-library", 47 | "extra": { 48 | "bower-asset-main": "./angular-cookies.js", 49 | "bower-asset-ignore": [] 50 | } 51 | }, 52 | { 53 | "name": "bower-asset/angular-route", 54 | "version": "v1.3.15", 55 | "source": { 56 | "type": "git", 57 | "url": "https://github.com/angular/bower-angular-route.git", 58 | "reference": "1f6e6ac94e20b98bca10155363042411f7729ce2" 59 | }, 60 | "dist": { 61 | "type": "zip", 62 | "url": "https://api.github.com/repos/angular/bower-angular-route/zipball/1f6e6ac94e20b98bca10155363042411f7729ce2", 63 | "reference": "1f6e6ac94e20b98bca10155363042411f7729ce2", 64 | "shasum": "" 65 | }, 66 | "require": { 67 | "bower-asset/angular": "1.3.15" 68 | }, 69 | "type": "bower-asset-library", 70 | "extra": { 71 | "bower-asset-main": "./angular-route.js", 72 | "bower-asset-ignore": [] 73 | } 74 | }, 75 | { 76 | "name": "bower-asset/angular-strap", 77 | "version": "v2.2.1", 78 | "source": { 79 | "type": "git", 80 | "url": "https://github.com/mgcrea/angular-strap.git", 81 | "reference": "206fd5b73dc012b8886fc4a2b8e4a62389d3af45" 82 | }, 83 | "dist": { 84 | "type": "zip", 85 | "url": "https://api.github.com/repos/mgcrea/angular-strap/zipball/206fd5b73dc012b8886fc4a2b8e4a62389d3af45", 86 | "reference": "206fd5b73dc012b8886fc4a2b8e4a62389d3af45", 87 | "shasum": "" 88 | }, 89 | "require": { 90 | "bower-asset/angular": ">=1.2.21,<2.0.0" 91 | }, 92 | "require-dev": { 93 | "bower-asset/angular-animate": ">=1.2.21,<2.0.0", 94 | "bower-asset/angular-i18n": ">=1.2.21,<2.0.0", 95 | "bower-asset/angular-mocks": ">=1.2.21,<2.0.0", 96 | "bower-asset/angular-motion": ">=0.3.3,<0.4.0", 97 | "bower-asset/angular-route": ">=1.2.21,<2.0.0", 98 | "bower-asset/angular-sanitize": ">=1.2.21,<2.0.0", 99 | "bower-asset/angular-scenario": ">=1.2.21,<2.0.0", 100 | "bower-asset/bootstrap": ">=3.2.0,<4.0.0", 101 | "bower-asset/bootstrap-additions": ">=0.2.3,<0.3.0", 102 | "bower-asset/fastclick": ">=1.0.3,<2.0.0", 103 | "bower-asset/font-awesome": ">=4.1.0,<5.0.0", 104 | "bower-asset/highlightjs": ">=8.0.0,<9.0.0", 105 | "bower-asset/jquery": ">=2.1.1,<3.0.0" 106 | }, 107 | "type": "bower-asset-library", 108 | "extra": { 109 | "bower-asset-main": [ 110 | "dist/angular-strap.js", 111 | "dist/angular-strap.tpl.js" 112 | ], 113 | "bower-asset-ignore": [ 114 | "docs", 115 | "test", 116 | "CONTRIBUTING.md" 117 | ] 118 | }, 119 | "description": "AngularStrap - AngularJS directives for Bootstrap", 120 | "keywords": [ 121 | "angular", 122 | "bootstrap" 123 | ] 124 | }, 125 | { 126 | "name": "bower-asset/bootstrap", 127 | "version": "v3.3.4", 128 | "source": { 129 | "type": "git", 130 | "url": "https://github.com/twbs/bootstrap.git", 131 | "reference": "a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f" 132 | }, 133 | "dist": { 134 | "type": "zip", 135 | "url": "https://api.github.com/repos/twbs/bootstrap/zipball/a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f", 136 | "reference": "a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f", 137 | "shasum": "" 138 | }, 139 | "require": { 140 | "bower-asset/jquery": ">=1.9.1" 141 | }, 142 | "type": "bower-asset-library", 143 | "extra": { 144 | "bower-asset-main": [ 145 | "less/bootstrap.less", 146 | "dist/css/bootstrap.css", 147 | "dist/js/bootstrap.js", 148 | "dist/fonts/glyphicons-halflings-regular.eot", 149 | "dist/fonts/glyphicons-halflings-regular.svg", 150 | "dist/fonts/glyphicons-halflings-regular.ttf", 151 | "dist/fonts/glyphicons-halflings-regular.woff", 152 | "dist/fonts/glyphicons-halflings-regular.woff2" 153 | ], 154 | "bower-asset-ignore": [ 155 | "/.*", 156 | "_config.yml", 157 | "CNAME", 158 | "composer.json", 159 | "CONTRIBUTING.md", 160 | "docs", 161 | "js/tests", 162 | "test-infra" 163 | ] 164 | }, 165 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 166 | "keywords": [ 167 | "css", 168 | "framework", 169 | "front-end", 170 | "js", 171 | "less", 172 | "mobile-first", 173 | "responsive", 174 | "web" 175 | ] 176 | }, 177 | { 178 | "name": "bower-asset/jquery", 179 | "version": "2.1.3", 180 | "source": { 181 | "type": "git", 182 | "url": "https://github.com/jquery/jquery.git", 183 | "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0" 184 | }, 185 | "dist": { 186 | "type": "zip", 187 | "url": "https://api.github.com/repos/jquery/jquery/zipball/8f2a9d9272d6ed7f32d3a484740ab342c02541e0", 188 | "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0", 189 | "shasum": "" 190 | }, 191 | "require-dev": { 192 | "bower-asset/qunit": "1.14.0", 193 | "bower-asset/requirejs": "2.1.10", 194 | "bower-asset/sinon": "1.8.1", 195 | "bower-asset/sizzle": "2.1.1-patch2" 196 | }, 197 | "type": "bower-asset-library", 198 | "extra": { 199 | "bower-asset-main": "dist/jquery.js", 200 | "bower-asset-ignore": [ 201 | "**/.*", 202 | "build", 203 | "speed", 204 | "test", 205 | "*.md", 206 | "AUTHORS.txt", 207 | "Gruntfile.js", 208 | "package.json" 209 | ] 210 | }, 211 | "license": [ 212 | "MIT" 213 | ], 214 | "keywords": [ 215 | "javascript", 216 | "jquery", 217 | "library" 218 | ] 219 | }, 220 | { 221 | "name": "bower-asset/jquery.inputmask", 222 | "version": "3.1.62", 223 | "source": { 224 | "type": "git", 225 | "url": "https://github.com/RobinHerbots/jquery.inputmask.git", 226 | "reference": "da1a274cefa18a52a0519ac7ffe8e8d31e950eae" 227 | }, 228 | "dist": { 229 | "type": "zip", 230 | "url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/da1a274cefa18a52a0519ac7ffe8e8d31e950eae", 231 | "reference": "da1a274cefa18a52a0519ac7ffe8e8d31e950eae", 232 | "shasum": "" 233 | }, 234 | "require": { 235 | "bower-asset/jquery": ">=1.7" 236 | }, 237 | "type": "bower-asset-library", 238 | "extra": { 239 | "bower-asset-main": [ 240 | "./dist/inputmask/jquery.inputmask.js", 241 | "./dist/inputmask/jquery.inputmask.extensions.js", 242 | "./dist/inputmask/jquery.inputmask.date.extensions.js", 243 | "./dist/inputmask/jquery.inputmask.numeric.extensions.js", 244 | "./dist/inputmask/jquery.inputmask.phone.extensions.js", 245 | "./dist/inputmask/jquery.inputmask.regex.extensions.js" 246 | ], 247 | "bower-asset-ignore": [ 248 | "**/.*", 249 | "qunit/", 250 | "nuget/", 251 | "tools/", 252 | "js/", 253 | "*.md", 254 | "build.properties", 255 | "build.xml", 256 | "jquery.inputmask.jquery.json" 257 | ] 258 | }, 259 | "license": [ 260 | "http://opensource.org/licenses/mit-license.php" 261 | ], 262 | "description": "jquery.inputmask is a jquery plugin which create an input mask.", 263 | "keywords": [ 264 | "form", 265 | "input", 266 | "inputmask", 267 | "jquery", 268 | "mask", 269 | "plugins" 270 | ] 271 | }, 272 | { 273 | "name": "bower-asset/punycode", 274 | "version": "v1.3.2", 275 | "source": { 276 | "type": "git", 277 | "url": "https://github.com/bestiejs/punycode.js.git", 278 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" 279 | }, 280 | "dist": { 281 | "type": "zip", 282 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", 283 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", 284 | "shasum": "" 285 | }, 286 | "type": "bower-asset-library", 287 | "extra": { 288 | "bower-asset-main": "punycode.js", 289 | "bower-asset-ignore": [ 290 | "coverage", 291 | "tests", 292 | ".*", 293 | "component.json", 294 | "Gruntfile.js", 295 | "node_modules", 296 | "package.json" 297 | ] 298 | } 299 | }, 300 | { 301 | "name": "bower-asset/yii2-pjax", 302 | "version": "v2.0.4", 303 | "source": { 304 | "type": "git", 305 | "url": "https://github.com/yiisoft/jquery-pjax.git", 306 | "reference": "3f20897307cca046fca5323b318475ae9dac0ca0" 307 | }, 308 | "dist": { 309 | "type": "zip", 310 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/3f20897307cca046fca5323b318475ae9dac0ca0", 311 | "reference": "3f20897307cca046fca5323b318475ae9dac0ca0", 312 | "shasum": "" 313 | }, 314 | "require": { 315 | "bower-asset/jquery": ">=1.8" 316 | }, 317 | "type": "bower-asset-library", 318 | "extra": { 319 | "bower-asset-main": "./jquery.pjax.js", 320 | "bower-asset-ignore": [ 321 | ".travis.yml", 322 | "Gemfile", 323 | "Gemfile.lock", 324 | "vendor/", 325 | "script/", 326 | "test/" 327 | ] 328 | }, 329 | "license": [ 330 | "MIT" 331 | ] 332 | }, 333 | { 334 | "name": "cebe/markdown", 335 | "version": "1.0.2", 336 | "source": { 337 | "type": "git", 338 | "url": "https://github.com/cebe/markdown.git", 339 | "reference": "f681fee8303310415b746f3758eeda0a7ad08bda" 340 | }, 341 | "dist": { 342 | "type": "zip", 343 | "url": "https://api.github.com/repos/cebe/markdown/zipball/f681fee8303310415b746f3758eeda0a7ad08bda", 344 | "reference": "f681fee8303310415b746f3758eeda0a7ad08bda", 345 | "shasum": "" 346 | }, 347 | "require": { 348 | "lib-pcre": "*", 349 | "php": ">=5.4.0" 350 | }, 351 | "require-dev": { 352 | "cebe/indent": "*", 353 | "facebook/xhprof": "*@dev", 354 | "phpunit/phpunit": "3.7.*" 355 | }, 356 | "bin": [ 357 | "bin/markdown" 358 | ], 359 | "type": "library", 360 | "extra": { 361 | "branch-alias": { 362 | "dev-master": "1.0.x-dev" 363 | } 364 | }, 365 | "autoload": { 366 | "psr-4": { 367 | "cebe\\markdown\\": "" 368 | } 369 | }, 370 | "notification-url": "https://packagist.org/downloads/", 371 | "license": [ 372 | "MIT" 373 | ], 374 | "authors": [ 375 | { 376 | "name": "Carsten Brandt", 377 | "email": "mail@cebe.cc", 378 | "homepage": "http://cebe.cc/", 379 | "role": "Creator" 380 | } 381 | ], 382 | "description": "A super fast, highly extensible markdown parser for PHP", 383 | "homepage": "https://github.com/cebe/markdown#readme", 384 | "keywords": [ 385 | "extensible", 386 | "fast", 387 | "gfm", 388 | "markdown", 389 | "markdown-extra" 390 | ], 391 | "time": "2015-03-06 05:21:16" 392 | }, 393 | { 394 | "name": "ezyang/htmlpurifier", 395 | "version": "v4.6.0", 396 | "source": { 397 | "type": "git", 398 | "url": "https://github.com/ezyang/htmlpurifier.git", 399 | "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd" 400 | }, 401 | "dist": { 402 | "type": "zip", 403 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd", 404 | "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd", 405 | "shasum": "" 406 | }, 407 | "require": { 408 | "php": ">=5.2" 409 | }, 410 | "type": "library", 411 | "autoload": { 412 | "psr-0": { 413 | "HTMLPurifier": "library/" 414 | }, 415 | "files": [ 416 | "library/HTMLPurifier.composer.php" 417 | ] 418 | }, 419 | "notification-url": "https://packagist.org/downloads/", 420 | "license": [ 421 | "LGPL" 422 | ], 423 | "authors": [ 424 | { 425 | "name": "Edward Z. Yang", 426 | "email": "admin@htmlpurifier.org", 427 | "homepage": "http://ezyang.com" 428 | } 429 | ], 430 | "description": "Standards compliant HTML filter written in PHP", 431 | "homepage": "http://htmlpurifier.org/", 432 | "keywords": [ 433 | "html" 434 | ], 435 | "time": "2013-11-30 08:25:19" 436 | }, 437 | { 438 | "name": "swiftmailer/swiftmailer", 439 | "version": "v5.4.0", 440 | "source": { 441 | "type": "git", 442 | "url": "https://github.com/swiftmailer/swiftmailer.git", 443 | "reference": "31454f258f10329ae7c48763eb898a75c39e0a9f" 444 | }, 445 | "dist": { 446 | "type": "zip", 447 | "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/31454f258f10329ae7c48763eb898a75c39e0a9f", 448 | "reference": "31454f258f10329ae7c48763eb898a75c39e0a9f", 449 | "shasum": "" 450 | }, 451 | "require": { 452 | "php": ">=5.3.3" 453 | }, 454 | "require-dev": { 455 | "mockery/mockery": "~0.9.1" 456 | }, 457 | "type": "library", 458 | "extra": { 459 | "branch-alias": { 460 | "dev-master": "5.4-dev" 461 | } 462 | }, 463 | "autoload": { 464 | "files": [ 465 | "lib/swift_required.php" 466 | ] 467 | }, 468 | "notification-url": "https://packagist.org/downloads/", 469 | "license": [ 470 | "MIT" 471 | ], 472 | "authors": [ 473 | { 474 | "name": "Chris Corbyn" 475 | }, 476 | { 477 | "name": "Fabien Potencier", 478 | "email": "fabien@symfony.com" 479 | } 480 | ], 481 | "description": "Swiftmailer, free feature-rich PHP mailer", 482 | "homepage": "http://swiftmailer.org", 483 | "keywords": [ 484 | "mail", 485 | "mailer" 486 | ], 487 | "time": "2015-03-14 06:06:39" 488 | }, 489 | { 490 | "name": "yiisoft/yii2", 491 | "version": "2.0.3", 492 | "source": { 493 | "type": "git", 494 | "url": "https://github.com/yiisoft/yii2-framework.git", 495 | "reference": "85b773a384f3894d558905cb13522bb338c99dba" 496 | }, 497 | "dist": { 498 | "type": "zip", 499 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/85b773a384f3894d558905cb13522bb338c99dba", 500 | "reference": "85b773a384f3894d558905cb13522bb338c99dba", 501 | "shasum": "" 502 | }, 503 | "require": { 504 | "bower-asset/jquery": "2.1.*@stable | 1.11.*@stable", 505 | "bower-asset/jquery.inputmask": "3.1.*", 506 | "bower-asset/punycode": "1.3.*", 507 | "bower-asset/yii2-pjax": ">=2.0.1", 508 | "cebe/markdown": "~1.0.0", 509 | "ext-mbstring": "*", 510 | "ezyang/htmlpurifier": "4.6.*", 511 | "lib-pcre": "*", 512 | "php": ">=5.4.0", 513 | "yiisoft/yii2-composer": "*" 514 | }, 515 | "bin": [ 516 | "yii" 517 | ], 518 | "type": "library", 519 | "extra": { 520 | "branch-alias": { 521 | "dev-master": "2.0.x-dev" 522 | } 523 | }, 524 | "autoload": { 525 | "psr-4": { 526 | "yii\\": "" 527 | } 528 | }, 529 | "notification-url": "https://packagist.org/downloads/", 530 | "license": [ 531 | "BSD-3-Clause" 532 | ], 533 | "authors": [ 534 | { 535 | "name": "Qiang Xue", 536 | "email": "qiang.xue@gmail.com", 537 | "homepage": "http://www.yiiframework.com/", 538 | "role": "Founder and project lead" 539 | }, 540 | { 541 | "name": "Alexander Makarov", 542 | "email": "sam@rmcreative.ru", 543 | "homepage": "http://rmcreative.ru/", 544 | "role": "Core framework development" 545 | }, 546 | { 547 | "name": "Maurizio Domba", 548 | "homepage": "http://mdomba.info/", 549 | "role": "Core framework development" 550 | }, 551 | { 552 | "name": "Carsten Brandt", 553 | "email": "mail@cebe.cc", 554 | "homepage": "http://cebe.cc/", 555 | "role": "Core framework development" 556 | }, 557 | { 558 | "name": "Timur Ruziev", 559 | "email": "resurtm@gmail.com", 560 | "homepage": "http://resurtm.com/", 561 | "role": "Core framework development" 562 | }, 563 | { 564 | "name": "Paul Klimov", 565 | "email": "klimov.paul@gmail.com", 566 | "role": "Core framework development" 567 | } 568 | ], 569 | "description": "Yii PHP Framework Version 2", 570 | "homepage": "http://www.yiiframework.com/", 571 | "keywords": [ 572 | "framework", 573 | "yii2" 574 | ], 575 | "time": "2015-03-01 06:22:44" 576 | }, 577 | { 578 | "name": "yiisoft/yii2-bootstrap", 579 | "version": "2.0.3", 580 | "source": { 581 | "type": "git", 582 | "url": "https://github.com/yiisoft/yii2-bootstrap.git", 583 | "reference": "d4bd9c5f97ea891ebbfaf276d3083d85e27fbcb6" 584 | }, 585 | "dist": { 586 | "type": "zip", 587 | "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap/zipball/d4bd9c5f97ea891ebbfaf276d3083d85e27fbcb6", 588 | "reference": "d4bd9c5f97ea891ebbfaf276d3083d85e27fbcb6", 589 | "shasum": "" 590 | }, 591 | "require": { 592 | "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*", 593 | "yiisoft/yii2": "*" 594 | }, 595 | "type": "yii2-extension", 596 | "extra": { 597 | "branch-alias": { 598 | "dev-master": "2.0.x-dev" 599 | } 600 | }, 601 | "autoload": { 602 | "psr-4": { 603 | "yii\\bootstrap\\": "" 604 | } 605 | }, 606 | "notification-url": "https://packagist.org/downloads/", 607 | "license": [ 608 | "BSD-3-Clause" 609 | ], 610 | "authors": [ 611 | { 612 | "name": "Qiang Xue", 613 | "email": "qiang.xue@gmail.com" 614 | } 615 | ], 616 | "description": "The Twitter Bootstrap extension for the Yii framework", 617 | "keywords": [ 618 | "bootstrap", 619 | "yii2" 620 | ], 621 | "time": "2015-03-01 06:22:44" 622 | }, 623 | { 624 | "name": "yiisoft/yii2-composer", 625 | "version": "2.0.3", 626 | "source": { 627 | "type": "git", 628 | "url": "https://github.com/yiisoft/yii2-composer.git", 629 | "reference": "ca8d23707ae47d20b0454e4b135c156f6da6d7be" 630 | }, 631 | "dist": { 632 | "type": "zip", 633 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/ca8d23707ae47d20b0454e4b135c156f6da6d7be", 634 | "reference": "ca8d23707ae47d20b0454e4b135c156f6da6d7be", 635 | "shasum": "" 636 | }, 637 | "require": { 638 | "composer-plugin-api": "1.0.0" 639 | }, 640 | "type": "composer-plugin", 641 | "extra": { 642 | "class": "yii\\composer\\Plugin", 643 | "branch-alias": { 644 | "dev-master": "2.0.x-dev" 645 | } 646 | }, 647 | "autoload": { 648 | "psr-4": { 649 | "yii\\composer\\": "" 650 | } 651 | }, 652 | "notification-url": "https://packagist.org/downloads/", 653 | "license": [ 654 | "BSD-3-Clause" 655 | ], 656 | "authors": [ 657 | { 658 | "name": "Qiang Xue", 659 | "email": "qiang.xue@gmail.com" 660 | } 661 | ], 662 | "description": "The composer plugin for Yii extension installer", 663 | "keywords": [ 664 | "composer", 665 | "extension installer", 666 | "yii2" 667 | ], 668 | "time": "2015-03-01 06:22:44" 669 | }, 670 | { 671 | "name": "yiisoft/yii2-swiftmailer", 672 | "version": "2.0.3", 673 | "source": { 674 | "type": "git", 675 | "url": "https://github.com/yiisoft/yii2-swiftmailer.git", 676 | "reference": "cb5f0a70d871b409bef7333fc3e0d262fb57eb5c" 677 | }, 678 | "dist": { 679 | "type": "zip", 680 | "url": "https://api.github.com/repos/yiisoft/yii2-swiftmailer/zipball/cb5f0a70d871b409bef7333fc3e0d262fb57eb5c", 681 | "reference": "cb5f0a70d871b409bef7333fc3e0d262fb57eb5c", 682 | "shasum": "" 683 | }, 684 | "require": { 685 | "swiftmailer/swiftmailer": "*", 686 | "yiisoft/yii2": "*" 687 | }, 688 | "type": "yii2-extension", 689 | "extra": { 690 | "branch-alias": { 691 | "dev-master": "2.0.x-dev" 692 | } 693 | }, 694 | "autoload": { 695 | "psr-4": { 696 | "yii\\swiftmailer\\": "" 697 | } 698 | }, 699 | "notification-url": "https://packagist.org/downloads/", 700 | "license": [ 701 | "BSD-3-Clause" 702 | ], 703 | "authors": [ 704 | { 705 | "name": "Paul Klimov", 706 | "email": "klimov.paul@gmail.com" 707 | } 708 | ], 709 | "description": "The SwiftMailer integration for the Yii framework", 710 | "keywords": [ 711 | "email", 712 | "mail", 713 | "mailer", 714 | "swift", 715 | "swiftmailer", 716 | "yii2" 717 | ], 718 | "time": "2015-03-01 06:22:44" 719 | } 720 | ], 721 | "packages-dev": [ 722 | { 723 | "name": "bower-asset/typeahead.js", 724 | "version": "v0.10.5", 725 | "source": { 726 | "type": "git", 727 | "url": "https://github.com/twitter/typeahead.js.git", 728 | "reference": "5f198b87d1af845da502ea9df93a5e84801ce742" 729 | }, 730 | "dist": { 731 | "type": "zip", 732 | "url": "https://api.github.com/repos/twitter/typeahead.js/zipball/5f198b87d1af845da502ea9df93a5e84801ce742", 733 | "reference": "5f198b87d1af845da502ea9df93a5e84801ce742", 734 | "shasum": "" 735 | }, 736 | "require": { 737 | "bower-asset/jquery": ">=1.7" 738 | }, 739 | "require-dev": { 740 | "bower-asset/jasmine-ajax": ">=1.3.1,<1.4", 741 | "bower-asset/jasmine-jquery": ">=1.5.2,<1.6", 742 | "bower-asset/jquery": ">=1.7,<1.8" 743 | }, 744 | "type": "bower-asset-library", 745 | "extra": { 746 | "bower-asset-main": "dist/typeahead.bundle.js" 747 | } 748 | }, 749 | { 750 | "name": "fzaninotto/faker", 751 | "version": "v1.4.0", 752 | "source": { 753 | "type": "git", 754 | "url": "https://github.com/fzaninotto/Faker.git", 755 | "reference": "010c7efedd88bf31141a02719f51fb44c732d5a0" 756 | }, 757 | "dist": { 758 | "type": "zip", 759 | "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/010c7efedd88bf31141a02719f51fb44c732d5a0", 760 | "reference": "010c7efedd88bf31141a02719f51fb44c732d5a0", 761 | "shasum": "" 762 | }, 763 | "require": { 764 | "php": ">=5.3.3" 765 | }, 766 | "require-dev": { 767 | "phpunit/phpunit": "~4.0", 768 | "squizlabs/php_codesniffer": "~1.5" 769 | }, 770 | "type": "library", 771 | "extra": { 772 | "branch-alias": [] 773 | }, 774 | "autoload": { 775 | "psr-0": { 776 | "Faker": "src/", 777 | "Faker\\PHPUnit": "test/" 778 | } 779 | }, 780 | "notification-url": "https://packagist.org/downloads/", 781 | "license": [ 782 | "MIT" 783 | ], 784 | "authors": [ 785 | { 786 | "name": "François Zaninotto" 787 | } 788 | ], 789 | "description": "Faker is a PHP library that generates fake data for you.", 790 | "keywords": [ 791 | "data", 792 | "faker", 793 | "fixtures" 794 | ], 795 | "time": "2014-06-04 14:43:02" 796 | }, 797 | { 798 | "name": "phpspec/php-diff", 799 | "version": "v1.0.2", 800 | "source": { 801 | "type": "git", 802 | "url": "https://github.com/phpspec/php-diff.git", 803 | "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a" 804 | }, 805 | "dist": { 806 | "type": "zip", 807 | "url": "https://api.github.com/repos/phpspec/php-diff/zipball/30e103d19519fe678ae64a60d77884ef3d71b28a", 808 | "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a", 809 | "shasum": "" 810 | }, 811 | "type": "library", 812 | "autoload": { 813 | "psr-0": { 814 | "Diff": "lib/" 815 | } 816 | }, 817 | "notification-url": "https://packagist.org/downloads/", 818 | "license": [ 819 | "BSD-3-Clause" 820 | ], 821 | "authors": [ 822 | { 823 | "name": "Chris Boulton", 824 | "homepage": "http://github.com/chrisboulton", 825 | "role": "Original developer" 826 | } 827 | ], 828 | "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", 829 | "time": "2013-11-01 13:02:21" 830 | }, 831 | { 832 | "name": "yiisoft/yii2-codeception", 833 | "version": "2.0.3", 834 | "source": { 835 | "type": "git", 836 | "url": "https://github.com/yiisoft/yii2-codeception.git", 837 | "reference": "c2fdee4e7e9846e141ceddeb4386325e921e375a" 838 | }, 839 | "dist": { 840 | "type": "zip", 841 | "url": "https://api.github.com/repos/yiisoft/yii2-codeception/zipball/c2fdee4e7e9846e141ceddeb4386325e921e375a", 842 | "reference": "c2fdee4e7e9846e141ceddeb4386325e921e375a", 843 | "shasum": "" 844 | }, 845 | "require": { 846 | "yiisoft/yii2": "*" 847 | }, 848 | "type": "yii2-extension", 849 | "extra": { 850 | "branch-alias": { 851 | "dev-master": "2.0.x-dev" 852 | } 853 | }, 854 | "autoload": { 855 | "psr-4": { 856 | "yii\\codeception\\": "" 857 | } 858 | }, 859 | "notification-url": "https://packagist.org/downloads/", 860 | "license": [ 861 | "BSD-3-Clause" 862 | ], 863 | "authors": [ 864 | { 865 | "name": "Mark Jebri", 866 | "email": "mark.github@yandex.ru" 867 | } 868 | ], 869 | "description": "The Codeception integration for the Yii framework", 870 | "keywords": [ 871 | "codeception", 872 | "yii2" 873 | ], 874 | "time": "2015-03-01 06:22:44" 875 | }, 876 | { 877 | "name": "yiisoft/yii2-debug", 878 | "version": "2.0.3", 879 | "source": { 880 | "type": "git", 881 | "url": "https://github.com/yiisoft/yii2-debug.git", 882 | "reference": "8a0db5130a9ea3941304dd77cef23d69257e8d48" 883 | }, 884 | "dist": { 885 | "type": "zip", 886 | "url": "https://api.github.com/repos/yiisoft/yii2-debug/zipball/8a0db5130a9ea3941304dd77cef23d69257e8d48", 887 | "reference": "8a0db5130a9ea3941304dd77cef23d69257e8d48", 888 | "shasum": "" 889 | }, 890 | "require": { 891 | "yiisoft/yii2": "*", 892 | "yiisoft/yii2-bootstrap": "*" 893 | }, 894 | "type": "yii2-extension", 895 | "extra": { 896 | "branch-alias": { 897 | "dev-master": "2.0.x-dev" 898 | } 899 | }, 900 | "autoload": { 901 | "psr-4": { 902 | "yii\\debug\\": "" 903 | } 904 | }, 905 | "notification-url": "https://packagist.org/downloads/", 906 | "license": [ 907 | "BSD-3-Clause" 908 | ], 909 | "authors": [ 910 | { 911 | "name": "Qiang Xue", 912 | "email": "qiang.xue@gmail.com" 913 | } 914 | ], 915 | "description": "The debugger extension for the Yii framework", 916 | "keywords": [ 917 | "debug", 918 | "debugger", 919 | "yii2" 920 | ], 921 | "time": "2015-03-01 06:22:44" 922 | }, 923 | { 924 | "name": "yiisoft/yii2-faker", 925 | "version": "2.0.3", 926 | "source": { 927 | "type": "git", 928 | "url": "https://github.com/yiisoft/yii2-faker.git", 929 | "reference": "b88ca69ee226a3610b2c26c026c3203d7ac50f6c" 930 | }, 931 | "dist": { 932 | "type": "zip", 933 | "url": "https://api.github.com/repos/yiisoft/yii2-faker/zipball/b88ca69ee226a3610b2c26c026c3203d7ac50f6c", 934 | "reference": "b88ca69ee226a3610b2c26c026c3203d7ac50f6c", 935 | "shasum": "" 936 | }, 937 | "require": { 938 | "fzaninotto/faker": "*", 939 | "yiisoft/yii2": "*" 940 | }, 941 | "type": "yii2-extension", 942 | "extra": { 943 | "branch-alias": { 944 | "dev-master": "2.0.x-dev" 945 | } 946 | }, 947 | "autoload": { 948 | "psr-4": { 949 | "yii\\faker\\": "" 950 | } 951 | }, 952 | "notification-url": "https://packagist.org/downloads/", 953 | "license": [ 954 | "BSD-3-Clause" 955 | ], 956 | "authors": [ 957 | { 958 | "name": "Mark Jebri", 959 | "email": "mark.github@yandex.ru" 960 | } 961 | ], 962 | "description": "Fixture generator. The Faker integration for the Yii framework.", 963 | "keywords": [ 964 | "Fixture", 965 | "faker", 966 | "yii2" 967 | ], 968 | "time": "2015-03-01 06:22:44" 969 | }, 970 | { 971 | "name": "yiisoft/yii2-gii", 972 | "version": "2.0.3", 973 | "source": { 974 | "type": "git", 975 | "url": "https://github.com/yiisoft/yii2-gii.git", 976 | "reference": "bb79aeafa8e3b89dd25e07ac895b269680e537a8" 977 | }, 978 | "dist": { 979 | "type": "zip", 980 | "url": "https://api.github.com/repos/yiisoft/yii2-gii/zipball/bb79aeafa8e3b89dd25e07ac895b269680e537a8", 981 | "reference": "bb79aeafa8e3b89dd25e07ac895b269680e537a8", 982 | "shasum": "" 983 | }, 984 | "require": { 985 | "bower-asset/typeahead.js": "0.10.*", 986 | "phpspec/php-diff": ">=1.0.2", 987 | "yiisoft/yii2": "*", 988 | "yiisoft/yii2-bootstrap": "*" 989 | }, 990 | "type": "yii2-extension", 991 | "extra": { 992 | "branch-alias": { 993 | "dev-master": "2.0.x-dev" 994 | } 995 | }, 996 | "autoload": { 997 | "psr-4": { 998 | "yii\\gii\\": "" 999 | } 1000 | }, 1001 | "notification-url": "https://packagist.org/downloads/", 1002 | "license": [ 1003 | "BSD-3-Clause" 1004 | ], 1005 | "authors": [ 1006 | { 1007 | "name": "Qiang Xue", 1008 | "email": "qiang.xue@gmail.com" 1009 | } 1010 | ], 1011 | "description": "The Gii extension for the Yii framework", 1012 | "keywords": [ 1013 | "code generator", 1014 | "gii", 1015 | "yii2" 1016 | ], 1017 | "time": "2015-03-01 06:22:44" 1018 | } 1019 | ], 1020 | "aliases": [], 1021 | "minimum-stability": "stable", 1022 | "stability-flags": [], 1023 | "prefer-stable": false, 1024 | "prefer-lowest": false, 1025 | "platform": { 1026 | "php": ">=5.4.0" 1027 | }, 1028 | "platform-dev": [] 1029 | } 1030 | -------------------------------------------------------------------------------- /console/config/.gitignore: -------------------------------------------------------------------------------- 1 | main-local.php 2 | params-local.php -------------------------------------------------------------------------------- /console/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | 'app-console', 11 | 'basePath' => dirname(__DIR__), 12 | 'bootstrap' => ['log'], 13 | 'controllerNamespace' => 'console\controllers', 14 | 'components' => [ 15 | 'log' => [ 16 | 'targets' => [ 17 | [ 18 | 'class' => 'yii\log\FileTarget', 19 | 'levels' => ['error', 'warning'], 20 | ], 21 | ], 22 | ], 23 | ], 24 | 'params' => $params, 25 | ]; 26 | -------------------------------------------------------------------------------- /console/config/params.php: -------------------------------------------------------------------------------- 1 | 'admin@example.com', 4 | ]; 5 | -------------------------------------------------------------------------------- /console/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neattutorials/angularjs-yii2-part-2-authentication/726353f9a475c61da3a53fce0afe120c841ccf3a/console/controllers/.gitkeep -------------------------------------------------------------------------------- /console/migrations/m130524_201442_init.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 13 | // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci 14 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 15 | } 16 | 17 | $this->createTable('{{%user}}', [ 18 | 'id' => Schema::TYPE_PK, 19 | 'username' => Schema::TYPE_STRING . ' NOT NULL', 20 | 'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL', 21 | 'password_hash' => Schema::TYPE_STRING . ' NOT NULL', 22 | 'password_reset_token' => Schema::TYPE_STRING, 23 | 'email' => Schema::TYPE_STRING . ' NOT NULL', 24 | 25 | 'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', 26 | 'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', 27 | 'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', 28 | ], $tableOptions); 29 | 30 | $user = new User(); 31 | $user->username = 'demo'; 32 | $user->email = 'demo@example.com'; 33 | $user->generateAuthKey(); 34 | $user->setPassword('demo'); 35 | return $user->save(false); 36 | } 37 | 38 | public function down() 39 | { 40 | $this->dropTable('{{%user}}'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /console/models/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /console/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /db/users.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neattutorials/angularjs-yii2-part-2-authentication/726353f9a475c61da3a53fce0afe120c841ccf3a/db/users.db -------------------------------------------------------------------------------- /environments/dev/backend/config/main-local.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'request' => [ 6 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 7 | 'cookieValidationKey' => '', 8 | ], 9 | ], 10 | ]; 11 | 12 | if (!YII_ENV_TEST) { 13 | // configuration adjustments for 'dev' environment 14 | $config['bootstrap'][] = 'debug'; 15 | $config['modules']['debug'] = 'yii\debug\Module'; 16 | 17 | $config['bootstrap'][] = 'gii'; 18 | $config['modules']['gii'] = 'yii\gii\Module'; 19 | } 20 | 21 | return $config; 22 | -------------------------------------------------------------------------------- /environments/dev/backend/config/params-local.php: -------------------------------------------------------------------------------- 1 | run(); 20 | -------------------------------------------------------------------------------- /environments/dev/backend/web/index.php: -------------------------------------------------------------------------------- 1 | run(); 19 | -------------------------------------------------------------------------------- /environments/dev/common/config/main-local.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'db' => [ 5 | 'class' => 'yii\db\Connection', 6 | 'dsn' => 'mysql:host=localhost;dbname=ay', 7 | 'username' => 'root', 8 | 'password' => '', 9 | 'charset' => 'utf8', 10 | ], 11 | 'mailer' => [ 12 | 'class' => 'yii\swiftmailer\Mailer', 13 | 'viewPath' => '@common/mail', 14 | // send all mails to a file by default. You have to set 15 | // 'useFileTransport' to false and configure a transport 16 | // for the mailer to send real emails. 17 | 'useFileTransport' => true, 18 | ], 19 | ], 20 | ]; 21 | -------------------------------------------------------------------------------- /environments/dev/common/config/params-local.php: -------------------------------------------------------------------------------- 1 | ['gii'], 4 | 'modules' => [ 5 | 'gii' => 'yii\gii\Module', 6 | ], 7 | ]; 8 | -------------------------------------------------------------------------------- /environments/dev/console/config/params-local.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'request' => [ 6 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 7 | 'cookieValidationKey' => '', 8 | ], 9 | ], 10 | ]; 11 | 12 | if (!YII_ENV_TEST) { 13 | // configuration adjustments for 'dev' environment 14 | $config['bootstrap'][] = 'debug'; 15 | $config['modules']['debug'] = 'yii\debug\Module'; 16 | 17 | $config['bootstrap'][] = 'gii'; 18 | $config['modules']['gii'] = 'yii\gii\Module'; 19 | } 20 | 21 | return $config; 22 | -------------------------------------------------------------------------------- /environments/dev/frontend/config/params-local.php: -------------------------------------------------------------------------------- 1 | run(); 19 | -------------------------------------------------------------------------------- /environments/dev/frontend/web/index.php: -------------------------------------------------------------------------------- 1 | run(); 19 | -------------------------------------------------------------------------------- /environments/dev/yii: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 32 | exit($exitCode); 33 | -------------------------------------------------------------------------------- /environments/index.php: -------------------------------------------------------------------------------- 1 | [ 11 | * 'path' => 'directory storing the local files', 12 | * 'setWritable' => [ 13 | * // list of directories that should be set writable 14 | * ], 15 | * 'setExecutable' => [ 16 | * // list of files that should be set executable 17 | * ], 18 | * 'setCookieValidationKey' => [ 19 | * // list of config files that need to be inserted with automatically generated cookie validation keys 20 | * ], 21 | * 'createSymlink' => [ 22 | * // list of symlinks to be created. Keys are symlinks, and values are the targets. 23 | * ], 24 | * ], 25 | * ]; 26 | * ``` 27 | */ 28 | return [ 29 | 'Development' => [ 30 | 'path' => 'dev', 31 | 'setWritable' => [ 32 | 'backend/runtime', 33 | 'backend/web/assets', 34 | 'frontend/runtime', 35 | 'frontend/web/assets', 36 | ], 37 | 'setExecutable' => [ 38 | 'yii', 39 | ], 40 | 'setCookieValidationKey' => [ 41 | 'backend/config/main-local.php', 42 | 'frontend/config/main-local.php', 43 | ], 44 | ], 45 | 'Production' => [ 46 | 'path' => 'prod', 47 | 'setWritable' => [ 48 | 'backend/runtime', 49 | 'backend/web/assets', 50 | 'frontend/runtime', 51 | 'frontend/web/assets', 52 | ], 53 | 'setExecutable' => [ 54 | 'yii', 55 | ], 56 | 'setCookieValidationKey' => [ 57 | 'backend/config/main-local.php', 58 | 'frontend/config/main-local.php', 59 | ], 60 | ], 61 | ]; 62 | -------------------------------------------------------------------------------- /environments/prod/backend/config/main-local.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'request' => [ 5 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 6 | 'cookieValidationKey' => '', 7 | ], 8 | ], 9 | ]; 10 | -------------------------------------------------------------------------------- /environments/prod/backend/config/params-local.php: -------------------------------------------------------------------------------- 1 | run(); 19 | -------------------------------------------------------------------------------- /environments/prod/common/config/main-local.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'db' => [ 5 | 'class' => 'yii\db\Connection', 6 | 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', 7 | 'username' => 'root', 8 | 'password' => '', 9 | 'charset' => 'utf8', 10 | ], 11 | 'mailer' => [ 12 | 'class' => 'yii\swiftmailer\Mailer', 13 | 'viewPath' => '@common/mail', 14 | ], 15 | ], 16 | ]; 17 | -------------------------------------------------------------------------------- /environments/prod/common/config/params-local.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'request' => [ 5 | // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 6 | 'cookieValidationKey' => '', 7 | ], 8 | ], 9 | ]; 10 | -------------------------------------------------------------------------------- /environments/prod/frontend/config/params-local.php: -------------------------------------------------------------------------------- 1 | run(); 19 | -------------------------------------------------------------------------------- /environments/prod/yii: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 32 | exit($exitCode); 33 | -------------------------------------------------------------------------------- /frontend/assets/AngularAsset.php: -------------------------------------------------------------------------------- 1 | View::POS_HEAD, 17 | ]; 18 | } 19 | -------------------------------------------------------------------------------- /frontend/assets/AppAsset.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 2.0 15 | */ 16 | class AppAsset extends AssetBundle 17 | { 18 | public $basePath = '@webroot'; 19 | public $baseUrl = '@web'; 20 | public $css = [ 21 | 'css/site.css', 22 | ]; 23 | public $js = [ 24 | 'js/app.js', 25 | 'js/controllers.js', 26 | ]; 27 | public $depends = [ 28 | 'yii\web\YiiAsset', 29 | 'yii\bootstrap\BootstrapAsset', 30 | 'frontend\assets\AngularAsset', 31 | ]; 32 | } 33 | -------------------------------------------------------------------------------- /frontend/config/.gitignore: -------------------------------------------------------------------------------- 1 | main-local.php 2 | params-local.php -------------------------------------------------------------------------------- /frontend/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | 'app-frontend', 11 | 'basePath' => dirname(__DIR__), 12 | 'bootstrap' => ['log'], 13 | 'controllerNamespace' => 'frontend\controllers', 14 | 'components' => [ 15 | 'user' => [ 16 | 'identityClass' => 'common\models\User', 17 | 'enableSession' => false, 18 | 'loginUrl' => null, 19 | 20 | ], 21 | 'request' => [ 22 | 'class' => '\yii\web\Request', 23 | 'enableCookieValidation' => false, 24 | 'parsers' => [ 25 | 'application/json' => 'yii\web\JsonParser', 26 | ], 27 | ], 28 | 'urlManager' => [ 29 | 'enablePrettyUrl' => true, 30 | 'showScriptName' => false, 31 | ], 32 | 'log' => [ 33 | 'traceLevel' => YII_DEBUG ? 3 : 0, 34 | 'targets' => [ 35 | [ 36 | 'class' => 'yii\log\FileTarget', 37 | 'levels' => ['error', 'warning'], 38 | ], 39 | ], 40 | ], 41 | 'errorHandler' => [ 42 | 'errorAction' => 'site/error', 43 | ], 44 | ], 45 | 'params' => $params, 46 | ]; 47 | -------------------------------------------------------------------------------- /frontend/config/params.php: -------------------------------------------------------------------------------- 1 | 'admin@example.com', 4 | ]; 5 | -------------------------------------------------------------------------------- /frontend/controllers/ApiController.php: -------------------------------------------------------------------------------- 1 | HttpBearerAuth::className(), 26 | 'only' => ['dashboard'], 27 | ]; 28 | $behaviors['contentNegotiator'] = [ 29 | 'class' => ContentNegotiator::className(), 30 | 'formats' => [ 31 | 'application/json' => Response::FORMAT_JSON, 32 | ], 33 | ]; 34 | $behaviors['access'] = [ 35 | 'class' => AccessControl::className(), 36 | 'only' => ['dashboard'], 37 | 'rules' => [ 38 | [ 39 | 'actions' => ['dashboard'], 40 | 'allow' => true, 41 | 'roles' => ['@'], 42 | ], 43 | ], 44 | ]; 45 | return $behaviors; 46 | } 47 | 48 | public function actionLogin() 49 | { 50 | $model = new LoginForm(); 51 | 52 | if ($model->load(Yii::$app->getRequest()->getBodyParams(), '') && $model->login()) { 53 | return ['access_token' => Yii::$app->user->identity->getAuthKey()]; 54 | } else { 55 | $model->validate(); 56 | return $model; 57 | } 58 | } 59 | 60 | public function actionDashboard() 61 | { 62 | $response = [ 63 | 'username' => Yii::$app->user->identity->username, 64 | 'access_token' => Yii::$app->user->identity->getAuthKey(), 65 | ]; 66 | 67 | return $response; 68 | } 69 | 70 | public function actionContact() 71 | { 72 | $model = new ContactForm(); 73 | if ($model->load(Yii::$app->getRequest()->getBodyParams(), '') && $model->validate()) { 74 | if ($model->sendEmail(Yii::$app->params['adminEmail'])) { 75 | $response = [ 76 | 'flash' => [ 77 | 'class' => 'success', 78 | 'message' => 'Thank you for contacting us. We will respond to you as soon as possible.', 79 | ] 80 | ]; 81 | } else { 82 | $response = [ 83 | 'flash' => [ 84 | 'class' => 'error', 85 | 'message' => 'There was an error sending email.', 86 | ] 87 | ]; 88 | } 89 | return $response; 90 | } else { 91 | $model->validate(); 92 | return $model; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /frontend/controllers/SiteController.php: -------------------------------------------------------------------------------- 1 | [ 19 | 'class' => 'yii\web\ErrorAction', 20 | ], 21 | 'captcha' => [ 22 | 'class' => 'yii\captcha\CaptchaAction', 23 | 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, 24 | ], 25 | ]; 26 | } 27 | 28 | public function actionIndex() 29 | { 30 | return $this->renderContent(null); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /frontend/models/ContactForm.php: -------------------------------------------------------------------------------- 1 | 'Verification Code', 41 | ]; 42 | } 43 | 44 | /** 45 | * Sends an email to the specified email address using the information collected by this model. 46 | * 47 | * @param string $email the target email address 48 | * @return boolean whether the email was sent 49 | */ 50 | public function sendEmail($email) 51 | { 52 | return Yii::$app->mailer->compose() 53 | ->setTo($email) 54 | ->setFrom([$this->email => $this->name]) 55 | ->setSubject($this->subject) 56 | ->setTextBody($this->body) 57 | ->send(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /frontend/models/PasswordResetRequestForm.php: -------------------------------------------------------------------------------- 1 | 'trim'], 21 | ['email', 'required'], 22 | ['email', 'email'], 23 | ['email', 'exist', 24 | 'targetClass' => '\common\models\User', 25 | 'filter' => ['status' => User::STATUS_ACTIVE], 26 | 'message' => 'There is no user with such email.' 27 | ], 28 | ]; 29 | } 30 | 31 | /** 32 | * Sends an email with a link, for resetting the password. 33 | * 34 | * @return boolean whether the email was send 35 | */ 36 | public function sendEmail() 37 | { 38 | /* @var $user User */ 39 | $user = User::findOne([ 40 | 'status' => User::STATUS_ACTIVE, 41 | 'email' => $this->email, 42 | ]); 43 | 44 | if ($user) { 45 | if (!User::isPasswordResetTokenValid($user->password_reset_token)) { 46 | $user->generatePasswordResetToken(); 47 | } 48 | 49 | if ($user->save()) { 50 | return \Yii::$app->mailer->compose(['html' => 'passwordResetToken-html', 'text' => 'passwordResetToken-text'], ['user' => $user]) 51 | ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot']) 52 | ->setTo($this->email) 53 | ->setSubject('Password reset for ' . \Yii::$app->name) 54 | ->send(); 55 | } 56 | } 57 | 58 | return false; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /frontend/models/ResetPasswordForm.php: -------------------------------------------------------------------------------- 1 | _user = User::findByPasswordResetToken($token); 35 | if (!$this->_user) { 36 | throw new InvalidParamException('Wrong password reset token.'); 37 | } 38 | parent::__construct($config); 39 | } 40 | 41 | /** 42 | * @inheritdoc 43 | */ 44 | public function rules() 45 | { 46 | return [ 47 | ['password', 'required'], 48 | ['password', 'string', 'min' => 6], 49 | ]; 50 | } 51 | 52 | /** 53 | * Resets password. 54 | * 55 | * @return boolean if password was reset. 56 | */ 57 | public function resetPassword() 58 | { 59 | $user = $this->_user; 60 | $user->setPassword($this->password); 61 | $user->removePasswordResetToken(); 62 | 63 | return $user->save(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /frontend/models/SignupForm.php: -------------------------------------------------------------------------------- 1 | 'trim'], 24 | ['username', 'required'], 25 | ['username', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This username has already been taken.'], 26 | ['username', 'string', 'min' => 2, 'max' => 255], 27 | 28 | ['email', 'filter', 'filter' => 'trim'], 29 | ['email', 'required'], 30 | ['email', 'email'], 31 | ['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken.'], 32 | 33 | ['password', 'required'], 34 | ['password', 'string', 'min' => 6], 35 | ]; 36 | } 37 | 38 | /** 39 | * Signs user up. 40 | * 41 | * @return User|null the saved model or null if saving fails 42 | */ 43 | public function signup() 44 | { 45 | if ($this->validate()) { 46 | $user = new User(); 47 | $user->username = $this->username; 48 | $user->email = $this->email; 49 | $user->setPassword($this->password); 50 | $user->generateAuthKey(); 51 | if ($user->save()) { 52 | return $user; 53 | } 54 | } 55 | 56 | return null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /frontend/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /frontend/views/layouts/main.php: -------------------------------------------------------------------------------- 1 | 8 | beginPage() ?> 9 | 10 | 11 | 12 | 13 | 14 | My Angular Yii Application 15 | head() ?> 16 | 17 | 18 | 19 | 20 | 21 | 22 | beginBody() ?> 23 |
24 | 58 | 59 |
60 |
61 |
62 |
63 | 64 |
65 | 66 | 72 | 73 | endBody() ?> 74 | 75 | 76 | endPage() ?> -------------------------------------------------------------------------------- /frontend/views/site/error.php: -------------------------------------------------------------------------------- 1 | title = $name; 11 | ?> 12 |
13 | 14 |

title) ?>

15 | 16 |
17 | 18 |
19 | 20 |

21 | The above error occurred while the Web server was processing your request. 22 |

23 |

24 | Please contact us if you think this is a server error. Thank you. 25 |

26 | 27 |
28 | -------------------------------------------------------------------------------- /frontend/web/.gitignore: -------------------------------------------------------------------------------- 1 | /index.php 2 | /index-test.php 3 | -------------------------------------------------------------------------------- /frontend/web/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | 3 | RewriteCond %{REQUEST_FILENAME} !-f 4 | RewriteCond %{REQUEST_FILENAME} !-d 5 | 6 | RewriteRule . index.php -------------------------------------------------------------------------------- /frontend/web/assets/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /frontend/web/css/site.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | .wrap { 7 | min-height: 100%; 8 | height: auto; 9 | margin: 0 auto -60px; 10 | padding: 0 0 60px; 11 | } 12 | 13 | .wrap > .container { 14 | padding: 70px 15px 20px; 15 | } 16 | 17 | .footer { 18 | height: 60px; 19 | background-color: #f5f5f5; 20 | border-top: 1px solid #ddd; 21 | padding-top: 20px; 22 | } 23 | 24 | .jumbotron { 25 | text-align: center; 26 | background-color: transparent; 27 | } 28 | 29 | .jumbotron .btn { 30 | font-size: 21px; 31 | padding: 14px 24px; 32 | } 33 | 34 | .not-set { 35 | color: #c55; 36 | font-style: italic; 37 | } 38 | 39 | /* add sorting icons to gridview sort links */ 40 | a.asc:after, a.desc:after { 41 | position: relative; 42 | top: 1px; 43 | display: inline-block; 44 | font-family: 'Glyphicons Halflings'; 45 | font-style: normal; 46 | font-weight: normal; 47 | line-height: 1; 48 | padding-left: 5px; 49 | } 50 | 51 | a.asc:after { 52 | content: /*"\e113"*/ "\e151"; 53 | } 54 | 55 | a.desc:after { 56 | content: /*"\e114"*/ "\e152"; 57 | } 58 | 59 | .sort-numerical a.asc:after { 60 | content: "\e153"; 61 | } 62 | 63 | .sort-numerical a.desc:after { 64 | content: "\e154"; 65 | } 66 | 67 | .sort-ordinal a.asc:after { 68 | content: "\e155"; 69 | } 70 | 71 | .sort-ordinal a.desc:after { 72 | content: "\e156"; 73 | } 74 | 75 | .grid-view th { 76 | white-space: nowrap; 77 | } 78 | 79 | .hint-block { 80 | display: block; 81 | margin-top: 5px; 82 | color: #999; 83 | } 84 | 85 | .error-summary { 86 | color: #a94442; 87 | background: #fdf7f7; 88 | border-left: 3px solid #eed3d7; 89 | padding: 10px 20px; 90 | margin: 0 0 15px 0; 91 | } 92 | -------------------------------------------------------------------------------- /frontend/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neattutorials/angularjs-yii2-part-2-authentication/726353f9a475c61da3a53fce0afe120c841ccf3a/frontend/web/favicon.ico -------------------------------------------------------------------------------- /frontend/web/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = angular.module('app', [ 4 | 'ngRoute', //$routeProvider 5 | 'mgcrea.ngStrap', //bs-navbar, data-match-route directives 6 | 'controllers' //Our module frontend/web/js/controllers.js 7 | ]); 8 | 9 | app.config(['$routeProvider', '$httpProvider', 10 | function($routeProvider, $httpProvider) { 11 | $routeProvider. 12 | when('/', { 13 | templateUrl: 'partials/index.html' 14 | }). 15 | when('/about', { 16 | templateUrl: 'partials/about.html' 17 | }). 18 | when('/contact', { 19 | templateUrl: 'partials/contact.html', 20 | controller: 'ContactController' 21 | }). 22 | when('/login', { 23 | templateUrl: 'partials/login.html', 24 | controller: 'LoginController' 25 | }). 26 | when('/dashboard', { 27 | templateUrl: 'partials/dashboard.html', 28 | controller: 'DashboardController' 29 | }). 30 | otherwise({ 31 | templateUrl: 'partials/404.html' 32 | }); 33 | $httpProvider.interceptors.push('authInterceptor'); 34 | } 35 | ]); 36 | 37 | app.factory('authInterceptor', function ($q, $window, $location) { 38 | return { 39 | request: function (config) { 40 | if ($window.sessionStorage.access_token) { 41 | //HttpBearerAuth 42 | config.headers.Authorization = 'Bearer ' + $window.sessionStorage.access_token; 43 | } 44 | return config; 45 | }, 46 | responseError: function (rejection) { 47 | if (rejection.status === 401) { 48 | $location.path('/login').replace(); 49 | } 50 | return $q.reject(rejection); 51 | } 52 | }; 53 | }); -------------------------------------------------------------------------------- /frontend/web/js/controllers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var controllers = angular.module('controllers', []); 4 | 5 | controllers.controller('MainController', ['$scope', '$location', '$window', 6 | function ($scope, $location, $window) { 7 | $scope.loggedIn = function() { 8 | return Boolean($window.sessionStorage.access_token); 9 | }; 10 | 11 | $scope.logout = function () { 12 | delete $window.sessionStorage.access_token; 13 | $location.path('/login').replace(); 14 | }; 15 | } 16 | ]); 17 | 18 | controllers.controller('ContactController', ['$scope', '$http', '$window', 19 | function($scope, $http, $window) { 20 | $scope.captchaUrl = 'site/captcha'; 21 | $scope.contact = function () { 22 | $scope.submitted = true; 23 | $scope.error = {}; 24 | $http.post('api/contact', $scope.contactModel).success( 25 | function (data) { 26 | $scope.contactModel = {}; 27 | $scope.flash = data.flash; 28 | $window.scrollTo(0,0); 29 | $scope.submitted = false; 30 | $scope.captchaUrl = 'site/captcha' + '?' + new Date().getTime(); 31 | }).error( 32 | function (data) { 33 | angular.forEach(data, function (error) { 34 | $scope.error[error.field] = error.message; 35 | }); 36 | } 37 | ); 38 | }; 39 | 40 | $scope.refreshCaptcha = function() { 41 | $http.get('site/captcha?refresh=1').success(function(data) { 42 | $scope.captchaUrl = data.url; 43 | }); 44 | }; 45 | }]); 46 | 47 | controllers.controller('DashboardController', ['$scope', '$http', 48 | function ($scope, $http) { 49 | $http.get('api/dashboard').success(function (data) { 50 | $scope.dashboard = data; 51 | }) 52 | } 53 | ]); 54 | 55 | controllers.controller('LoginController', ['$scope', '$http', '$window', '$location', 56 | function($scope, $http, $window, $location) { 57 | $scope.login = function () { 58 | $scope.submitted = true; 59 | $scope.error = {}; 60 | $http.post('api/login', $scope.userModel).success( 61 | function (data) { 62 | $window.sessionStorage.access_token = data.access_token; 63 | $location.path('/dashboard').replace(); 64 | }).error( 65 | function (data) { 66 | angular.forEach(data, function (error) { 67 | $scope.error[error.field] = error.message; 68 | }); 69 | } 70 | ); 71 | }; 72 | } 73 | ]); -------------------------------------------------------------------------------- /frontend/web/partials/404.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Not Found (#404)

4 | 5 |
6 | Page not found. 7 |
8 | 9 |

10 | The above error occurred while the Web server was processing your request. 11 |

12 | 13 |

14 | Please contact us if you think this is a server error. Thank you. 15 |

16 | 17 |
-------------------------------------------------------------------------------- /frontend/web/partials/about.html: -------------------------------------------------------------------------------- 1 |

About

2 | 3 |

This is the About page. You may modify the following file to customize its content:

4 | 5 | frontend\web\partials\about.html -------------------------------------------------------------------------------- /frontend/web/partials/contact.html: -------------------------------------------------------------------------------- 1 |
2 | {{flash.message}} 3 |
4 |

Contact

5 | 6 |

7 | If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. 8 |

9 | 10 |
11 | 12 |
13 |
14 | 15 |
18 | 19 | 20 |

{{ error['name'] }}

21 |
22 | 23 | 30 | 31 |
34 | 35 | 36 |

{{ error['subject'] }}

37 |
38 | 39 |
42 | 43 | 44 |

{{ error['body'] }}

45 |
46 | 47 |
50 | 51 |
52 |
53 | 54 |
55 |
56 | 57 |
58 |
59 |

{{ error['verifyCode'] }}

60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 |
68 |
69 | -------------------------------------------------------------------------------- /frontend/web/partials/dashboard.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Hello {{ dashboard.username }}

4 | Welcome to the secret page.
5 | Your access_token is {{ dashboard.access_token }} 6 |
7 | -------------------------------------------------------------------------------- /frontend/web/partials/index.html: -------------------------------------------------------------------------------- 1 |
2 |

Congratulations!

3 | 4 |

You have successfully created your Angular/Yii-powered application.

5 | 6 |

Get started with Yii

7 |
8 | 9 |
10 | 11 |
12 |
13 |

Heading

14 | 15 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 16 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 17 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 18 | fugiat nulla pariatur.

19 | 20 |

Yii Documentation »

21 |
22 |
23 |

Heading

24 | 25 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 26 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 27 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 28 | fugiat nulla pariatur.

29 | 30 |

Yii Forum »

31 |
32 |
33 |

Heading

34 | 35 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 36 | dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip 37 | ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 38 | fugiat nulla pariatur.

39 | 40 |

Yii Extensions »

41 |
42 |
43 | 44 |
-------------------------------------------------------------------------------- /frontend/web/partials/login.html: -------------------------------------------------------------------------------- 1 |

Login

2 | 3 |

Please fill out the following fields to login:

4 | 5 |
6 |
7 |
8 |
11 | 12 | 13 |

{{ error['username'] }}

14 |
15 | 16 |
19 | 20 | 21 |

{{ error['password'] }}

22 |
23 | 24 |
25 | 26 |
27 | 28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /frontend/web/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /init: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 11 | * 12 | * @link http://www.yiiframework.com/ 13 | * @copyright Copyright (c) 2008 Yii Software LLC 14 | * @license http://www.yiiframework.com/license/ 15 | */ 16 | 17 | if (!extension_loaded('openssl')) { 18 | die('The OpenSSL PHP extension is required by Yii2.'); 19 | } 20 | 21 | $params = getParams(); 22 | $root = str_replace('\\', '/', __DIR__); 23 | $envs = require("$root/environments/index.php"); 24 | $envNames = array_keys($envs); 25 | 26 | echo "Yii Application Initialization Tool v1.0\n\n"; 27 | 28 | $envName = null; 29 | if (empty($params['env']) || $params['env'] === '1') { 30 | echo "Which environment do you want the application to be initialized in?\n\n"; 31 | foreach ($envNames as $i => $name) { 32 | echo " [$i] $name\n"; 33 | } 34 | echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] '; 35 | $answer = trim(fgets(STDIN)); 36 | 37 | if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) { 38 | echo "\n Quit initialization.\n"; 39 | exit(0); 40 | } 41 | 42 | if (isset($envNames[$answer])) { 43 | $envName = $envNames[$answer]; 44 | } 45 | } else { 46 | $envName = $params['env']; 47 | } 48 | 49 | if (!in_array($envName, $envNames)) { 50 | $envsList = implode(', ', $envNames); 51 | echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n"; 52 | exit(2); 53 | } 54 | 55 | $env = $envs[$envName]; 56 | 57 | if (empty($params['env'])) { 58 | echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] "; 59 | $answer = trim(fgets(STDIN)); 60 | if (strncasecmp($answer, 'y', 1)) { 61 | echo "\n Quit initialization.\n"; 62 | exit(0); 63 | } 64 | } 65 | 66 | echo "\n Start initialization ...\n\n"; 67 | $files = getFileList("$root/environments/{$env['path']}"); 68 | $all = false; 69 | foreach ($files as $file) { 70 | if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) { 71 | break; 72 | } 73 | } 74 | 75 | $callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable']; 76 | foreach ($callbacks as $callback) { 77 | if (!empty($env[$callback])) { 78 | $callback($root, $env[$callback]); 79 | } 80 | } 81 | 82 | echo "\n ... initialization completed.\n\n"; 83 | 84 | function getFileList($root, $basePath = '') 85 | { 86 | $files = []; 87 | $handle = opendir($root); 88 | while (($path = readdir($handle)) !== false) { 89 | if ($path === '.svn' || $path === '.' || $path === '..') { 90 | continue; 91 | } 92 | $fullPath = "$root/$path"; 93 | $relativePath = $basePath === '' ? $path : "$basePath/$path"; 94 | if (is_dir($fullPath)) { 95 | $files = array_merge($files, getFileList($fullPath, $relativePath)); 96 | } else { 97 | $files[] = $relativePath; 98 | } 99 | } 100 | closedir($handle); 101 | return $files; 102 | } 103 | 104 | function copyFile($root, $source, $target, &$all, $params) 105 | { 106 | if (!is_file($root . '/' . $source)) { 107 | echo " skip $target ($source not exist)\n"; 108 | return true; 109 | } 110 | if (is_file($root . '/' . $target)) { 111 | if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) { 112 | echo " unchanged $target\n"; 113 | return true; 114 | } 115 | if ($all) { 116 | echo " overwrite $target\n"; 117 | } else { 118 | echo " exist $target\n"; 119 | echo " ...overwrite? [Yes|No|All|Quit] "; 120 | 121 | 122 | $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN)); 123 | if (!strncasecmp($answer, 'q', 1)) { 124 | return false; 125 | } else { 126 | if (!strncasecmp($answer, 'y', 1)) { 127 | echo " overwrite $target\n"; 128 | } else { 129 | if (!strncasecmp($answer, 'a', 1)) { 130 | echo " overwrite $target\n"; 131 | $all = true; 132 | } else { 133 | echo " skip $target\n"; 134 | return true; 135 | } 136 | } 137 | } 138 | } 139 | file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); 140 | return true; 141 | } 142 | echo " generate $target\n"; 143 | @mkdir(dirname($root . '/' . $target), 0777, true); 144 | file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); 145 | return true; 146 | } 147 | 148 | function getParams() 149 | { 150 | $rawParams = []; 151 | if (isset($_SERVER['argv'])) { 152 | $rawParams = $_SERVER['argv']; 153 | array_shift($rawParams); 154 | } 155 | 156 | $params = []; 157 | foreach ($rawParams as $param) { 158 | if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) { 159 | $name = $matches[1]; 160 | $params[$name] = isset($matches[3]) ? $matches[3] : true; 161 | } else { 162 | $params[] = $param; 163 | } 164 | } 165 | return $params; 166 | } 167 | 168 | function setWritable($root, $paths) 169 | { 170 | foreach ($paths as $writable) { 171 | echo " chmod 0777 $writable\n"; 172 | @chmod("$root/$writable", 0777); 173 | } 174 | } 175 | 176 | function setExecutable($root, $paths) 177 | { 178 | foreach ($paths as $executable) { 179 | echo " chmod 0755 $executable\n"; 180 | @chmod("$root/$executable", 0755); 181 | } 182 | } 183 | 184 | function setCookieValidationKey($root, $paths) 185 | { 186 | foreach ($paths as $file) { 187 | echo " generate cookie validation key in $file\n"; 188 | $file = $root . '/' . $file; 189 | $length = 32; 190 | $bytes = openssl_random_pseudo_bytes($length); 191 | $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.'); 192 | $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file)); 193 | file_put_contents($file, $content); 194 | } 195 | } 196 | 197 | function createSymlink($links) 198 | { 199 | foreach ($links as $link => $target) { 200 | echo " symlink $target as $link\n"; 201 | if (!is_link($link)) { 202 | symlink($target, $link); 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /init.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem ------------------------------------------------------------- 4 | rem Yii command line init script for Windows. 5 | rem 6 | rem @author Qiang Xue 7 | rem @link http://www.yiiframework.com/ 8 | rem @copyright Copyright (c) 2008 Yii Software LLC 9 | rem @license http://www.yiiframework.com/license/ 10 | rem ------------------------------------------------------------- 11 | 12 | @setlocal 13 | 14 | set YII_PATH=%~dp0 15 | 16 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe 17 | 18 | "%PHP_COMMAND%" "%YII_PATH%init" %* 19 | 20 | @endlocal 21 | -------------------------------------------------------------------------------- /requirements.php: -------------------------------------------------------------------------------- 1 | Error'; 18 | echo '

The path to yii framework seems to be incorrect.

'; 19 | echo '

You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . '.

'; 20 | echo '

Please refer to the README on how to install Yii.

'; 21 | } 22 | 23 | require_once($frameworkPath . '/requirements/YiiRequirementChecker.php'); 24 | $requirementsChecker = new YiiRequirementChecker(); 25 | 26 | $gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.'; 27 | $gdOK = $imagickOK = false; 28 | 29 | if (extension_loaded('imagick')) { 30 | $imagick = new Imagick(); 31 | $imagickFormats = $imagick->queryFormats('PNG'); 32 | if (in_array('PNG', $imagickFormats)) { 33 | $imagickOK = true; 34 | } else { 35 | $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.'; 36 | } 37 | } 38 | 39 | if (extension_loaded('gd')) { 40 | $gdInfo = gd_info(); 41 | if (!empty($gdInfo['FreeType Support'])) { 42 | $gdOK = true; 43 | } else { 44 | $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.'; 45 | } 46 | } 47 | 48 | /** 49 | * Adjust requirements according to your application specifics. 50 | */ 51 | $requirements = array( 52 | // Database : 53 | array( 54 | 'name' => 'PDO extension', 55 | 'mandatory' => true, 56 | 'condition' => extension_loaded('pdo'), 57 | 'by' => 'All DB-related classes', 58 | ), 59 | array( 60 | 'name' => 'PDO SQLite extension', 61 | 'mandatory' => false, 62 | 'condition' => extension_loaded('pdo_sqlite'), 63 | 'by' => 'All DB-related classes', 64 | 'memo' => 'Required for SQLite database.', 65 | ), 66 | array( 67 | 'name' => 'PDO MySQL extension', 68 | 'mandatory' => false, 69 | 'condition' => extension_loaded('pdo_mysql'), 70 | 'by' => 'All DB-related classes', 71 | 'memo' => 'Required for MySQL database.', 72 | ), 73 | array( 74 | 'name' => 'PDO PostgreSQL extension', 75 | 'mandatory' => false, 76 | 'condition' => extension_loaded('pdo_pgsql'), 77 | 'by' => 'All DB-related classes', 78 | 'memo' => 'Required for PostgreSQL database.', 79 | ), 80 | // Cache : 81 | array( 82 | 'name' => 'Memcache extension', 83 | 'mandatory' => false, 84 | 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), 85 | 'by' => 'MemCache', 86 | 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : '' 87 | ), 88 | array( 89 | 'name' => 'APC extension', 90 | 'mandatory' => false, 91 | 'condition' => extension_loaded('apc'), 92 | 'by' => 'ApcCache', 93 | ), 94 | // CAPTCHA: 95 | array( 96 | 'name' => 'GD PHP extension with FreeType support', 97 | 'mandatory' => false, 98 | 'condition' => $gdOK, 99 | 'by' => 'Captcha', 100 | 'memo' => $gdMemo, 101 | ), 102 | array( 103 | 'name' => 'ImageMagick PHP extension with PNG support', 104 | 'mandatory' => false, 105 | 'condition' => $imagickOK, 106 | 'by' => 'Captcha', 107 | 'memo' => $imagickMemo, 108 | ), 109 | // PHP ini : 110 | 'phpExposePhp' => array( 111 | 'name' => 'Expose PHP', 112 | 'mandatory' => false, 113 | 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), 114 | 'by' => 'Security reasons', 115 | 'memo' => '"expose_php" should be disabled at php.ini', 116 | ), 117 | 'phpAllowUrlInclude' => array( 118 | 'name' => 'PHP allow url include', 119 | 'mandatory' => false, 120 | 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), 121 | 'by' => 'Security reasons', 122 | 'memo' => '"allow_url_include" should be disabled at php.ini', 123 | ), 124 | 'phpSmtp' => array( 125 | 'name' => 'PHP mail SMTP', 126 | 'mandatory' => false, 127 | 'condition' => strlen(ini_get('SMTP')) > 0, 128 | 'by' => 'Email sending', 129 | 'memo' => 'PHP mail SMTP server required', 130 | ), 131 | ); 132 | $requirementsChecker->checkYii()->check($requirements)->render(); 133 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | This directory contains various tests for the advanced applications. 2 | 3 | Tests in `codeception` directory are developed with [Codeception PHP Testing Framework](http://codeception.com/). 4 | 5 | After creating and setting up the advanced application, follow these steps to prepare for the tests: 6 | 7 | 1. Install Codeception if it's not yet installed: 8 | 9 | ``` 10 | composer global require "codeception/codeception=2.0.*" "codeception/specify=*" "codeception/verify=*" 11 | ``` 12 | 13 | If you've never used Composer for global packages run `composer global status`. It should output: 14 | 15 | ``` 16 | Changed current directory to 17 | ``` 18 | 19 | Then add `/vendor/bin` to you `PATH` environment variable. Now you're able to use `codecept` from command 20 | line globally. 21 | 22 | 2. Install faker extension by running the following from template root directory where `composer.json` is: 23 | 24 | ``` 25 | composer require --dev yiisoft/yii2-faker:* 26 | ``` 27 | 28 | 3. Create `yii2_advanced_tests` database then update it by applying migrations: 29 | 30 | ``` 31 | codeception/bin/yii migrate 32 | ``` 33 | 34 | 4. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in 35 | webserver. In the root directory where `common`, `frontend` etc. are execute the following: 36 | 37 | ``` 38 | php -S localhost:8080 39 | ``` 40 | 41 | 5. Now you can run the tests with the following commands, assuming you are in the `tests/codeception` directory: 42 | 43 | ``` 44 | # frontend tests 45 | cd frontend 46 | codecept build 47 | codecept run 48 | 49 | # backend tests 50 | 51 | cd backend 52 | codecept build 53 | codecept run 54 | 55 | # etc. 56 | ``` 57 | 58 | If you already have run `codecept build` for each application, you can skip that step and run all tests by a single `codecept run`. 59 | -------------------------------------------------------------------------------- /tests/codeception.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - codeception/common 3 | - codeception/console 4 | - codeception/backend 5 | - codeception/frontend 6 | 7 | paths: 8 | log: codeception/_output 9 | 10 | settings: 11 | colors: true 12 | -------------------------------------------------------------------------------- /tests/codeception/_output/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/codeception/backend/.gitignore: -------------------------------------------------------------------------------- 1 | # these files are auto generated by codeception build 2 | /unit/UnitTester.php 3 | /functional/FunctionalTester.php 4 | /acceptance/AcceptanceTester.php 5 | -------------------------------------------------------------------------------- /tests/codeception/backend/_bootstrap.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure login page works'); 10 | 11 | $loginPage = LoginPage::openBy($I); 12 | 13 | $I->amGoingTo('submit login form with no data'); 14 | $loginPage->login('', ''); 15 | if (method_exists($I, 'wait')) { 16 | $I->wait(3); // only for selenium 17 | } 18 | $I->expectTo('see validations errors'); 19 | $I->see('Username cannot be blank.', '.help-block'); 20 | $I->see('Password cannot be blank.', '.help-block'); 21 | 22 | $I->amGoingTo('try to login with wrong credentials'); 23 | $I->expectTo('see validations errors'); 24 | $loginPage->login('admin', 'wrong'); 25 | if (method_exists($I, 'wait')) { 26 | $I->wait(3); // only for selenium 27 | } 28 | $I->expectTo('see validations errors'); 29 | $I->see('Incorrect username or password.', '.help-block'); 30 | 31 | $I->amGoingTo('try to login with correct credentials'); 32 | $loginPage->login('erau', 'password_0'); 33 | if (method_exists($I, 'wait')) { 34 | $I->wait(3); // only for selenium 35 | } 36 | $I->expectTo('see that user is logged'); 37 | $I->seeLink('Logout (erau)'); 38 | $I->dontSeeLink('Login'); 39 | $I->dontSeeLink('Signup'); 40 | /** Uncomment if using WebDriver 41 | * $I->click('Logout (erau)'); 42 | * $I->dontSeeLink('Logout (erau)'); 43 | * $I->seeLink('Login'); 44 | */ 45 | -------------------------------------------------------------------------------- /tests/codeception/backend/acceptance/_bootstrap.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure login page works'); 10 | 11 | $loginPage = LoginPage::openBy($I); 12 | 13 | $I->amGoingTo('submit login form with no data'); 14 | $loginPage->login('', ''); 15 | $I->expectTo('see validations errors'); 16 | $I->see('Username cannot be blank.', '.help-block'); 17 | $I->see('Password cannot be blank.', '.help-block'); 18 | 19 | $I->amGoingTo('try to login with wrong credentials'); 20 | $I->expectTo('see validations errors'); 21 | $loginPage->login('admin', 'wrong'); 22 | $I->expectTo('see validations errors'); 23 | $I->see('Incorrect username or password.', '.help-block'); 24 | 25 | $I->amGoingTo('try to login with correct credentials'); 26 | $loginPage->login('erau', 'password_0'); 27 | $I->expectTo('see that user is logged'); 28 | $I->seeLink('Logout (erau)'); 29 | $I->dontSeeLink('Login'); 30 | $I->dontSeeLink('Signup'); 31 | -------------------------------------------------------------------------------- /tests/codeception/backend/functional/_bootstrap.php: -------------------------------------------------------------------------------- 1 | run(); 23 | exit($exitCode); 24 | -------------------------------------------------------------------------------- /tests/codeception/bin/yii.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem ------------------------------------------------------------- 4 | rem Yii command line bootstrap script for Windows. 5 | rem 6 | rem @author Qiang Xue 7 | rem @link http://www.yiiframework.com/ 8 | rem @copyright Copyright (c) 2008 Yii Software LLC 9 | rem @license http://www.yiiframework.com/license/ 10 | rem ------------------------------------------------------------- 11 | 12 | @setlocal 13 | 14 | set YII_PATH=%~dp0 15 | 16 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe 17 | 18 | "%PHP_COMMAND%" "%YII_PATH%yii" %* 19 | 20 | @endlocal 21 | -------------------------------------------------------------------------------- /tests/codeception/common/.gitignore: -------------------------------------------------------------------------------- 1 | # these files are auto generated by codeception build 2 | /unit/UnitTester.php 3 | /functional/FunctionalTester.php 4 | /acceptance/AcceptanceTester.php 5 | -------------------------------------------------------------------------------- /tests/codeception/common/_bootstrap.php: -------------------------------------------------------------------------------- 1 | actor->fillField('input[name="LoginForm[username]"]', $username); 22 | $this->actor->fillField('input[name="LoginForm[password]"]', $password); 23 | $this->actor->click('login-button'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/codeception/common/_support/FixtureHelper.php: -------------------------------------------------------------------------------- 1 | loadFixtures(); 38 | } 39 | 40 | /** 41 | * Method is called after all suite tests run 42 | */ 43 | public function _afterSuite() 44 | { 45 | $this->unloadFixtures(); 46 | } 47 | 48 | /** 49 | * @inheritdoc 50 | */ 51 | public function fixtures() 52 | { 53 | return [ 54 | 'user' => [ 55 | 'class' => UserFixture::className(), 56 | 'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php', 57 | ], 58 | ]; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/codeception/common/codeception.yml: -------------------------------------------------------------------------------- 1 | namespace: tests\codeception\common 2 | actor: Tester 3 | paths: 4 | tests: . 5 | log: _output 6 | data: _data 7 | helpers: _support 8 | settings: 9 | bootstrap: _bootstrap.php 10 | suite_class: \PHPUnit_Framework_TestSuite 11 | colors: true 12 | memory_limit: 1024M 13 | log: true 14 | -------------------------------------------------------------------------------- /tests/codeception/common/fixtures/UserFixture.php: -------------------------------------------------------------------------------- 1 | 'erau', 6 | 'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI', 7 | // password_0 8 | 'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne', 9 | 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490', 10 | 'created_at' => '1392559490', 11 | 'updated_at' => '1392559490', 12 | 'email' => 'sfriesen@jenkins.info', 13 | ], 14 | ]; 15 | -------------------------------------------------------------------------------- /tests/codeception/common/templates/fixtures/user.php: -------------------------------------------------------------------------------- 1 | getSecurity(); 8 | 9 | return [ 10 | 'username' => $faker->userName, 11 | 'email' => $faker->email, 12 | 'auth_key' => $security->generateRandomString(), 13 | 'password_hash' => $security->generatePasswordHash('password_' . $index), 14 | 'password_reset_token' => $security->generateRandomString() . '_' . time(), 15 | 'created_at' => time(), 16 | 'updated_at' => time(), 17 | ]; 18 | -------------------------------------------------------------------------------- /tests/codeception/common/unit.suite.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | 3 | # suite for unit (internal) tests. 4 | # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. 5 | 6 | class_name: UnitTester 7 | -------------------------------------------------------------------------------- /tests/codeception/common/unit/DbTestCase.php: -------------------------------------------------------------------------------- 1 | 'bayer.hudson', 6 | 'auth_key' => 'HP187Mvq7Mmm3CTU80dLkGmni_FUH_lR', 7 | //password_0 8 | 'password_hash' => '$2y$13$EjaPFBnZOQsHdGuHI.xvhuDp1fHpo8hKRSk6yshqa9c5EG8s3C3lO', 9 | 'password_reset_token' => 'ExzkCOaYc1L8IOBs4wdTGGbgNiG3Wz1I_1402312317', 10 | 'created_at' => '1402312317', 11 | 'updated_at' => '1402312317', 12 | 'email' => 'nicole.paucek@schultz.info', 13 | ], 14 | ]; 15 | -------------------------------------------------------------------------------- /tests/codeception/common/unit/models/LoginFormTest.php: -------------------------------------------------------------------------------- 1 | [ 25 | 'user' => [ 26 | 'class' => 'yii\web\User', 27 | 'identityClass' => 'common\models\User', 28 | ], 29 | ], 30 | ]); 31 | } 32 | 33 | protected function tearDown() 34 | { 35 | Yii::$app->user->logout(); 36 | parent::tearDown(); 37 | } 38 | 39 | public function testLoginNoUser() 40 | { 41 | $model = new LoginForm([ 42 | 'username' => 'not_existing_username', 43 | 'password' => 'not_existing_password', 44 | ]); 45 | 46 | $this->specify('user should not be able to login, when there is no identity', function () use ($model) { 47 | expect('model should not login user', $model->login())->false(); 48 | expect('user should not be logged in', Yii::$app->user->isGuest)->true(); 49 | }); 50 | } 51 | 52 | public function testLoginWrongPassword() 53 | { 54 | $model = new LoginForm([ 55 | 'username' => 'bayer.hudson', 56 | 'password' => 'wrong_password', 57 | ]); 58 | 59 | $this->specify('user should not be able to login with wrong password', function () use ($model) { 60 | expect('model should not login user', $model->login())->false(); 61 | expect('error message should be set', $model->errors)->hasKey('password'); 62 | expect('user should not be logged in', Yii::$app->user->isGuest)->true(); 63 | }); 64 | } 65 | 66 | public function testLoginCorrect() 67 | { 68 | 69 | $model = new LoginForm([ 70 | 'username' => 'bayer.hudson', 71 | 'password' => 'password_0', 72 | ]); 73 | 74 | $this->specify('user should be able to login with correct credentials', function () use ($model) { 75 | expect('model should login user', $model->login())->true(); 76 | expect('error message should not be set', $model->errors)->hasntKey('password'); 77 | expect('user should be logged in', Yii::$app->user->isGuest)->false(); 78 | }); 79 | } 80 | 81 | /** 82 | * @inheritdoc 83 | */ 84 | public function fixtures() 85 | { 86 | return [ 87 | 'user' => [ 88 | 'class' => UserFixture::className(), 89 | 'dataFile' => '@tests/codeception/common/unit/fixtures/data/models/user.php' 90 | ], 91 | ]; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /tests/codeception/config/acceptance.php: -------------------------------------------------------------------------------- 1 | 'app-common', 12 | 'basePath' => dirname(__DIR__), 13 | ] 14 | ); 15 | -------------------------------------------------------------------------------- /tests/codeception/config/config.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'fixture' => [ 8 | 'class' => 'yii\faker\FixtureController', 9 | 'fixtureDataPath' => '@tests/codeception/common/fixtures/data', 10 | 'templatePath' => '@tests/codeception/common/templates/fixtures', 11 | 'namespace' => 'tests\codeception\common\fixtures', 12 | ], 13 | ], 14 | 'components' => [ 15 | 'db' => [ 16 | 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_tests', 17 | ], 18 | 'mailer' => [ 19 | 'useFileTransport' => true, 20 | ], 21 | 'urlManager' => [ 22 | 'showScriptName' => true, 23 | ], 24 | ], 25 | ]; 26 | -------------------------------------------------------------------------------- /tests/codeception/config/console/unit.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'request' => [ 8 | // it's not recommended to run functional tests with CSRF validation enabled 9 | 'enableCsrfValidation' => false, 10 | // but if you absolutely need it set cookie domain to localhost 11 | /* 12 | 'csrfCookie' => [ 13 | 'domain' => 'localhost', 14 | ], 15 | */ 16 | ], 17 | ], 18 | ]; -------------------------------------------------------------------------------- /tests/codeception/config/unit.php: -------------------------------------------------------------------------------- 1 | $value) { 21 | $inputType = $field === 'body' ? 'textarea' : 'input'; 22 | $this->actor->fillField($inputType . '[name="ContactForm[' . $field . ']"]', $value); 23 | } 24 | $this->actor->click('contact-button'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/codeception/frontend/_pages/SignupPage.php: -------------------------------------------------------------------------------- 1 | $value) { 22 | $inputType = $field === 'body' ? 'textarea' : 'input'; 23 | $this->actor->fillField($inputType . '[name="SignupForm[' . $field . ']"]', $value); 24 | } 25 | $this->actor->click('signup-button'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance.suite.yml: -------------------------------------------------------------------------------- 1 | # Codeception Test Suite Configuration 2 | 3 | # suite for acceptance tests. 4 | # perform tests in browser using the Selenium-like tools. 5 | # powered by Mink (http://mink.behat.org). 6 | # (tip: that's what your customer will see). 7 | # (tip: test your ajax and javascript by one of Mink drivers). 8 | 9 | # RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. 10 | 11 | class_name: AcceptanceTester 12 | modules: 13 | enabled: 14 | - PhpBrowser 15 | - tests\codeception\common\_support\FixtureHelper 16 | # you can use WebDriver instead of PhpBrowser to test javascript and ajax. 17 | # This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium 18 | # "restart" option is used by the WebDriver to start each time per test-file new session and cookies, 19 | # it is useful if you want to login in your app in each test. 20 | # - WebDriver 21 | config: 22 | PhpBrowser: 23 | # PLEASE ADJUST IT TO THE ACTUAL ENTRY POINT WITHOUT PATH INFO 24 | url: http://localhost:8080 25 | # WebDriver: 26 | # url: http://localhost:8080 27 | # browser: firefox 28 | # restart: true 29 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/AboutCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that about works'); 9 | AboutPage::openBy($I); 10 | $I->see('About', 'h1'); 11 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/ContactCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that contact works'); 9 | 10 | $contactPage = ContactPage::openBy($I); 11 | 12 | $I->see('Contact', 'h1'); 13 | 14 | $I->amGoingTo('submit contact form with no data'); 15 | $contactPage->submit([]); 16 | if (method_exists($I, 'wait')) { 17 | $I->wait(3); // only for selenium 18 | } 19 | $I->expectTo('see validations errors'); 20 | $I->see('Contact', 'h1'); 21 | $I->see('Name cannot be blank', '.help-block'); 22 | $I->see('Email cannot be blank', '.help-block'); 23 | $I->see('Subject cannot be blank', '.help-block'); 24 | $I->see('Body cannot be blank', '.help-block'); 25 | $I->see('The verification code is incorrect', '.help-block'); 26 | 27 | $I->amGoingTo('submit contact form with not correct email'); 28 | $contactPage->submit([ 29 | 'name' => 'tester', 30 | 'email' => 'tester.email', 31 | 'subject' => 'test subject', 32 | 'body' => 'test content', 33 | 'verifyCode' => 'testme', 34 | ]); 35 | if (method_exists($I, 'wait')) { 36 | $I->wait(3); // only for selenium 37 | } 38 | $I->expectTo('see that email adress is wrong'); 39 | $I->dontSee('Name cannot be blank', '.help-block'); 40 | $I->see('Email is not a valid email address.', '.help-block'); 41 | $I->dontSee('Subject cannot be blank', '.help-block'); 42 | $I->dontSee('Body cannot be blank', '.help-block'); 43 | $I->dontSee('The verification code is incorrect', '.help-block'); 44 | 45 | $I->amGoingTo('submit contact form with correct data'); 46 | $contactPage->submit([ 47 | 'name' => 'tester', 48 | 'email' => 'tester@example.com', 49 | 'subject' => 'test subject', 50 | 'body' => 'test content', 51 | 'verifyCode' => 'testme', 52 | ]); 53 | if (method_exists($I, 'wait')) { 54 | $I->wait(3); // only for selenium 55 | } 56 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.'); 57 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/HomeCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that home page works'); 8 | $I->amOnPage(Yii::$app->homeUrl); 9 | $I->see('My Company'); 10 | $I->seeLink('About'); 11 | $I->click('About'); 12 | $I->see('This is the About page.'); 13 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/LoginCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure login page works'); 9 | 10 | $loginPage = LoginPage::openBy($I); 11 | 12 | $I->amGoingTo('submit login form with no data'); 13 | $loginPage->login('', ''); 14 | $I->expectTo('see validations errors'); 15 | $I->see('Username cannot be blank.', '.help-block'); 16 | $I->see('Password cannot be blank.', '.help-block'); 17 | 18 | $I->amGoingTo('try to login with wrong credentials'); 19 | $I->expectTo('see validations errors'); 20 | $loginPage->login('admin', 'wrong'); 21 | $I->expectTo('see validations errors'); 22 | $I->see('Incorrect username or password.', '.help-block'); 23 | 24 | $I->amGoingTo('try to login with correct credentials'); 25 | $loginPage->login('erau', 'password_0'); 26 | $I->expectTo('see that user is logged'); 27 | $I->seeLink('Logout (erau)'); 28 | $I->dontSeeLink('Login'); 29 | $I->dontSeeLink('Signup'); 30 | /** Uncomment if using WebDriver 31 | * $I->click('Logout (erau)'); 32 | * $I->dontSeeLink('Logout (erau)'); 33 | * $I->seeLink('Login'); 34 | */ 35 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/SignupCest.php: -------------------------------------------------------------------------------- 1 | 'tester.email@example.com', 27 | 'username' => 'tester', 28 | ]); 29 | } 30 | 31 | /** 32 | * This method is called when test fails. 33 | * @param \Codeception\Event\FailEvent $event 34 | */ 35 | public function _fail($event) 36 | { 37 | } 38 | 39 | /** 40 | * @param \codeception_frontend\AcceptanceTester $I 41 | * @param \Codeception\Scenario $scenario 42 | */ 43 | public function testUserSignup($I, $scenario) 44 | { 45 | $I->wantTo('ensure that signup works'); 46 | 47 | $signupPage = SignupPage::openBy($I); 48 | $I->see('Signup', 'h1'); 49 | $I->see('Please fill out the following fields to signup:'); 50 | 51 | $I->amGoingTo('submit signup form with no data'); 52 | 53 | $signupPage->submit([]); 54 | 55 | $I->expectTo('see validation errors'); 56 | $I->see('Username cannot be blank.', '.help-block'); 57 | $I->see('Email cannot be blank.', '.help-block'); 58 | $I->see('Password cannot be blank.', '.help-block'); 59 | 60 | $I->amGoingTo('submit signup form with not correct email'); 61 | $signupPage->submit([ 62 | 'username' => 'tester', 63 | 'email' => 'tester.email', 64 | 'password' => 'tester_password', 65 | ]); 66 | 67 | $I->expectTo('see that email address is wrong'); 68 | $I->dontSee('Username cannot be blank.', '.help-block'); 69 | $I->dontSee('Password cannot be blank.', '.help-block'); 70 | $I->see('Email is not a valid email address.', '.help-block'); 71 | 72 | $I->amGoingTo('submit signup form with correct email'); 73 | $signupPage->submit([ 74 | 'username' => 'tester', 75 | 'email' => 'tester.email@example.com', 76 | 'password' => 'tester_password', 77 | ]); 78 | 79 | $I->expectTo('see that user logged in'); 80 | $I->seeLink('Logout (tester)'); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/_bootstrap.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that about works'); 9 | AboutPage::openBy($I); 10 | $I->see('About', 'h1'); 11 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/ContactCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that contact works'); 9 | 10 | $contactPage = ContactPage::openBy($I); 11 | 12 | $I->see('Contact', 'h1'); 13 | 14 | $I->amGoingTo('submit contact form with no data'); 15 | $contactPage->submit([]); 16 | $I->expectTo('see validations errors'); 17 | $I->see('Contact', 'h1'); 18 | $I->see('Name cannot be blank', '.help-block'); 19 | $I->see('Email cannot be blank', '.help-block'); 20 | $I->see('Subject cannot be blank', '.help-block'); 21 | $I->see('Body cannot be blank', '.help-block'); 22 | $I->see('The verification code is incorrect', '.help-block'); 23 | 24 | $I->amGoingTo('submit contact form with not correct email'); 25 | $contactPage->submit([ 26 | 'name' => 'tester', 27 | 'email' => 'tester.email', 28 | 'subject' => 'test subject', 29 | 'body' => 'test content', 30 | 'verifyCode' => 'testme', 31 | ]); 32 | $I->expectTo('see that email adress is wrong'); 33 | $I->dontSee('Name cannot be blank', '.help-block'); 34 | $I->see('Email is not a valid email address.', '.help-block'); 35 | $I->dontSee('Subject cannot be blank', '.help-block'); 36 | $I->dontSee('Body cannot be blank', '.help-block'); 37 | $I->dontSee('The verification code is incorrect', '.help-block'); 38 | 39 | $I->amGoingTo('submit contact form with correct data'); 40 | $contactPage->submit([ 41 | 'name' => 'tester', 42 | 'email' => 'tester@example.com', 43 | 'subject' => 'test subject', 44 | 'body' => 'test content', 45 | 'verifyCode' => 'testme', 46 | ]); 47 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.'); 48 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/HomeCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that home page works'); 8 | $I->amOnPage(Yii::$app->homeUrl); 9 | $I->see('My Company'); 10 | $I->seeLink('About'); 11 | $I->click('About'); 12 | $I->see('This is the About page.'); 13 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/LoginCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure login page works'); 9 | 10 | $loginPage = LoginPage::openBy($I); 11 | 12 | $I->amGoingTo('submit login form with no data'); 13 | $loginPage->login('', ''); 14 | $I->expectTo('see validations errors'); 15 | $I->see('Username cannot be blank.', '.help-block'); 16 | $I->see('Password cannot be blank.', '.help-block'); 17 | 18 | $I->amGoingTo('try to login with wrong credentials'); 19 | $I->expectTo('see validations errors'); 20 | $loginPage->login('admin', 'wrong'); 21 | $I->expectTo('see validations errors'); 22 | $I->see('Incorrect username or password.', '.help-block'); 23 | 24 | $I->amGoingTo('try to login with correct credentials'); 25 | $loginPage->login('erau', 'password_0'); 26 | $I->expectTo('see that user is logged'); 27 | $I->seeLink('Logout (erau)'); 28 | $I->dontSeeLink('Login'); 29 | $I->dontSeeLink('Signup'); 30 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/SignupCest.php: -------------------------------------------------------------------------------- 1 | 'tester.email@example.com', 27 | 'username' => 'tester', 28 | ]); 29 | } 30 | 31 | /** 32 | * This method is called when test fails. 33 | * @param \Codeception\Event\FailEvent $event 34 | */ 35 | public function _fail($event) 36 | { 37 | 38 | } 39 | 40 | /** 41 | * 42 | * @param \codeception_frontend\FunctionalTester $I 43 | * @param \Codeception\Scenario $scenario 44 | */ 45 | public function testUserSignup($I, $scenario) 46 | { 47 | $I->wantTo('ensure that signup works'); 48 | 49 | $signupPage = SignupPage::openBy($I); 50 | $I->see('Signup', 'h1'); 51 | $I->see('Please fill out the following fields to signup:'); 52 | 53 | $I->amGoingTo('submit signup form with no data'); 54 | 55 | $signupPage->submit([]); 56 | 57 | $I->expectTo('see validation errors'); 58 | $I->see('Username cannot be blank.', '.help-block'); 59 | $I->see('Email cannot be blank.', '.help-block'); 60 | $I->see('Password cannot be blank.', '.help-block'); 61 | 62 | $I->amGoingTo('submit signup form with not correct email'); 63 | $signupPage->submit([ 64 | 'username' => 'tester', 65 | 'email' => 'tester.email', 66 | 'password' => 'tester_password', 67 | ]); 68 | 69 | $I->expectTo('see that email address is wrong'); 70 | $I->dontSee('Username cannot be blank.', '.help-block'); 71 | $I->dontSee('Password cannot be blank.', '.help-block'); 72 | $I->see('Email is not a valid email address.', '.help-block'); 73 | 74 | $I->amGoingTo('submit signup form with correct email'); 75 | $signupPage->submit([ 76 | 'username' => 'tester', 77 | 'email' => 'tester.email@example.com', 78 | 'password' => 'tester_password', 79 | ]); 80 | 81 | $I->expectTo('see that user is created'); 82 | $I->seeRecord('common\models\User', [ 83 | 'username' => 'tester', 84 | 'email' => 'tester.email@example.com', 85 | ]); 86 | 87 | $I->expectTo('see that user logged in'); 88 | $I->seeLink('Logout (tester)'); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/_bootstrap.php: -------------------------------------------------------------------------------- 1 | 'okirlin', 6 | 'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv', 7 | 'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi', 8 | 'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_' . time(), 9 | 'created_at' => '1391885313', 10 | 'updated_at' => '1391885313', 11 | 'email' => 'brady.renner@rutherford.com', 12 | ], 13 | [ 14 | 'username' => 'troy.becker', 15 | 'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp', 16 | 'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2', 17 | 'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_' . time(), 18 | 'created_at' => '1391885313', 19 | 'updated_at' => '1391885313', 20 | 'email' => 'nicolas.dianna@hotmail.com', 21 | 'status' => '0', 22 | ], 23 | ]; 24 | -------------------------------------------------------------------------------- /tests/codeception/frontend/unit/models/ContactFormTest.php: -------------------------------------------------------------------------------- 1 | mailer->fileTransportCallback = function ($mailer, $message) { 18 | return 'testing_message.eml'; 19 | }; 20 | } 21 | 22 | protected function tearDown() 23 | { 24 | unlink($this->getMessageFile()); 25 | parent::tearDown(); 26 | } 27 | 28 | public function testContact() 29 | { 30 | $model = new ContactForm(); 31 | 32 | $model->attributes = [ 33 | 'name' => 'Tester', 34 | 'email' => 'tester@example.com', 35 | 'subject' => 'very important letter subject', 36 | 'body' => 'body of current message', 37 | ]; 38 | 39 | $model->sendEmail('admin@example.com'); 40 | 41 | $this->specify('email should be send', function () { 42 | expect('email file should exist', file_exists($this->getMessageFile()))->true(); 43 | }); 44 | 45 | $this->specify('message should contain correct data', function () use ($model) { 46 | $emailMessage = file_get_contents($this->getMessageFile()); 47 | 48 | expect('email should contain user name', $emailMessage)->contains($model->name); 49 | expect('email should contain sender email', $emailMessage)->contains($model->email); 50 | expect('email should contain subject', $emailMessage)->contains($model->subject); 51 | expect('email should contain body', $emailMessage)->contains($model->body); 52 | }); 53 | } 54 | 55 | private function getMessageFile() 56 | { 57 | return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml'; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/codeception/frontend/unit/models/PasswordResetRequestFormTest.php: -------------------------------------------------------------------------------- 1 | mailer->fileTransportCallback = function ($mailer, $message) { 21 | return 'testing_message.eml'; 22 | }; 23 | } 24 | 25 | protected function tearDown() 26 | { 27 | @unlink($this->getMessageFile()); 28 | 29 | parent::tearDown(); 30 | } 31 | 32 | public function testSendEmailWrongUser() 33 | { 34 | $this->specify('no user with such email, message should not be send', function () { 35 | 36 | $model = new PasswordResetRequestForm(); 37 | $model->email = 'not-existing-email@example.com'; 38 | 39 | expect('email not send', $model->sendEmail())->false(); 40 | 41 | }); 42 | 43 | $this->specify('user is not active, message should not be send', function () { 44 | 45 | $model = new PasswordResetRequestForm(); 46 | $model->email = $this->user[1]['email']; 47 | 48 | expect('email not send', $model->sendEmail())->false(); 49 | 50 | }); 51 | } 52 | 53 | public function testSendEmailCorrectUser() 54 | { 55 | $model = new PasswordResetRequestForm(); 56 | $model->email = $this->user[0]['email']; 57 | $user = User::findOne(['password_reset_token' => $this->user[0]['password_reset_token']]); 58 | 59 | expect('email sent', $model->sendEmail())->true(); 60 | expect('user has valid token', $user->password_reset_token)->notNull(); 61 | 62 | $this->specify('message has correct format', function () use ($model) { 63 | 64 | expect('message file exists', file_exists($this->getMessageFile()))->true(); 65 | 66 | $message = file_get_contents($this->getMessageFile()); 67 | expect('message "from" is correct', $message)->contains(Yii::$app->params['supportEmail']); 68 | expect('message "to" is correct', $message)->contains($model->email); 69 | 70 | }); 71 | } 72 | 73 | public function fixtures() 74 | { 75 | return [ 76 | 'user' => [ 77 | 'class' => UserFixture::className(), 78 | 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php' 79 | ], 80 | ]; 81 | } 82 | 83 | private function getMessageFile() 84 | { 85 | return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml'; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /tests/codeception/frontend/unit/models/ResetPasswordFormTest.php: -------------------------------------------------------------------------------- 1 | user[0]['password_reset_token']); 31 | expect('password should be resetted', $form->resetPassword())->true(); 32 | } 33 | 34 | public function fixtures() 35 | { 36 | return [ 37 | 'user' => [ 38 | 'class' => UserFixture::className(), 39 | 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php' 40 | ], 41 | ]; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tests/codeception/frontend/unit/models/SignupFormTest.php: -------------------------------------------------------------------------------- 1 | 'some_username', 19 | 'email' => 'some_email@example.com', 20 | 'password' => 'some_password', 21 | ]); 22 | 23 | $user = $model->signup(); 24 | 25 | $this->assertInstanceOf('common\models\User', $user, 'user should be valid'); 26 | 27 | expect('username should be correct', $user->username)->equals('some_username'); 28 | expect('email should be correct', $user->email)->equals('some_email@example.com'); 29 | expect('password should be correct', $user->validatePassword('some_password'))->true(); 30 | } 31 | 32 | public function testNotCorrectSignup() 33 | { 34 | $model = new SignupForm([ 35 | 'username' => 'troy.becker', 36 | 'email' => 'nicolas.dianna@hotmail.com', 37 | 'password' => 'some_password', 38 | ]); 39 | 40 | expect('username and email are in use, user should not be created', $model->signup())->null(); 41 | } 42 | 43 | public function fixtures() 44 | { 45 | return [ 46 | 'user' => [ 47 | 'class' => UserFixture::className(), 48 | 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php', 49 | ], 50 | ]; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /yii.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem ------------------------------------------------------------- 4 | rem Yii command line bootstrap script for Windows. 5 | rem 6 | rem @author Qiang Xue 7 | rem @link http://www.yiiframework.com/ 8 | rem @copyright Copyright (c) 2008 Yii Software LLC 9 | rem @license http://www.yiiframework.com/license/ 10 | rem ------------------------------------------------------------- 11 | 12 | @setlocal 13 | 14 | set YII_PATH=%~dp0 15 | 16 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe 17 | 18 | "%PHP_COMMAND%" "%YII_PATH%yii" %* 19 | 20 | @endlocal 21 | --------------------------------------------------------------------------------