├── .bowerrc ├── .gitignore ├── LICENSE.md ├── README.md ├── backend ├── assets │ ├── AppAsset.php │ ├── BootstrapjsAsset.php │ ├── LoginAsset.php │ └── TreeAsset.php ├── behaviors │ └── TestBehavior.php ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── main.php │ └── params.php ├── controllers │ ├── BackendController.php │ ├── HomeController.php │ ├── RbacController.php │ ├── RestfulController.php │ ├── SysController.php │ ├── TestController.php │ └── UserController.php ├── models │ ├── .gitkeep │ ├── AuthAssignment.php │ ├── AuthItem.php │ ├── LoginForm.php │ ├── TAdmUser.php │ ├── TMenu.php │ └── forsearch │ │ └── TAdmUserSearch.php ├── runtime │ └── .gitignore ├── views │ ├── home │ │ ├── _menu.php │ │ ├── error.php │ │ └── index.php │ ├── layouts │ │ ├── main-login.php │ │ └── main.php │ ├── rbac │ │ ├── _form.php │ │ ├── assignauth.php │ │ ├── assignrole.php │ │ ├── create.php │ │ ├── roles.php │ │ └── update.php │ ├── sys │ │ ├── _form.php │ │ ├── create.php │ │ ├── index.php │ │ └── update.php │ └── user │ │ ├── changepwd.php │ │ ├── index.php │ │ ├── loadhtml.php │ │ ├── login.php │ │ └── setphoto.php └── web │ ├── .gitignore │ ├── .htaccess │ ├── assets │ └── .gitignore │ ├── css │ ├── ace-rtl.min.css │ ├── ace-skins.min.css │ ├── ace.min.css │ ├── font-awesome.min.css │ ├── jquery.datetimepicker.css │ └── treeview.css │ ├── favicon.ico │ ├── font │ └── fontawesome-webfont.woff │ ├── images │ └── user.jpg │ ├── js │ ├── ace-elements.min.js │ ├── ace-extra.min.js │ ├── ace.min.js │ ├── bootstrap.min.js │ ├── jquery.cookie.js │ ├── jquery.datetimepicker.js │ └── typeahead-bs2.min.js │ ├── robots.txt │ └── upload │ └── user │ └── default.jpg ├── common ├── components │ └── MyHelper.php ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── db.php │ ├── main.php │ └── params.php ├── mail │ ├── layouts │ │ └── html.php │ └── passwordResetToken.php ├── models │ ├── LoginForm.php │ └── User.php └── widgets │ ├── DateTimePicker.php │ └── DateTimePickerAsset.php ├── composer.json ├── composer.lock ├── console ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── main.php │ └── params.php ├── controllers │ └── .gitkeep ├── migrations │ ├── m130524_201442_init.php │ ├── m141022_124022_create_menutable.php │ └── m141101_015745_createtable_admin_user.php ├── models │ └── .gitkeep └── runtime │ └── .gitignore ├── 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 │ └── AppAsset.php ├── config │ ├── .gitignore │ ├── bootstrap.php │ ├── main.php │ └── params.php ├── controllers │ └── SiteController.php ├── models │ ├── ContactForm.php │ ├── PasswordResetRequestForm.php │ ├── ResetPasswordForm.php │ └── SignupForm.php ├── runtime │ └── .gitignore ├── views │ ├── layouts │ │ └── main.php │ └── site │ │ ├── about.php │ │ ├── contact.php │ │ ├── error.php │ │ ├── index.php │ │ ├── login.php │ │ ├── requestPasswordResetToken.php │ │ ├── resetPassword.php │ │ └── signup.php ├── web │ ├── .gitignore │ ├── assets │ │ └── .gitignore │ ├── css │ │ └── site.css │ ├── favicon.ico │ └── robots.txt └── widgets │ └── Alert.php ├── 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 └── img │ ├── demo1.jpg │ ├── demo2.png │ └── demo3.png └── 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 | Yii2开发的后台管理系统 2 | =================================== 3 | 4 | 用Yii2.0.0开发的后台管理系统.通过RBAC控制不同用户的菜单显示以及权限。 5 | 6 | 7 | 安装 8 | ------------ 9 | 10 | 1. 直接运行`git clone https://github.com/BigKuCha/yga.git`克隆到工作目录,或者直接下载zip包 11 | 2. 运行`composer update --prefer-dist` 安装yii2核心文件 12 | 3. 创建数据库 `nevermore` 编码 `utf8-unicode-ci` 13 | 4. 在项目根目录下运行`init` 初始化项目(生成入口脚本、创建runtime目录等) 14 | 5. 删除`common/config/main-local.php`里的db配置(采用`common/config/db.php`里的就可以) 15 | 5. 运行`yii migrate`导入菜单表`t_menu`和用户表`t_admin_user` 16 | 6. 运行`yii migrate --migrationPath=@yii/rbac/migrations/`导入Yii官方提供的权限控制表 17 | 18 | 配置 19 | ------------- 20 | 21 | ### Apache 22 | 开启apache的rewite模块,网站根目录指向`web/` 23 | **NOTE:** 如果不开启rewite,需要重新配置路由 24 | 25 | 图示 26 | ------------ 27 | ![image](https://github.com/BigKuCha/yga/blob/master/tests/img/demo1.jpg) 28 | ![image](https://github.com/BigKuCha/yga/blob/master/tests/img/demo2.png) 29 | ![image](https://github.com/BigKuCha/yga/blob/master/tests/img/demo3.png) 30 | 31 | ------------ 32 | 33 | ### 关于Yii2 34 | Yii官方网站 [yiiframework.com](http://www.yiiframework.com) 35 | Yii2仓库地址[yiisoft/yii2](https://github.com/yiisoft/yii2) 36 | -------------------------------------------------------------------------------- /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/font-awesome.min.css', 22 | 'css/ace.min.css', 23 | 'css/ace-rtl.min.css', 24 | 'css/ace-skins.min.css', 25 | ]; 26 | public $js = [ 27 | 'js/ace-extra.min.js', 28 | 'js/typeahead-bs2.min.js', 29 | 'js/ace-elements.min.js', 30 | 'js/ace.min.js', 31 | 'js/jquery.cookie.js' 32 | ]; 33 | public $depends = [ 34 | 'backend\assets\BootstrapjsAsset', 35 | 'yii\bootstrap\BootstrapAsset', 36 | ]; 37 | } 38 | -------------------------------------------------------------------------------- /backend/assets/BootstrapjsAsset.php: -------------------------------------------------------------------------------- 1 | 14 | * @since 2.0 15 | */ 16 | class BootstrapjsAsset extends AssetBundle 17 | { 18 | public $sourcePath = '@bower/bootstrap/dist'; 19 | public $js = [ 20 | 'js/bootstrap.js', 21 | ]; 22 | public $depends = [ 23 | 'yii\web\JqueryAsset', 24 | ]; 25 | } 26 | -------------------------------------------------------------------------------- /backend/assets/LoginAsset.php: -------------------------------------------------------------------------------- 1 | 'myafter', 26 | ]; 27 | } 28 | 29 | public function myafter() 30 | { 31 | echo '我来自TestBehavior!' . $this->msg . '
'; 32 | } 33 | 34 | public static function Say() 35 | { 36 | echo "我是来自TestBehavior的静态方法
"; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /backend/config/.gitignore: -------------------------------------------------------------------------------- 1 | main-local.php 2 | params-local.php -------------------------------------------------------------------------------- /backend/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | 'app-backend', 9 | 'basePath' => dirname(__DIR__), 10 | 'defaultRoute'=>'home', 11 | 'language'=>'zh-CN', 12 | 'controllerNamespace' => 'backend\controllers', 13 | 'bootstrap' => ['log'], 14 | 'modules' => [ 15 | 'admin' => [ 16 | 'class' => 'mdm\admin\Module', 17 | ] 18 | ], 19 | 'components' => [ 20 | 'user' => [ 21 | 'identityClass' => 'backend\models\TAdmUser', 22 | 'enableAutoLogin' => true, 23 | ], 24 | 'request'=>[ 25 | 'enableCsrfValidation'=>false, 26 | ], 27 | 'log' => [ 28 | 'traceLevel' => YII_DEBUG ? 3 : 0, 29 | 'targets' => [ 30 | [ 31 | 'class' => 'yii\log\FileTarget', 32 | 'levels' => ['error', 'warning'], 33 | ], 34 | ], 35 | ], 36 | 'errorHandler' => [ 37 | 'errorAction' => 'home/error', 38 | ], 39 | 'urlManager' => [ 40 | 'enablePrettyUrl' => true, 41 | 'showScriptName' => false, 42 | 'rules'=>[ 43 | '/'=>'/', 44 | ['class' => 'yii\rest\UrlRule', 'controller' => 'user'], 45 | ], 46 | ], 47 | 'authManager'=>[ 48 | 'class'=>'yii\rbac\DbManager' 49 | ] 50 | ], 51 | 'params' => $params, 52 | ]; 53 | -------------------------------------------------------------------------------- /backend/config/params.php: -------------------------------------------------------------------------------- 1 | 'Nevermore后台管理系统', 4 | ]; 5 | -------------------------------------------------------------------------------- /backend/controllers/BackendController.php: -------------------------------------------------------------------------------- 1 | [ 36 | 'class' => AccessControl::className(), 37 | 'rules' => [ 38 | [ 39 | 'allow' => true, 40 | 'roles' => ['@'], 41 | ], 42 | [ 43 | 'actions' => ['error'], 44 | 'allow' => true, 45 | ], 46 | [ 47 | 'actions' => ['login'], 48 | 'allow' => true, 49 | 'roles' => ['?'], 50 | ], 51 | ], 52 | 'denyCallback' => function ($rules, $action) { 53 | Yii::$app->user->returnUrl = Yii::$app->request->url; 54 | return $this->redirect(['user/login']); 55 | }, 56 | ], 57 | ]; 58 | } 59 | 60 | /** 61 | * 初始化 62 | */ 63 | public function init() 64 | { 65 | Yii::$container->set('yii\widgets\LinkPager', [ 66 | 'firstPageLabel' => '首页', 67 | 'lastPageLabel' => '尾页', 68 | 'prevPageLabel' => '上页', 69 | 'nextPageLabel' => '下页', 70 | 'hideOnSinglePage' => false, 71 | 'options' => [ 72 | 'class' => 'pagination pull-right' 73 | ], 74 | ]); 75 | Yii::$container->set('yii\data\Pagination', [ 76 | 'defaultPageSize' => 15 77 | ]); 78 | Yii::$container->set('yii\grid\ActionColumn', [ 79 | 'template' => '{update} {delete}', 80 | ]); 81 | Yii::$container->set(ActiveForm::className(), [ 82 | 'type' => ActiveForm::TYPE_HORIZONTAL, 83 | ]); 84 | Yii::$container->set('yii\captcha\Captcha', [ 85 | 'captchaAction' => 'home/captcha' 86 | ]); 87 | Yii::$container->set('yii\captcha\CaptchaValidator', [ 88 | 'captchaAction' => 'home/captcha' 89 | ]); 90 | Yii::$container->set('backend\behaviors\TestBehavior', [ 91 | 'msg' => 'xxxxxxx', 92 | ]); 93 | } 94 | 95 | /** 96 | * 强制刷新菜单 97 | * @return \yii\web\Response 98 | */ 99 | public function actionReflushmenu() 100 | { 101 | Yii::$app->session->setFlash('reflush'); 102 | return $this->goHome(); 103 | } 104 | 105 | public function beforeAction($action) 106 | { 107 | parent::beforeAction($action); 108 | //访问非菜单里的action时,菜单保持打开(添加角色时角色管理保持打开状态) 109 | $refferroute = Yii::$app->request->referrer; 110 | $_referrer = parse_url($refferroute); 111 | Yii::$app->session->set('referrerroute', $_referrer['path']); 112 | $route = Yii::$app->requestedRoute; 113 | //未加入权限控制的所有路由允许访问 114 | if (!Yii::$app->authManager->getPermission($route)) { 115 | return true; 116 | } 117 | 118 | if (Yii::$app->user->id != 1 && !Yii::$app->user->can($route)) { 119 | throw new MethodNotAllowedHttpException('未被授权!'); 120 | } 121 | 122 | return true; 123 | } 124 | 125 | public function afterAction($action, $result) 126 | { 127 | parent::afterAction($action, $result); 128 | return $result; 129 | } 130 | } -------------------------------------------------------------------------------- /backend/controllers/HomeController.php: -------------------------------------------------------------------------------- 1 | [ 38 | 'class' => AccessControl::className(), 39 | 'rules' => [ 40 | [ 41 | 'allow' => true, 42 | 'roles' => ['@'], 43 | ], 44 | [ 45 | 'actions' => ['error'], 46 | 'allow' => true, 47 | ], 48 | ], 49 | 'denyCallback' => function ($rules, $action) { 50 | Yii::$app->user->returnUrl = Yii::$app->request->url; 51 | return $this->redirect(['user/login']); 52 | }, 53 | ], 54 | ]; 55 | } 56 | 57 | /** 58 | * @inheritdoc 59 | */ 60 | public function actions() 61 | { 62 | return [ 63 | 'error' => [ 64 | 'class' => 'yii\web\ErrorAction', 65 | ], 66 | 'captcha' => [ 67 | 'class' => 'yii\captcha\CaptchaAction' 68 | ], 69 | ]; 70 | } 71 | 72 | public function actionIndex() 73 | { 74 | //缓存一个带有依赖的缓存 75 | $key = '_menu' . Yii::$app->user->id; 76 | if (Yii::$app->session->getFlash('reflush') || !Yii::$app->cache->get($key)) { 77 | //如果缓存依赖发生改变,重新生成缓存 78 | $dp = new ExpressionDependency([ 79 | 'expression' => 'count(Yii::$app->authManager->getPermissionsByUser(Yii::$app->user->id))' 80 | ]); 81 | $dp2 = new DbDependency([ 82 | 'sql' => 'select max(updated_at) from auth_item', 83 | ]); 84 | Yii::$app->cache->set($key, 'nothing', 0, new ChainedDependency([ 85 | 'dependencies' => [$dp, $dp2] 86 | ])); 87 | //利用上面的缓存依赖生成菜单的永久缓存 88 | $_list = TMenu::generateMenuByUser(); 89 | Yii::$app->cache->set('menulist-' . Yii::$app->user->id, $_list, 0); 90 | } 91 | return $this->render('index'); 92 | } 93 | } -------------------------------------------------------------------------------- /backend/controllers/RestfulController.php: -------------------------------------------------------------------------------- 1 | where('level=1')->all(); 25 | return $this->render('index', [ 26 | 'list' => $list, 27 | ]); 28 | } 29 | 30 | /** 31 | * 添加新菜单 32 | * @return string|Response 33 | */ 34 | public function actionCreate() 35 | { 36 | $request = Yii::$app->request; 37 | $model = new TMenu; 38 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 39 | Yii::$app->session->setFlash('success'); 40 | return $this->redirect(['sys/menu']); 41 | } else { 42 | $model->loadDefaultValues(); 43 | $model->parentid = $request->get('pid', 0); 44 | $model->level = $request->get('level', 0) + 1; 45 | return $this->render('create', [ 46 | 'model' => $model, 47 | 'plevel' => $request->get('level', 0) 48 | ]); 49 | } 50 | } 51 | 52 | /** 53 | * 更新菜单 54 | * @param $id 55 | * @return string|Response 56 | */ 57 | public function actionUpdate($id) 58 | { 59 | $model = TMenu::findOne($id); 60 | if ($model->load(Yii::$app->request->post()) && $model->save()) { 61 | Yii::$app->session->setFlash('success'); 62 | return $this->redirect(['sys/menu']); 63 | } else { 64 | return $this->render('update', [ 65 | 'model' => $model, 66 | ]); 67 | } 68 | } 69 | 70 | /** 71 | * 删除菜单 72 | * @return Response 73 | * @throws \Exception 74 | */ 75 | public function actionMenudel() 76 | { 77 | $id = Yii::$app->request->get('id'); 78 | $level = Yii::$app->request->get('level'); 79 | //循环删除是为了在afterDelete删除对应的permission 80 | //一级菜单先删除孙子节点 81 | if ($level == 1) { 82 | $son = TMenu::find()->where(['parentid' => $id, 'level' => 2])->all(); 83 | foreach ($son as $s) { 84 | $gsons = TMenu::find()->where(['parentid' => $s->id])->all(); 85 | foreach ($gsons as $g) { 86 | $g->delete(); 87 | } 88 | } 89 | } 90 | //一二级菜单删除儿子节点 91 | if ($level <= 2) { 92 | $son = TMenu::find()->where(['parentid' => $id])->all(); 93 | foreach ($son as $s) { 94 | $s->delete(); 95 | } 96 | } 97 | //删除自身 98 | TMenu::findOne($id)->delete(); 99 | Yii::$app->session->setFlash('success'); 100 | return $this->redirect(['sys/menu']); 101 | } 102 | 103 | /** 104 | * Ajax 验证菜单名称 105 | * @return array 106 | */ 107 | public function actionAjaxvalidate() 108 | { 109 | if ($id = Yii::$app->request->post('id')) { 110 | $model = TMenu::findOne($id); 111 | } else { 112 | $model = new TMenu(); 113 | } 114 | if (Yii::$app->request->isAjax) { 115 | $model->load(Yii::$app->request->post()); 116 | Yii::$app->response->format = Response::FORMAT_JSON; 117 | return ActiveForm::validate($model, 'menuname'); 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /backend/controllers/TestController.php: -------------------------------------------------------------------------------- 1 | TestBehavior::className(), 24 | // 'msg'=>'APEC开的真操蛋!' 25 | ] 26 | ]; 27 | } 28 | 29 | /** 30 | * 事件 31 | * @return string 32 | */ 33 | public function actionEvent() 34 | { 35 | $this->on(Controller::EVENT_AFTER_ACTION, [$this, 'hello']); 36 | $this->on(Controller::EVENT_AFTER_ACTION, function () { 37 | echo "我是来自匿名函数的事件
"; 38 | }); 39 | self::say(); 40 | return '---------'; 41 | } 42 | 43 | public function actionTest() 44 | { 45 | self::say(); 46 | return '++++++'; 47 | } 48 | 49 | /** 50 | * 事件处理器 51 | */ 52 | public function Hello() 53 | { 54 | echo 'hello World!
'; 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /backend/models/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /backend/models/AuthAssignment.php: -------------------------------------------------------------------------------- 1 | 64] 35 | ]; 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | public function attributeLabels() 42 | { 43 | return [ 44 | 'item_name' => 'Item Name', 45 | 'user_id' => 'User ID', 46 | 'created_at' => 'Created At', 47 | ]; 48 | } 49 | 50 | /** 51 | * @return \yii\db\ActiveQuery 52 | */ 53 | public function getItemName() 54 | { 55 | return $this->hasOne(AuthItem::className(), ['name' => 'item_name']); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /backend/models/AuthItem.php: -------------------------------------------------------------------------------- 1 | 64] 43 | ]; 44 | } 45 | 46 | /** 47 | * @inheritdoc 48 | */ 49 | public function attributeLabels() 50 | { 51 | return [ 52 | 'name' => '名称', 53 | 'type' => '类型', 54 | 'description' => '描述', 55 | 'rule_name' => '规则名称', 56 | 'data' => '数据', 57 | 'created_at' => '创建时间', 58 | 'updated_at' => '修改时间', 59 | ]; 60 | } 61 | 62 | /** 63 | * @return \yii\db\ActiveQuery 64 | */ 65 | public function getAuthAssignments() 66 | { 67 | return $this->hasMany(AuthAssignment::className(), ['item_name' => 'name']); 68 | } 69 | 70 | /** 71 | * @return \yii\db\ActiveQuery 72 | */ 73 | public function getRuleName() 74 | { 75 | return $this->hasOne(AuthRule::className(), ['name' => 'rule_name']); 76 | } 77 | 78 | /** 79 | * @return \yii\db\ActiveQuery 80 | */ 81 | public function getAuthItemChildren() 82 | { 83 | return $this->hasMany(AuthItemChild::className(), ['child' => 'name']); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /backend/models/LoginForm.php: -------------------------------------------------------------------------------- 1 | hasErrors()) { 44 | $user = $this->getUser(); 45 | if (!$user || !$user->validatePassword($this->password)) { 46 | $this->addError($attribute, '用户名或密码错误'); 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 = TAdmUser::findByUsername($this->username); 74 | } 75 | return $this->_user; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /backend/models/TAdmUser.php: -------------------------------------------------------------------------------- 1 | ['create','chgpwd']], 37 | ['verifyCode','captcha','on'=>['create','chgpwd']], 38 | [['username', 'password', 'userphoto'], 'string', 'max' => 255], 39 | ['password_repeat','compare','compareAttribute'=>'password'] 40 | ]; 41 | } 42 | 43 | /** 44 | * @inheritdoc 45 | */ 46 | public function attributeLabels() 47 | { 48 | return [ 49 | 'id' => 'ID', 50 | 'username' => '用户名', 51 | 'password' => '密码', 52 | 'password_repeat'=>'重复密码', 53 | 'verifyCode'=>'验证码', 54 | 'userphoto'=>'用户头像', 55 | ]; 56 | } 57 | public function beforeSave($insert) 58 | { 59 | if($this->isNewRecord || $this->password!=$this->oldAttributes['password']) 60 | $this->password = Yii::$app->security->generatePasswordHash($this->password); 61 | return true; 62 | } 63 | 64 | /** 65 | * 关联获取角色 66 | * @return \yii\db\ActiveQuery 67 | */ 68 | public function getRoles() 69 | { 70 | return $this->hasMany(AuthAssignment::className(),['user_id'=>'id']); 71 | } 72 | 73 | public static function findByusername($username) 74 | { 75 | return static::find()->where('username=:u',[':u'=>$username])->one(); 76 | } 77 | 78 | public function validatePassword($password) 79 | { 80 | return Yii::$app->security->validatePassword($password,$this->password); 81 | } 82 | public static function findIdentity($id) 83 | { 84 | return static::findOne($id); 85 | } 86 | public static function findIdentityByAccessToken($token, $type = null) 87 | { 88 | return null; 89 | } 90 | public function getId() 91 | { 92 | return $this->id; 93 | } 94 | public function getAuthKey() 95 | { 96 | return md5($this->id); 97 | } 98 | public function validateAuthKey($authKey) 99 | { 100 | return $authKey===$this->getAuthKey(); 101 | } 102 | } -------------------------------------------------------------------------------- /backend/models/TMenu.php: -------------------------------------------------------------------------------- 1 | 32], 38 | [['menuicon'], 'string', 'max' => 16] 39 | ]; 40 | } 41 | 42 | /** 43 | * @inheritdoc 44 | */ 45 | public function attributeLabels() 46 | { 47 | return [ 48 | 'id' => 'ID', 49 | 'menuname' => '菜单名称', 50 | 'parentid' => '父类ID', 51 | 'route' => '路由', 52 | 'menuicon' => '图标', 53 | 'level' => '级别', 54 | ]; 55 | } 56 | 57 | public function afterSave($insert, $changedAttributes) 58 | { 59 | parent::afterSave($insert, $changedAttributes); 60 | $auth = Yii::$app->authManager; 61 | if($insert) 62 | { 63 | $permission = $auth->createPermission($this->route); 64 | $permission->description = $this->menuname; 65 | $auth->add($permission); 66 | }else 67 | { 68 | $route = ArrayHelper::getValue($changedAttributes,'route',$this->route); 69 | $permission = $auth->getPermission($route); 70 | $permission->name = $this->route; 71 | $permission->description = $this->menuname; 72 | $auth->update($route,$permission); 73 | } 74 | 75 | } 76 | 77 | public function afterDelete() 78 | { 79 | parent::afterDelete(); 80 | //删除所有权限 81 | $auth = Yii::$app->authManager; 82 | if($p = $auth->getPermission($this->route)) 83 | $auth->remove($p); 84 | } 85 | /** 86 | * 获取子菜单 87 | * @return static 88 | */ 89 | public function getSon() 90 | { 91 | return $this->hasMany(TMenu::className(),['parentid'=>'id'])->orderBy('level desc'); 92 | } 93 | /** 94 | * 获取父菜单 95 | */ 96 | public function getFather() 97 | { 98 | return $this->hasOne(TMenu::className(),['id'=>'parentid']); 99 | } 100 | 101 | /** 102 | * 生成菜单 103 | * @return string 104 | */ 105 | public static function generateMenuByUser() 106 | { 107 | $list = TMenu::find()->where('level=1')->all(); 108 | $menu = Yii::$app->controller->renderPartial('@backend/views/home/_menu',[ 109 | 'list'=>$list, 110 | 'admin'=>(Yii::$app->user->id==1)?true:false 111 | ]); 112 | return $menu; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /backend/models/forsearch/TAdmUserSearch.php: -------------------------------------------------------------------------------- 1 | $query, 46 | ]); 47 | 48 | if (!($this->load($params) && $this->validate())) { 49 | return $dataProvider; 50 | } 51 | 52 | $query->andFilterWhere([ 53 | 'id' => $this->id, 54 | ]); 55 | 56 | $query->andFilterWhere(['like', 'username', $this->username]) 57 | ->andFilterWhere(['like', 'password', $this->password]) 58 | ->andFilterWhere(['like', 'userphoto', $this->userphoto]); 59 | 60 | return $dataProvider; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /backend/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /backend/views/home/_menu.php: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /backend/views/home/error.php: -------------------------------------------------------------------------------- 1 | title = $name; 11 | $this->params['breadcrumbs'] = [ 12 | $name, 13 | ]; 14 | ?> 15 |
16 | 17 |

title) ?>

18 | 19 |
20 | 21 |
22 |

23 | 服务器在处理您的请求时发生以上错误! 24 |

25 |

26 | 如果你认为这是一个服务器错误,请联系我们。谢谢. 27 |

28 | 29 |
30 | -------------------------------------------------------------------------------- /backend/views/home/index.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 22 | '欢迎页' 23 | ]; 24 | ?> 25 | 'icon-comment-alt', 27 | 'body'=>'欢迎使用'.' '.Yii::$app->params['webname'].'', 28 | ]) ?> -------------------------------------------------------------------------------- /backend/views/layouts/main-login.php: -------------------------------------------------------------------------------- 1 | 23 | beginPage() ?> 24 | 25 | 26 | 27 | 28 | 登录页面 - Bootstrap后台管理系统模版Ace下载 29 | head() ?> 30 | 31 | 32 | beginBody() ?> 33 | 34 | endBody() ?> 35 | 36 | 37 | endPage() ?> -------------------------------------------------------------------------------- /backend/views/rbac/_form.php: -------------------------------------------------------------------------------- 1 | 27 | 28 |
29 | Url::toRoute(['rbac/validateitemname']), 31 | ]) ?> 32 | 33 | field($model, 'name', ['enableAjaxValidation' => true])->textInput() ?> 34 | field($model, 'description')->textarea() ?> 35 | name) ?> 36 | 37 |
38 | 'btn btn-lg btn-primary']) ?> 39 |
40 | 41 | end() ?> 42 | 43 |
-------------------------------------------------------------------------------- /backend/views/rbac/assignrole.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 25 | [ 26 | 'label' => '用户管理', 27 | 'url' => '/user/index' 28 | ], 29 | '角色授予' 30 | ]; 31 | ?> 32 |
33 | $model, 35 | 'attributes' => [ 36 | 'username', 37 | ], 38 | ]) ?> 39 |
40 | 41 |
42 |
43 | 备选角色: 44 | 'avaliable', 47 | 'multiple' => true, 48 | 'size' => 20, 49 | 'style' => 'width:100%']); 50 | ?> 51 |
52 |
53 |  

54 | >', '#', ['class' => 'btn btn-success', 'data-action' => 'assign','data-dd'=>'xxxx']) . '
'; 56 | echo Html::a('<<', '#', ['class' => 'btn btn-success', 'data-action' => 'delete']) . '
'; 57 | ?> 58 |
59 |
60 | 已有角色: 61 | 'assigned', 64 | 'multiple' => true, 65 | 'size' => 20, 66 | 'style' => 'width:100%']); 67 | ?> 68 |
69 |
70 | 101 | registerJs($this->blocks['JS_END'],\yii\web\View::POS_END); 104 | $this->registerJs($this->blocks['JS_READY']); 105 | ?> 106 | -------------------------------------------------------------------------------- /backend/views/rbac/create.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 26 | [ 27 | 'label' => '角色管理', 28 | 'url' => Url::toRoute(['rbac/roles']) 29 | ], 30 | '添加角色', 31 | ]; 32 | ?> 33 | render('_form', ['model' => $model]) ?> -------------------------------------------------------------------------------- /backend/views/rbac/roles.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 26 | '角色管理', 27 | ]; 28 | ?> 29 |

30 | 'btn btn-sm btn btn-success']) ?> 31 |

32 | 33 | $dataprovider, 35 | 'columns' => [ 36 | [ 37 | 'class' => 'yii\grid\SerialColumn', 38 | 'header' => '编号' 39 | ], 40 | 'name:text:名称', 41 | 'description:text:描述', 42 | 'ruleName:text:规则名称', 43 | 'createdAt:datetime:创建时间', 44 | [ 45 | 'class' => 'yii\grid\ActionColumn', 46 | 'header' => '操作', 47 | 'template' => '{view} {update} {delete}', 48 | 'buttons' => [ 49 | 'view' => function ($url, $model, $key) { 50 | return MyHelper::actionbutton(['rbac/assignauth', 'rolename' => $key], 'view', ['title' => '分配权限']); 51 | }, 52 | 'update' => function ($url, $model, $key) { 53 | return MyHelper::actionbutton('update?id=' . $key, 'update'); 54 | }, 55 | 'delete' => function ($url, $model, $key) { 56 | return MyHelper::actionbutton('/rbac/deleterole?id=' . $key, 'delete'); 57 | } 58 | ] 59 | ] 60 | ], 61 | ]) ?> -------------------------------------------------------------------------------- /backend/views/rbac/update.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 26 | [ 27 | 'label' => '角色管理', 28 | 'url' => Url::toRoute(['rbac/roles']) 29 | ], 30 | '更新角色', 31 | ]; 32 | ?> 33 | 34 | render('_form', ['model' => $model]) ?> -------------------------------------------------------------------------------- /backend/views/sys/_form.php: -------------------------------------------------------------------------------- 1 | 24 | 25 |
26 | '/sys/create', 28 | 'validationUrl' => '/sys/ajaxvalidate', 29 | ]) ?> 30 | 31 | field($model, 'menuname')->textInput() ?> 32 | field($model, 'route', ['enableAjaxValidation' => true])->textInput()->hint('三级菜单必须要按照\'controller/action\'格式书写') ?> 33 | field($model, 'menuicon')->textInput()->hint('参照Bootstrap图标') ?> 34 | field($model, 'level')->dropDownList([ 35 | '1' => '一级菜单', 36 | '2' => '二级菜单', 37 | '3' => '三级菜单', 38 | ], [ 39 | 'options' => [ 40 | '1' => ['disabled' => ($plevel == 0) ? false : true], 41 | '2' => ['disabled' => ($plevel == 1) ? false : true], 42 | '3' => ['disabled' => ($plevel == 1 || $plevel == 2) ? false : true] 43 | ] 44 | ]) ?> 45 | 46 | id) ?> 47 |
48 | isNewRecord ? '添加' : '更新', ['class' => 'btn btn-lg btn-primary']) ?> 49 |
50 | end() ?> 51 |
-------------------------------------------------------------------------------- /backend/views/sys/create.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 24 | [ 25 | 'label' => '路由管理', 26 | 'url' => \yii\helpers\Url::toRoute(['sys/menu']) 27 | ], 28 | '添加路由' 29 | ]; 30 | ?> 31 | 32 | render('_form', ['model' => $model, 'plevel' => $plevel]) ?> -------------------------------------------------------------------------------- /backend/views/sys/index.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 15 | '菜单管理' 16 | ]; 17 | ?> 18 | 19 |
20 |
    21 |
  • 22 | params['webname'] ?> 23 | 24 |
  • 25 |
  • 26 |
      27 | 28 | 29 | 30 |
    • 31 | menuname ?> 32 | 33 | 34 | 35 | 36 |
        37 | 38 | getSon()->all() as $son): ?> 39 | 40 | level == 3): ?> 41 |
      • 42 | menuname ?> 43 | 44 | 45 |
      • 46 | 47 |
      • 48 | menuname ?> 50 | 51 | 53 | 54 | 55 |
          56 | 57 | getSon()->all() as $gson): ?> 58 |
        • 59 | menuname ?> 61 | 62 | 63 |
        • 64 | 65 |
        66 |
      • 67 | 68 | 69 |
      70 |
    • 71 | 72 |
    73 | 74 |
  • 75 |
76 |
77 | 95 | registerJs($this->blocks['aa']) ?> -------------------------------------------------------------------------------- /backend/views/sys/update.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 25 | [ 26 | 'label' => '路由管理', 27 | 'url' => \yii\helpers\Url::toRoute(['sys/menu']) 28 | ], 29 | '添加路由' 30 | ]; 31 | ?> 32 | 33 | render('_form', ['model' => $model, 'plevel' => '']) ?> -------------------------------------------------------------------------------- /backend/views/user/changepwd.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 23 | '修改密码' 24 | ]; 25 | ?> 26 |
27 | 28 | field($model,'password')->passwordInput(['value'=>'']) ?> 29 | field($model,'password_repeat')->passwordInput() ?> 30 |
31 | 'btn btn-lg btn-primary']) ?> 32 |
33 | end() ?> 34 |
-------------------------------------------------------------------------------- /backend/views/user/index.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 27 | '用户管理', 28 | ]; 29 | ?> 30 | 31 | 'md', 34 | 'header' => '

添加用户

', 35 | 'footer' => '', 36 | 'clientOptions'=>[ 37 | 'remote'=>'http://admin/user/loadhtml' 38 | ] 39 | ]); 40 | Modal::end(); 41 | ?> 42 | 43 |

44 | 'btn btn-sm btn-success', 46 | 'onclick' => '$("#md").modal();' 47 | // 'onclick'=>'loadhtml(1)' 48 | ]) ?> 49 |

50 | $dataprovider, 52 | 'filterModel' => $searchmodel, 53 | 'columns' => [ 54 | 'id', 55 | [ 56 | 'attribute'=>'username', 57 | 'filter'=>['admin'=>'系统管理员','demo'=>'屌丝管理员','hello'=>'嘻哈管理员'], 58 | ], 59 | 'password', 60 | [ 61 | 'header' => '角色', 62 | 'content' => function ($model) { 63 | $roles = Yii::$app->authManager->getRolesByUser($model->id); 64 | $roles = implode(',', array_keys($roles)); 65 | return $roles; 66 | } 67 | ], 68 | [ 69 | 'header' => '操作', 70 | 'class' => 'yii\grid\ActionColumn', 71 | 'template' => '{view} {update} {delete}', 72 | 'buttons' => [ 73 | 'view' => function ($url, $model, $key) { 74 | return $key == 1 ? null : MyHelper::actionbutton('/rbac/assignrole?id=' . $key, 'view', ['title' => '查看/添加角色']); 75 | }, 76 | 'delete' => function ($url, $model, $key) { 77 | return $key == 1 ? null : MyHelper::actionbutton($url, 'delete'); 78 | } 79 | ] 80 | ], 81 | ], 82 | ]) ?> 83 | 96 | registerJs($this->blocks['js_end'],\yii\web\View::POS_END) ?> -------------------------------------------------------------------------------- /backend/views/user/loadhtml.php: -------------------------------------------------------------------------------- 1 | 23 | 'userform' 25 | ]) ?> 26 | field($model,'username')->textInput() ?> 27 | field($model,'password')->passwordInput() ?> 28 | field($model,'password_repeat')->passwordInput() ?> 29 | end() ?> -------------------------------------------------------------------------------- /backend/views/user/setphoto.php: -------------------------------------------------------------------------------- 1 | params['breadcrumbs'] = [ 24 | '设置头像' 25 | ]; 26 | ?> 27 |
28 | 'multipart/form-data']) ?> 29 | 'photo', 31 | 'showMessage'=>false, 32 | 'pluginOptions'=>[ 33 | 'showUpload'=>false, 34 | 'showRemove'=>false, 35 | 'browseLabel'=>'浏览...', 36 | 'initialPreview'=>[ 37 | Html::img('/upload/user/'.$preview,['class'=>'file-preview-image']) 38 | ], 39 | ], 40 | ]) ?> 41 |
42 | 'btn btn-lg btn-primary']) ?> 43 |
44 | 45 |
-------------------------------------------------------------------------------- /backend/web/.gitignore: -------------------------------------------------------------------------------- 1 | /index.php 2 | /index-test.php 3 | /upload 4 | -------------------------------------------------------------------------------- /backend/web/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Options +FollowSymLinks 3 | IndexIgnore */* 4 | RewriteEngine on 5 | 6 | # if a directory or a file exists, use it directly 7 | RewriteCond %{REQUEST_FILENAME} !-f 8 | RewriteCond %{REQUEST_FILENAME} !-d 9 | 10 | # otherwise forward it to index.php 11 | RewriteRule . index.php 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /backend/web/assets/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/web/css/treeview.css: -------------------------------------------------------------------------------- 1 | .tree { 2 | min-height:20px; 3 | padding:19px; 4 | margin-bottom:20px; 5 | background-color:#fbfbfb; 6 | border:1px solid #999; 7 | -webkit-border-radius:4px; 8 | -moz-border-radius:4px; 9 | border-radius:4px; 10 | -webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05); 11 | -moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05); 12 | box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05) 13 | } 14 | .tree li { 15 | list-style-type:none; 16 | margin:0; 17 | padding:10px 5px 0 5px; 18 | position:relative 19 | } 20 | .tree li::before, .tree li::after { 21 | content:''; 22 | left:-20px; 23 | position:absolute; 24 | right:auto 25 | } 26 | .tree li::before { 27 | border-left:1px solid #999; 28 | bottom:50px; 29 | height:100%; 30 | top:0; 31 | width:1px 32 | } 33 | .tree li::after { 34 | border-top:1px solid #999; 35 | height:20px; 36 | top:25px; 37 | width:25px 38 | } 39 | .tree li span { 40 | -moz-border-radius:5px; 41 | -webkit-border-radius:5px; 42 | border:1px solid #999; 43 | border-radius:5px; 44 | display:inline-block; 45 | padding:3px 8px; 46 | text-decoration:none 47 | } 48 | .tree li.parent_li>span { 49 | cursor:pointer 50 | } 51 | .tree>ul>li::before, .tree>ul>li::after { 52 | border:0 53 | } 54 | .tree li:last-child::before { 55 | height:30px 56 | } 57 | .tree li.parent_li>span:hover, .tree li.parent_li>span:hover+ul li span { 58 | background:#eee; 59 | border:1px solid #94a0b4; 60 | color:#000 61 | } -------------------------------------------------------------------------------- /backend/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/backend/web/favicon.ico -------------------------------------------------------------------------------- /backend/web/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/backend/web/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /backend/web/images/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/backend/web/images/user.jpg -------------------------------------------------------------------------------- /backend/web/js/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.4.1 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2013 Klaus Hartl 6 | * Released under the MIT license 7 | */ 8 | (function (factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | // AMD 11 | define(['../../js/jquery'], factory); 12 | } else if (typeof exports === 'object') { 13 | // CommonJS 14 | factory(require('jquery')); 15 | } else { 16 | // Browser globals 17 | factory(jQuery); 18 | } 19 | }(function ($) { 20 | 21 | var pluses = /\+/g; 22 | 23 | function encode(s) { 24 | return config.raw ? s : encodeURIComponent(s); 25 | } 26 | 27 | function decode(s) { 28 | return config.raw ? s : decodeURIComponent(s); 29 | } 30 | 31 | function stringifyCookieValue(value) { 32 | return encode(config.json ? JSON.stringify(value) : String(value)); 33 | } 34 | 35 | function parseCookieValue(s) { 36 | if (s.indexOf('"') === 0) { 37 | // This is a quoted cookie as according to RFC2068, unescape... 38 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 39 | } 40 | 41 | try { 42 | // Replace server-side written pluses with spaces. 43 | // If we can't decode the cookie, ignore it, it's unusable. 44 | // If we can't parse the cookie, ignore it, it's unusable. 45 | s = decodeURIComponent(s.replace(pluses, ' ')); 46 | return config.json ? JSON.parse(s) : s; 47 | } catch(e) {} 48 | } 49 | 50 | function read(s, converter) { 51 | var value = config.raw ? s : parseCookieValue(s); 52 | return $.isFunction(converter) ? converter(value) : value; 53 | } 54 | 55 | var config = $.cookie = function (key, value, options) { 56 | 57 | // Write 58 | 59 | if (value !== undefined && !$.isFunction(value)) { 60 | options = $.extend({}, config.defaults, options); 61 | 62 | if (typeof options.expires === 'number') { 63 | var days = options.expires, t = options.expires = new Date(); 64 | t.setTime(+t + days * 864e+5); 65 | } 66 | 67 | return (document.cookie = [ 68 | encode(key), '=', stringifyCookieValue(value), 69 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 70 | options.path ? '; path=' + options.path : '', 71 | options.domain ? '; domain=' + options.domain : '', 72 | options.secure ? '; secure' : '' 73 | ].join('')); 74 | } 75 | 76 | // Read 77 | 78 | var result = key ? undefined : {}; 79 | 80 | // To prevent the for loop in the first place assign an empty array 81 | // in case there are no cookies at all. Also prevents odd result when 82 | // calling $.cookie(). 83 | var cookies = document.cookie ? document.cookie.split('; ') : []; 84 | 85 | for (var i = 0, l = cookies.length; i < l; i++) { 86 | var parts = cookies[i].split('='); 87 | var name = decode(parts.shift()); 88 | var cookie = parts.join('='); 89 | 90 | if (key && key === name) { 91 | // If second argument (value) is a function it's a converter... 92 | result = read(cookie, value); 93 | break; 94 | } 95 | 96 | // Prevent storing a cookie that we couldn't decode. 97 | if (!key && (cookie = read(cookie)) !== undefined) { 98 | result[name] = cookie; 99 | } 100 | } 101 | 102 | return result; 103 | }; 104 | 105 | config.defaults = {}; 106 | 107 | $.removeCookie = function (key, options) { 108 | if ($.cookie(key) === undefined) { 109 | return false; 110 | } 111 | 112 | // Must not alter options, thus extending a fresh object... 113 | $.cookie(key, '', $.extend({}, options, { expires: -1 })); 114 | return !$.cookie(key); 115 | }; 116 | 117 | })); 118 | -------------------------------------------------------------------------------- /backend/web/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /backend/web/upload/user/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/backend/web/upload/user/default.jpg -------------------------------------------------------------------------------- /common/config/.gitignore: -------------------------------------------------------------------------------- 1 | main-local.php 2 | params-local.php 3 | -------------------------------------------------------------------------------- /common/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'class' => 'yii\db\Connection', 25 | 'dsn' => 'mysql:host=localhost;dbname=nevermore', 26 | 'username' => 'root', 27 | 'password' => '', 28 | 'charset' => 'utf8', 29 | ], 30 | ]; 31 | ?> 32 | 33 | -------------------------------------------------------------------------------- /common/config/main.php: -------------------------------------------------------------------------------- 1 | dirname(dirname(__DIR__)) . '/vendor', 5 | 'components' => [ 6 | 'cache' => [ 7 | 'class' => 'yii\caching\FileCache', 8 | ], 9 | 'mailer' => [ 10 | 'class' => 'yii\swiftmailer\Mailer', 11 | 'viewPath' => '@common/mail', 12 | // send all mails to a file by default. You have to set 13 | // 'useFileTransport' to false and configure a transport 14 | // for the mailer to send real emails. 15 | 'useFileTransport' => true, 16 | ], 17 | 'db'=>$db['db'], 18 | ], 19 | ]; 20 | -------------------------------------------------------------------------------- /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/passwordResetToken.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 | -------------------------------------------------------------------------------- /common/models/LoginForm.php: -------------------------------------------------------------------------------- 1 | hasErrors()) { 43 | $user = $this->getUser(); 44 | if (!$user || !$user->validatePassword($this->password)) { 45 | $this->addError($attribute, 'Incorrect username or password.'); 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * Logs in a user using the provided username and password. 52 | * 53 | * @return boolean whether the user is logged in successfully 54 | */ 55 | public function login() 56 | { 57 | if ($this->validate()) { 58 | return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0); 59 | } else { 60 | return false; 61 | } 62 | } 63 | 64 | /** 65 | * Finds user by [[username]] 66 | * 67 | * @return User|null 68 | */ 69 | public function getUser() 70 | { 71 | if ($this->_user === false) { 72 | $this->_user = User::findByUsername($this->username); 73 | } 74 | 75 | return $this->_user; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /common/models/User.php: -------------------------------------------------------------------------------- 1 | self::STATUS_ACTIVE], 56 | ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], 57 | 58 | ['role', 'default', 'value' => self::ROLE_USER], 59 | ['role', 'in', 'range' => [self::ROLE_USER]], 60 | ]; 61 | } 62 | 63 | /** 64 | * @inheritdoc 65 | */ 66 | public static function findIdentity($id) 67 | { 68 | return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); 69 | } 70 | 71 | /** 72 | * @inheritdoc 73 | */ 74 | public static function findIdentityByAccessToken($token, $type = null) 75 | { 76 | throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); 77 | } 78 | 79 | /** 80 | * Finds user by username 81 | * 82 | * @param string $username 83 | * @return static|null 84 | */ 85 | public static function findByUsername($username) 86 | { 87 | return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]); 88 | } 89 | 90 | /** 91 | * Finds user by password reset token 92 | * 93 | * @param string $token password reset token 94 | * @return static|null 95 | */ 96 | public static function findByPasswordResetToken($token) 97 | { 98 | if (!static::isPasswordResetTokenValid($token)) { 99 | return null; 100 | } 101 | 102 | return static::findOne([ 103 | 'password_reset_token' => $token, 104 | 'status' => self::STATUS_ACTIVE, 105 | ]); 106 | } 107 | 108 | /** 109 | * Finds out if password reset token is valid 110 | * 111 | * @param string $token password reset token 112 | * @return boolean 113 | */ 114 | public static function isPasswordResetTokenValid($token) 115 | { 116 | if (empty($token)) { 117 | return false; 118 | } 119 | $expire = Yii::$app->params['user.passwordResetTokenExpire']; 120 | $parts = explode('_', $token); 121 | $timestamp = (int) end($parts); 122 | return $timestamp + $expire >= time(); 123 | } 124 | 125 | /** 126 | * @inheritdoc 127 | */ 128 | public function getId() 129 | { 130 | return $this->getPrimaryKey(); 131 | } 132 | 133 | /** 134 | * @inheritdoc 135 | */ 136 | public function getAuthKey() 137 | { 138 | return $this->auth_key; 139 | } 140 | 141 | /** 142 | * @inheritdoc 143 | */ 144 | public function validateAuthKey($authKey) 145 | { 146 | return $this->getAuthKey() === $authKey; 147 | } 148 | 149 | /** 150 | * Validates password 151 | * 152 | * @param string $password password to validate 153 | * @return boolean if password provided is valid for current user 154 | */ 155 | public function validatePassword($password) 156 | { 157 | return Yii::$app->security->validatePassword($password, $this->password_hash); 158 | } 159 | 160 | /** 161 | * Generates password hash from password and sets it to the model 162 | * 163 | * @param string $password 164 | */ 165 | public function setPassword($password) 166 | { 167 | $this->password_hash = Yii::$app->security->generatePasswordHash($password); 168 | } 169 | 170 | /** 171 | * Generates "remember me" authentication key 172 | */ 173 | public function generateAuthKey() 174 | { 175 | $this->auth_key = Yii::$app->security->generateRandomString(); 176 | } 177 | 178 | /** 179 | * Generates new password reset token 180 | */ 181 | public function generatePasswordResetToken() 182 | { 183 | $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); 184 | } 185 | 186 | /** 187 | * Removes password reset token 188 | */ 189 | public function removePasswordResetToken() 190 | { 191 | $this->password_reset_token = null; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /common/widgets/DateTimePicker.php: -------------------------------------------------------------------------------- 1 | 'ch',//中文 41 | 'timepicker'=>false,//不选择时间 42 | 'format'=>'Y-m-d',//格式 43 | 'closeOnDateSelect'=>true,//选择完日期关闭插件 44 | ]; 45 | /** 46 | * @inheritdoc 47 | */ 48 | public function init() 49 | { 50 | parent::init(); 51 | if ($this->inline && !isset($this->containerOptions['id'])) { 52 | $this->containerOptions['id'] = $this->options['id'] . '-container'; 53 | } 54 | } 55 | 56 | /** 57 | * Renders the widget. 58 | */ 59 | public function run() 60 | { 61 | echo $this->renderWidget() . "\n"; 62 | $containerID = $this->inline ? $this->containerOptions['id'] : $this->options['id']; 63 | 64 | $view = $this->getView(); 65 | $options = Json::encode(array_merge($this->_defaultsetting,$this->clientOptions)); 66 | $view->registerJs("jQuery('#{$containerID}').datetimepicker($options);"); 67 | $this->clientOptions = false; // the datepicker js widget is already registered 68 | $this->registerWidget('datetimepicker', $containerID); 69 | DateTimePickerAsset::register($this->getView()); 70 | } 71 | 72 | /** 73 | * Renders the DatePicker widget. 74 | * @return string the rendering result. 75 | */ 76 | protected function renderWidget() 77 | { 78 | $contents = []; 79 | 80 | if ($this->inline === false) { 81 | if ($this->hasModel()) { 82 | $contents[] = Html::activeTextInput($this->model, $this->attribute, $this->options); 83 | } else { 84 | $contents[] = Html::textInput($this->name, $this->value, $this->options); 85 | } 86 | } else { 87 | if ($this->hasModel()) { 88 | $contents[] = Html::activeHiddenInput($this->model, $this->attribute, $this->options); 89 | $this->clientOptions['defaultDate'] = $this->model->{$this->attribute}; 90 | } else { 91 | $contents[] = Html::hiddenInput($this->name, $this->value, $this->options); 92 | $this->clientOptions['defaultDate'] = $this->value; 93 | } 94 | $this->clientOptions['altField'] = '#' . $this->options['id']; 95 | $contents[] = Html::tag('div', null, $this->containerOptions); 96 | } 97 | 98 | return implode("\n", $contents); 99 | } 100 | } -------------------------------------------------------------------------------- /common/widgets/DateTimePickerAsset.php: -------------------------------------------------------------------------------- 1 | =5.4.0", 23 | "yiisoft/yii2": "*", 24 | "yiisoft/yii2-bootstrap": "*", 25 | "yiisoft/yii2-swiftmailer": "*", 26 | "yiisoft/yii2-imagine": "*", 27 | "kartik-v/yii2-widgets": "*", 28 | "kucha/ueditor": "*" 29 | }, 30 | "require-dev": { 31 | "yiisoft/yii2-codeception": "*", 32 | "yiisoft/yii2-debug": "*", 33 | "yiisoft/yii2-gii": "*", 34 | "yiisoft/yii2-faker": "*" 35 | }, 36 | "config": { 37 | "process-timeout": 1800 38 | }, 39 | "extra": { 40 | "asset-installer-paths": { 41 | "npm-asset-library": "vendor/npm", 42 | "bower-asset-library": "vendor/bower" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /console/config/.gitignore: -------------------------------------------------------------------------------- 1 | main-local.php 2 | params-local.php -------------------------------------------------------------------------------- /console/config/bootstrap.php: -------------------------------------------------------------------------------- 1 | 'app-console', 12 | 'basePath' => dirname(__DIR__), 13 | 'bootstrap' => ['log', 'gii'], 14 | 'controllerNamespace' => 'console\controllers', 15 | 'modules' => [ 16 | 'gii' => 'yii\gii\Module', 17 | ], 18 | 'components' => [ 19 | 'log' => [ 20 | 'targets' => [ 21 | [ 22 | 'class' => 'yii\log\FileTarget', 23 | 'levels' => ['error', 'warning'], 24 | ], 25 | ], 26 | ], 27 | 'authManager'=>[ 28 | 'class'=>'yii\rbac\DbManager', 29 | ], 30 | ], 31 | 'params' => $params, 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /console/config/params.php: -------------------------------------------------------------------------------- 1 | 'admin@example.com', 4 | ]; 5 | -------------------------------------------------------------------------------- /console/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/console/controllers/.gitkeep -------------------------------------------------------------------------------- /console/migrations/m130524_201442_init.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 12 | // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci 13 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 14 | } 15 | 16 | /*$this->createTable('{{%user}}', [ 17 | 'id' => Schema::TYPE_PK, 18 | 'username' => Schema::TYPE_STRING . ' NOT NULL', 19 | 'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL', 20 | 'password_hash' => Schema::TYPE_STRING . ' NOT NULL', 21 | 'password_reset_token' => Schema::TYPE_STRING, 22 | 'email' => Schema::TYPE_STRING . ' NOT NULL', 23 | 'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', 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 | 31 | public function down() 32 | { 33 | $this->dropTable('{{%user}}'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /console/migrations/m141022_124022_create_menutable.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 12 | // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci 13 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 14 | } 15 | 16 | $this->createTable('{{%t_menu}}', [ 17 | 'id' => Schema::TYPE_PK, 18 | 'menuname' => Schema::TYPE_STRING . '(32) NOT NULL', 19 | 'parentid'=> Schema::TYPE_SMALLINT .' NOT NULL DEFAULT 0', 20 | 'route' => Schema::TYPE_STRING . '(32) NOT NULL', 21 | 'menuicon' => Schema::TYPE_STRING . '(16) NOT NULL DEFAULT "icon-book"', 22 | 23 | 'level' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 1', 24 | ], $tableOptions); 25 | $sql = "INSERT INTO `t_menu` (`id`, `menuname`, `parentid`, `route`, `menuicon`, `level`) VALUES 26 | (1, '设置', 0, 'conf', 'icon-cog', 1), 27 | (2, '菜单管理', 1, 'sys/menu', 'icon-book', 3), 28 | (3, '用户管理', 1, 'user/index', 'icon-book', 3), 29 | (4, '权限管理', 1, 'rbac', 'icon-book', 2), 30 | (5, '角色管理', 4, 'rbac/roles', 'icon-book', 3);"; 31 | $this->execute($sql); 32 | } 33 | 34 | public function down() 35 | { 36 | echo "m141022_124022_create_menutable cannot be reverted.\n"; 37 | 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /console/migrations/m141101_015745_createtable_admin_user.php: -------------------------------------------------------------------------------- 1 | db->driverName === 'mysql') { 12 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; 13 | } 14 | 15 | $this->createTable('{{%t_adm_user}}', [ 16 | 'id' => Schema::TYPE_PK, 17 | 'username' => Schema::TYPE_STRING . '(64) NOT NULL', 18 | 'password' => Schema::TYPE_STRING . '(64) NOT NULL', 19 | 'userphoto' => Schema::TYPE_STRING . '(64) NOT NULL', 20 | ], $tableOptions); 21 | $pw1 = Yii::$app->security->generatePasswordHash('admin'); 22 | $pw2 = Yii::$app->security->generatePasswordHash('demo'); 23 | $sql = "INSERT INTO `t_adm_user` (`id`, `username`, `password`) VALUES 24 | (1, 'admin', '$pw1'), 25 | (2, 'demo', '$pw2');"; 26 | $this->execute($sql); 27 | } 28 | 29 | public function down() 30 | { 31 | echo "m141101_015745_createtable_admin_user cannot be reverted.\n"; 32 | 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /console/models/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /console/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /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=yii2advanced', 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 | [ 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 directories 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/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 | -------------------------------------------------------------------------------- /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 | 'enableAutoLogin' => true, 18 | ], 19 | 'log' => [ 20 | 'traceLevel' => YII_DEBUG ? 3 : 0, 21 | 'targets' => [ 22 | [ 23 | 'class' => 'yii\log\FileTarget', 24 | 'levels' => ['error', 'warning'], 25 | ], 26 | ], 27 | ], 28 | 'errorHandler' => [ 29 | 'errorAction' => 'site/error', 30 | ], 31 | ], 32 | 'params' => $params, 33 | ]; 34 | -------------------------------------------------------------------------------- /frontend/config/params.php: -------------------------------------------------------------------------------- 1 | 'admin@example.com', 4 | ]; 5 | -------------------------------------------------------------------------------- /frontend/controllers/SiteController.php: -------------------------------------------------------------------------------- 1 | [ 28 | 'class' => AccessControl::className(), 29 | 'only' => ['logout', 'signup'], 30 | 'rules' => [ 31 | [ 32 | 'actions' => ['signup'], 33 | 'allow' => true, 34 | 'roles' => ['?'], 35 | ], 36 | [ 37 | 'actions' => ['logout'], 38 | 'allow' => true, 39 | 'roles' => ['@'], 40 | ], 41 | ], 42 | ], 43 | 'verbs' => [ 44 | 'class' => VerbFilter::className(), 45 | 'actions' => [ 46 | 'logout' => ['post'], 47 | ], 48 | ], 49 | ]; 50 | } 51 | 52 | /** 53 | * @inheritdoc 54 | */ 55 | public function actions() 56 | { 57 | return [ 58 | 'error' => [ 59 | 'class' => 'yii\web\ErrorAction', 60 | ], 61 | 'captcha' => [ 62 | 'class' => 'yii\captcha\CaptchaAction', 63 | 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, 64 | ], 65 | ]; 66 | } 67 | 68 | public function actionIndex() 69 | { 70 | return $this->render('index'); 71 | } 72 | 73 | public function actionLogin() 74 | { 75 | if (!\Yii::$app->user->isGuest) { 76 | return $this->goHome(); 77 | } 78 | 79 | $model = new LoginForm(); 80 | if ($model->load(Yii::$app->request->post()) && $model->login()) { 81 | return $this->goBack(); 82 | } else { 83 | return $this->render('login', [ 84 | 'model' => $model, 85 | ]); 86 | } 87 | } 88 | 89 | public function actionLogout() 90 | { 91 | Yii::$app->user->logout(); 92 | 93 | return $this->goHome(); 94 | } 95 | 96 | public function actionContact() 97 | { 98 | $model = new ContactForm(); 99 | if ($model->load(Yii::$app->request->post()) && $model->validate()) { 100 | if ($model->sendEmail(Yii::$app->params['adminEmail'])) { 101 | Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.'); 102 | } else { 103 | Yii::$app->session->setFlash('error', 'There was an error sending email.'); 104 | } 105 | 106 | return $this->refresh(); 107 | } else { 108 | return $this->render('contact', [ 109 | 'model' => $model, 110 | ]); 111 | } 112 | } 113 | 114 | public function actionAbout() 115 | { 116 | return $this->render('about'); 117 | } 118 | 119 | public function actionSignup() 120 | { 121 | $model = new SignupForm(); 122 | if ($model->load(Yii::$app->request->post())) { 123 | if ($user = $model->signup()) { 124 | if (Yii::$app->getUser()->login($user)) { 125 | return $this->goHome(); 126 | } 127 | } 128 | } 129 | 130 | return $this->render('signup', [ 131 | 'model' => $model, 132 | ]); 133 | } 134 | 135 | public function actionRequestPasswordReset() 136 | { 137 | $model = new PasswordResetRequestForm(); 138 | if ($model->load(Yii::$app->request->post()) && $model->validate()) { 139 | if ($model->sendEmail()) { 140 | Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.'); 141 | 142 | return $this->goHome(); 143 | } else { 144 | Yii::$app->getSession()->setFlash('error', 'Sorry, we are unable to reset password for email provided.'); 145 | } 146 | } 147 | 148 | return $this->render('requestPasswordResetToken', [ 149 | 'model' => $model, 150 | ]); 151 | } 152 | 153 | public function actionResetPassword($token) 154 | { 155 | try { 156 | $model = new ResetPasswordForm($token); 157 | } catch (InvalidParamException $e) { 158 | throw new BadRequestHttpException($e->getMessage()); 159 | } 160 | 161 | if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) { 162 | Yii::$app->getSession()->setFlash('success', 'New password was saved.'); 163 | 164 | return $this->goHome(); 165 | } 166 | 167 | return $this->render('resetPassword', [ 168 | 'model' => $model, 169 | ]); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /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('passwordResetToken', ['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); 34 | if (!$this->_user) { 35 | throw new InvalidParamException('Wrong password reset token.'); 36 | } 37 | parent::__construct($config); 38 | } 39 | 40 | /** 41 | * @inheritdoc 42 | */ 43 | public function rules() 44 | { 45 | return [ 46 | ['password', 'required'], 47 | ['password', 'string', 'min' => 6], 48 | ]; 49 | } 50 | 51 | /** 52 | * Resets password. 53 | * 54 | * @return boolean if password was reset. 55 | */ 56 | public function resetPassword() 57 | { 58 | $user = $this->_user; 59 | $user->password = $this->password; 60 | $user->removePasswordResetToken(); 61 | 62 | return $user->save(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /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 | $user->save(); 52 | return $user; 53 | } 54 | 55 | return null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /frontend/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /frontend/views/layouts/main.php: -------------------------------------------------------------------------------- 1 | 14 | beginPage() ?> 15 | 16 | 17 | 18 | 19 | 20 | 21 | <?= Html::encode($this->title) ?> 22 | head() ?> 23 | 24 | 25 | beginBody() ?> 26 |
27 | 'My Company', 30 | 'brandUrl' => Yii::$app->homeUrl, 31 | 'options' => [ 32 | 'class' => 'navbar-inverse navbar-fixed-top', 33 | ], 34 | ]); 35 | $menuItems = [ 36 | ['label' => 'Home', 'url' => ['/site/index']], 37 | ['label' => 'About', 'url' => ['/site/about']], 38 | ['label' => 'Contact', 'url' => ['/site/contact']], 39 | ]; 40 | if (Yii::$app->user->isGuest) { 41 | $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']]; 42 | $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; 43 | } else { 44 | $menuItems[] = [ 45 | 'label' => 'Logout (' . Yii::$app->user->identity->username . ')', 46 | 'url' => ['/site/logout'], 47 | 'linkOptions' => ['data-method' => 'post'] 48 | ]; 49 | } 50 | echo Nav::widget([ 51 | 'options' => ['class' => 'navbar-nav navbar-right'], 52 | 'items' => $menuItems, 53 | ]); 54 | NavBar::end(); 55 | ?> 56 | 57 |
58 | isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], 60 | ]) ?> 61 | 62 | 63 |
64 |
65 | 66 |
67 |
68 |

© My Company

69 |

70 |
71 |
72 | 73 | endBody() ?> 74 | 75 | 76 | endPage() ?> 77 | -------------------------------------------------------------------------------- /frontend/views/site/about.php: -------------------------------------------------------------------------------- 1 | title = 'About'; 6 | $this->params['breadcrumbs'][] = $this->title; 7 | ?> 8 |
9 |

title) ?>

10 | 11 |

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

12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /frontend/views/site/contact.php: -------------------------------------------------------------------------------- 1 | title = 'Contact'; 11 | $this->params['breadcrumbs'][] = $this->title; 12 | ?> 13 |
14 |

title) ?>

15 | 16 |

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

19 | 20 |
21 |
22 | 'contact-form']); ?> 23 | field($model, 'name') ?> 24 | field($model, 'email') ?> 25 | field($model, 'subject') ?> 26 | field($model, 'body')->textArea(['rows' => 6]) ?> 27 | field($model, 'verifyCode')->widget(Captcha::className(), [ 28 | 'template' => '
{image}
{input}
', 29 | ]) ?> 30 |
31 | 'btn btn-primary', 'name' => 'contact-button']) ?> 32 |
33 | 34 |
35 |
36 | 37 |
38 | -------------------------------------------------------------------------------- /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/views/site/index.php: -------------------------------------------------------------------------------- 1 | title = 'My Yii Application'; 4 | ?> 5 |
6 | 7 |
8 |

Congratulations!

9 | 10 |

You have successfully created your Yii-powered application.

11 | 12 |

Get started with Yii

13 |
14 | 15 |
16 | 17 |
18 |
19 |

Heading

20 | 21 |

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

25 | 26 |

Yii Documentation »

27 |
28 |
29 |

Heading

30 | 31 |

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

35 | 36 |

Yii Forum »

37 |
38 |
39 |

Heading

40 | 41 |

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

45 | 46 |

Yii Extensions »

47 |
48 |
49 | 50 |
51 |
52 | -------------------------------------------------------------------------------- /frontend/views/site/login.php: -------------------------------------------------------------------------------- 1 | title = 'Login'; 10 | $this->params['breadcrumbs'][] = $this->title; 11 | ?> 12 | 33 | -------------------------------------------------------------------------------- /frontend/views/site/requestPasswordResetToken.php: -------------------------------------------------------------------------------- 1 | title = 'Request password reset'; 10 | $this->params['breadcrumbs'][] = $this->title; 11 | ?> 12 |
13 |

title) ?>

14 | 15 |

Please fill out your email. A link to reset password will be sent there.

16 | 17 |
18 |
19 | 'request-password-reset-form']); ?> 20 | field($model, 'email') ?> 21 |
22 | 'btn btn-primary']) ?> 23 |
24 | 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /frontend/views/site/resetPassword.php: -------------------------------------------------------------------------------- 1 | title = 'Reset password'; 10 | $this->params['breadcrumbs'][] = $this->title; 11 | ?> 12 |
13 |

title) ?>

14 | 15 |

Please choose your new password:

16 | 17 |
18 |
19 | 'reset-password-form']); ?> 20 | field($model, 'password')->passwordInput() ?> 21 |
22 | 'btn btn-primary']) ?> 23 |
24 | 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /frontend/views/site/signup.php: -------------------------------------------------------------------------------- 1 | title = 'Signup'; 10 | $this->params['breadcrumbs'][] = $this->title; 11 | ?> 12 | 30 | -------------------------------------------------------------------------------- /frontend/web/.gitignore: -------------------------------------------------------------------------------- 1 | /index.php 2 | /index-test.php 3 | -------------------------------------------------------------------------------- /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/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/frontend/web/favicon.ico -------------------------------------------------------------------------------- /frontend/web/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /frontend/widgets/Alert.php: -------------------------------------------------------------------------------- 1 | getSession()->setFlash('error', 'This is the message'); 16 | * \Yii::$app->getSession()->setFlash('success', 'This is the message'); 17 | * \Yii::$app->getSession()->setFlash('info', 'This is the message'); 18 | * ``` 19 | * 20 | * Multiple messages could be set as follows: 21 | * 22 | * ```php 23 | * \Yii::$app->getSession()->setFlash('error', ['Error 1', 'Error 2']); 24 | * ``` 25 | * 26 | * @author Kartik Visweswaran 27 | * @author Alexander Makarov 28 | */ 29 | class Alert extends \yii\bootstrap\Widget 30 | { 31 | /** 32 | * @var array the alert types configuration for the flash messages. 33 | * This array is setup as $key => $value, where: 34 | * - $key is the name of the session flash variable 35 | * - $value is the bootstrap alert type (i.e. danger, success, info, warning) 36 | */ 37 | public $alertTypes = [ 38 | 'error' => 'alert-danger', 39 | 'danger' => 'alert-danger', 40 | 'success' => 'alert-success', 41 | 'info' => 'alert-info', 42 | 'warning' => 'alert-warning' 43 | ]; 44 | 45 | /** 46 | * @var array the options for rendering the close button tag. 47 | */ 48 | public $closeButton = []; 49 | 50 | public function init() 51 | { 52 | parent::init(); 53 | 54 | $session = \Yii::$app->getSession(); 55 | $flashes = $session->getAllFlashes(); 56 | $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : ''; 57 | 58 | foreach ($flashes as $type => $data) { 59 | if (isset($this->alertTypes[$type])) { 60 | $data = (array) $data; 61 | foreach ($data as $message) { 62 | /* initialize css class for each alert box */ 63 | $this->options['class'] = $this->alertTypes[$type] . $appendCss; 64 | 65 | /* assign unique id to each alert box */ 66 | $this->options['id'] = $this->getId() . '-' . $type; 67 | 68 | echo \yii\bootstrap\Alert::widget([ 69 | 'body' => $message, 70 | 'closeButton' => $this->closeButton, 71 | 'options' => $this->options, 72 | ]); 73 | } 74 | 75 | $session->removeFlash($type); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /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 | /** 27 | * Adjust requirements according to your application specifics. 28 | */ 29 | $requirements = array( 30 | // Database : 31 | array( 32 | 'name' => 'PDO extension', 33 | 'mandatory' => true, 34 | 'condition' => extension_loaded('pdo'), 35 | 'by' => 'All DB-related classes', 36 | ), 37 | array( 38 | 'name' => 'PDO SQLite extension', 39 | 'mandatory' => false, 40 | 'condition' => extension_loaded('pdo_sqlite'), 41 | 'by' => 'All DB-related classes', 42 | 'memo' => 'Required for SQLite database.', 43 | ), 44 | array( 45 | 'name' => 'PDO MySQL extension', 46 | 'mandatory' => false, 47 | 'condition' => extension_loaded('pdo_mysql'), 48 | 'by' => 'All DB-related classes', 49 | 'memo' => 'Required for MySQL database.', 50 | ), 51 | array( 52 | 'name' => 'PDO PostgreSQL extension', 53 | 'mandatory' => false, 54 | 'condition' => extension_loaded('pdo_pgsql'), 55 | 'by' => 'All DB-related classes', 56 | 'memo' => 'Required for PostgreSQL database.', 57 | ), 58 | // Cache : 59 | array( 60 | 'name' => 'Memcache extension', 61 | 'mandatory' => false, 62 | 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), 63 | 'by' => 'MemCache', 64 | 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : '' 65 | ), 66 | array( 67 | 'name' => 'APC extension', 68 | 'mandatory' => false, 69 | 'condition' => extension_loaded('apc'), 70 | 'by' => 'ApcCache', 71 | ), 72 | // PHP ini : 73 | 'phpSafeMode' => array( 74 | 'name' => 'PHP safe mode', 75 | 'mandatory' => false, 76 | 'condition' => $requirementsChecker->checkPhpIniOff("safe_mode"), 77 | 'by' => 'File uploading and console command execution', 78 | 'memo' => '"safe_mode" should be disabled at php.ini', 79 | ), 80 | 'phpExposePhp' => array( 81 | 'name' => 'Expose PHP', 82 | 'mandatory' => false, 83 | 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), 84 | 'by' => 'Security reasons', 85 | 'memo' => '"expose_php" should be disabled at php.ini', 86 | ), 87 | 'phpAllowUrlInclude' => array( 88 | 'name' => 'PHP allow url include', 89 | 'mandatory' => false, 90 | 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), 91 | 'by' => 'Security reasons', 92 | 'memo' => '"allow_url_include" should be disabled at php.ini', 93 | ), 94 | 'phpSmtp' => array( 95 | 'name' => 'PHP mail SMTP', 96 | 'mandatory' => false, 97 | 'condition' => strlen(ini_get('SMTP')) > 0, 98 | 'by' => 'Email sending', 99 | 'memo' => 'PHP mail SMTP server required', 100 | ), 101 | ); 102 | $requirementsChecker->checkYii()->check($requirements)->render(); 103 | -------------------------------------------------------------------------------- /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'); 8 | 9 | $loginPage = LoginPage::openBy($I); 10 | 11 | $I->amGoingTo('submit login form with no data'); 12 | $loginPage->login('', ''); 13 | $I->expectTo('see validations errors'); 14 | $I->see('Username cannot be blank.', '.help-block'); 15 | $I->see('Password cannot be blank.', '.help-block'); 16 | 17 | $I->amGoingTo('try to login with wrong credentials'); 18 | $I->expectTo('see validations errors'); 19 | $loginPage->login('admin', 'wrong'); 20 | $I->expectTo('see validations errors'); 21 | $I->see('Incorrect username or password.', '.help-block'); 22 | 23 | $I->amGoingTo('try to login with correct credentials'); 24 | $loginPage->login('erau', 'password_0'); 25 | $I->expectTo('see that user is logged'); 26 | $I->seeLink('Logout (erau)'); 27 | $I->dontSeeLink('Login'); 28 | $I->dontSeeLink('Signup'); 29 | /** Uncomment if using WebDriver 30 | * $I->click('Logout (erau)'); 31 | * $I->dontSeeLink('Logout (erau)'); 32 | * $I->seeLink('Login'); 33 | */ 34 | -------------------------------------------------------------------------------- /tests/codeception/backend/acceptance/_bootstrap.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure login page works'); 8 | 9 | $loginPage = LoginPage::openBy($I); 10 | 11 | $I->amGoingTo('submit login form with no data'); 12 | $loginPage->login('', ''); 13 | $I->expectTo('see validations errors'); 14 | $I->see('Username cannot be blank.', '.help-block'); 15 | $I->see('Password cannot be blank.', '.help-block'); 16 | 17 | $I->amGoingTo('try to login with wrong credentials'); 18 | $I->expectTo('see validations errors'); 19 | $loginPage->login('admin', 'wrong'); 20 | $I->expectTo('see validations errors'); 21 | $I->see('Incorrect username or password.', '.help-block'); 22 | 23 | $I->amGoingTo('try to login with correct credentials'); 24 | $loginPage->login('erau', 'password_0'); 25 | $I->expectTo('see that user is logged'); 26 | $I->seeLink('Logout (erau)'); 27 | $I->dontSeeLink('Login'); 28 | $I->dontSeeLink('Signup'); 29 | -------------------------------------------------------------------------------- /tests/codeception/backend/functional/_bootstrap.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'fixture' => [ 22 | 'class' => 'yii\faker\FixtureController', 23 | 'fixtureDataPath' => '@tests/codeception/common/fixtures/data', 24 | 'templatePath' => '@tests/codeception/common/templates/fixtures', 25 | ], 26 | ], 27 | ] 28 | ); 29 | 30 | $application = new yii\console\Application($config); 31 | $exitCode = $application->run(); 32 | exit($exitCode); 33 | -------------------------------------------------------------------------------- /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_acceptance" %* 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 | 'db' => [ 8 | 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_tests', 9 | ], 10 | 'mailer' => [ 11 | 'useFileTransport' => true, 12 | ], 13 | 'urlManager' => [ 14 | 'showScriptName' => true, 15 | ], 16 | ], 17 | ]; 18 | -------------------------------------------------------------------------------- /tests/codeception/config/console/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 | url: 'http://localhost:8080' 24 | # WebDriver: 25 | # url: 'http://localhost' 26 | # browser: firefox 27 | # restart: true 28 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/AboutCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that about works'); 7 | AboutPage::openBy($I); 8 | $I->see('About', 'h1'); 9 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/ContactCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that contact works'); 7 | 8 | $contactPage = ContactPage::openBy($I); 9 | 10 | $I->see('Contact', 'h1'); 11 | 12 | $I->amGoingTo('submit contact form with no data'); 13 | $contactPage->submit([]); 14 | $I->expectTo('see validations errors'); 15 | $I->see('Contact', 'h1'); 16 | $I->see('Name cannot be blank', '.help-block'); 17 | $I->see('Email cannot be blank', '.help-block'); 18 | $I->see('Subject cannot be blank', '.help-block'); 19 | $I->see('Body cannot be blank', '.help-block'); 20 | $I->see('The verification code is incorrect', '.help-block'); 21 | 22 | $I->amGoingTo('submit contact form with not correct email'); 23 | $contactPage->submit([ 24 | 'name' => 'tester', 25 | 'email' => 'tester.email', 26 | 'subject' => 'test subject', 27 | 'body' => 'test content', 28 | 'verifyCode' => 'testme', 29 | ]); 30 | $I->expectTo('see that email adress is wrong'); 31 | $I->dontSee('Name cannot be blank', '.help-block'); 32 | $I->see('Email is not a valid email address.', '.help-block'); 33 | $I->dontSee('Subject cannot be blank', '.help-block'); 34 | $I->dontSee('Body cannot be blank', '.help-block'); 35 | $I->dontSee('The verification code is incorrect', '.help-block'); 36 | 37 | $I->amGoingTo('submit contact form with correct data'); 38 | $contactPage->submit([ 39 | 'name' => 'tester', 40 | 'email' => 'tester@example.com', 41 | 'subject' => 'test subject', 42 | 'body' => 'test content', 43 | 'verifyCode' => 'testme', 44 | ]); 45 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.'); 46 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/HomeCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that home page works'); 6 | $I->amOnPage(Yii::$app->homeUrl); 7 | $I->see('My Company'); 8 | $I->seeLink('About'); 9 | $I->click('About'); 10 | $I->see('This is the About page.'); 11 | -------------------------------------------------------------------------------- /tests/codeception/frontend/acceptance/LoginCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure login page works'); 7 | 8 | $loginPage = LoginPage::openBy($I); 9 | 10 | $I->amGoingTo('submit login form with no data'); 11 | $loginPage->login('', ''); 12 | $I->expectTo('see validations errors'); 13 | $I->see('Username cannot be blank.', '.help-block'); 14 | $I->see('Password cannot be blank.', '.help-block'); 15 | 16 | $I->amGoingTo('try to login with wrong credentials'); 17 | $I->expectTo('see validations errors'); 18 | $loginPage->login('admin', 'wrong'); 19 | $I->expectTo('see validations errors'); 20 | $I->see('Incorrect username or password.', '.help-block'); 21 | 22 | $I->amGoingTo('try to login with correct credentials'); 23 | $loginPage->login('erau', 'password_0'); 24 | $I->expectTo('see that user is logged'); 25 | $I->seeLink('Logout (erau)'); 26 | $I->dontSeeLink('Login'); 27 | $I->dontSeeLink('Signup'); 28 | /** Uncomment if using WebDriver 29 | * $I->click('Logout (erau)'); 30 | * $I->dontSeeLink('Logout (erau)'); 31 | * $I->seeLink('Login'); 32 | */ 33 | -------------------------------------------------------------------------------- /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'); 7 | AboutPage::openBy($I); 8 | $I->see('About', 'h1'); 9 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/ContactCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that contact works'); 7 | 8 | $contactPage = ContactPage::openBy($I); 9 | 10 | $I->see('Contact', 'h1'); 11 | 12 | $I->amGoingTo('submit contact form with no data'); 13 | $contactPage->submit([]); 14 | $I->expectTo('see validations errors'); 15 | $I->see('Contact', 'h1'); 16 | $I->see('Name cannot be blank', '.help-block'); 17 | $I->see('Email cannot be blank', '.help-block'); 18 | $I->see('Subject cannot be blank', '.help-block'); 19 | $I->see('Body cannot be blank', '.help-block'); 20 | $I->see('The verification code is incorrect', '.help-block'); 21 | 22 | $I->amGoingTo('submit contact form with not correct email'); 23 | $contactPage->submit([ 24 | 'name' => 'tester', 25 | 'email' => 'tester.email', 26 | 'subject' => 'test subject', 27 | 'body' => 'test content', 28 | 'verifyCode' => 'testme', 29 | ]); 30 | $I->expectTo('see that email adress is wrong'); 31 | $I->dontSee('Name cannot be blank', '.help-block'); 32 | $I->see('Email is not a valid email address.', '.help-block'); 33 | $I->dontSee('Subject cannot be blank', '.help-block'); 34 | $I->dontSee('Body cannot be blank', '.help-block'); 35 | $I->dontSee('The verification code is incorrect', '.help-block'); 36 | 37 | $I->amGoingTo('submit contact form with correct data'); 38 | $contactPage->submit([ 39 | 'name' => 'tester', 40 | 'email' => 'tester@example.com', 41 | 'subject' => 'test subject', 42 | 'body' => 'test content', 43 | 'verifyCode' => 'testme', 44 | ]); 45 | $I->see('Thank you for contacting us. We will respond to you as soon as possible.'); 46 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/HomeCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure that home page works'); 5 | $I->amOnPage(Yii::$app->homeUrl); 6 | $I->see('My Company'); 7 | $I->seeLink('About'); 8 | $I->click('About'); 9 | $I->see('This is the About page.'); 10 | -------------------------------------------------------------------------------- /tests/codeception/frontend/functional/LoginCept.php: -------------------------------------------------------------------------------- 1 | wantTo('ensure login page works'); 7 | 8 | $loginPage = LoginPage::openBy($I); 9 | 10 | $I->amGoingTo('submit login form with no data'); 11 | $loginPage->login('', ''); 12 | $I->expectTo('see validations errors'); 13 | $I->see('Username cannot be blank.', '.help-block'); 14 | $I->see('Password cannot be blank.', '.help-block'); 15 | 16 | $I->amGoingTo('try to login with wrong credentials'); 17 | $I->expectTo('see validations errors'); 18 | $loginPage->login('admin', 'wrong'); 19 | $I->expectTo('see validations errors'); 20 | $I->see('Incorrect username or password.', '.help-block'); 21 | 22 | $I->amGoingTo('try to login with correct credentials'); 23 | $loginPage->login('erau', 'password_0'); 24 | $I->expectTo('see that user is logged'); 25 | $I->seeLink('Logout (erau)'); 26 | $I->dontSeeLink('Login'); 27 | $I->dontSeeLink('Signup'); 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests/img/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/tests/img/demo1.jpg -------------------------------------------------------------------------------- /tests/img/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/tests/img/demo2.png -------------------------------------------------------------------------------- /tests/img/demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigKuCha/yii2-admin/25c41bd940beca35b0061d77a35df4a71dca822f/tests/img/demo3.png -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------